]> git.uio.no Git - u/mrichter/AliRoot.git/commitdiff
- Reshape the architecture of the Kalman tracking to make it more modular
authorivana <ivana@f7af4fe6-9843-0410-8265-dc069ae4e863>
Thu, 28 Jun 2007 14:23:56 +0000 (14:23 +0000)
committerivana <ivana@f7af4fe6-9843-0410-8265-dc069ae4e863>
Thu, 28 Jun 2007 14:23:56 +0000 (14:23 +0000)
  and similar to the Original one. Performances (efficiency, resolution,
  cpu time) of the new version are the same as before.
- Remove the class AliMUONTrackK.
- Add new options to the Original tracking that were available
  only for the Kalman.
- Speed up the last fit (accounting for multiple scattering) in the
  Original tracking.
(Philippe P.)

15 files changed:
MUON/AliMUONTrack.cxx
MUON/AliMUONTrack.h
MUON/AliMUONTrackExtrap.cxx
MUON/AliMUONTrackExtrap.h
MUON/AliMUONTrackHitPattern.cxx
MUON/AliMUONTrackHitPattern.h
MUON/AliMUONTrackParam.cxx
MUON/AliMUONTrackParam.h
MUON/AliMUONTrackReconstructor.cxx
MUON/AliMUONTrackReconstructor.h
MUON/AliMUONTrackReconstructorK.cxx
MUON/AliMUONTrackReconstructorK.h
MUON/AliMUONTracker.cxx
MUON/AliMUONVTrackReconstructor.cxx
MUON/AliMUONVTrackReconstructor.h

index aaa733b8c17735ab8083e6ff730d247aed8b9ea1..b181babbf280fecb6d60de41a36e38beed4c7ba5 100644 (file)
 
 #include "AliMUONTrackParam.h" 
 #include "AliMUONHitForRec.h" 
+#include "AliMUONObjectPair.h" 
 #include "AliMUONConstants.h"
 #include "AliMUONTrackExtrap.h" 
 
 #include "AliLog.h"
 
 #include <TMath.h>
-#include <Riostream.h>
 #include <TMatrixD.h>
 
+#include <Riostream.h>
+
 /// \cond CLASSIMP
 ClassImp(AliMUONTrack) // Class implementation in ROOT context
 /// \endcond
 
-const Double_t AliMUONTrack::fgkMaxTrackingDistanceBending    = 2.;
-const Double_t AliMUONTrack::fgkMaxTrackingDistanceNonBending = 2.;
-
 //__________________________________________________________________________
 AliMUONTrack::AliMUONTrack()
   : TObject(),
@@ -52,10 +51,13 @@ AliMUONTrack::AliMUONTrack()
     fTrackParamAtHit(0x0),
     fHitForRecAtHit(0x0),
     fNTrackHits(0),
-    fExtrapTrackParam(),
     fFitWithVertex(kFALSE),
     fVertex(0x0),
-    fFitFMin(-1.),
+    fFitWithMCS(kFALSE),
+    fHitWeightsNonBending(0x0),
+    fHitWeightsBending(0x0),
+    fGlobalChi2(-1.),
+    fImproved(kFALSE),
     fMatchTrigger(-1),
     floTrgNum(-1),
     fChi2MatchTrigger(0.),
@@ -67,16 +69,19 @@ AliMUONTrack::AliMUONTrack()
 }
 
   //__________________________________________________________________________
-AliMUONTrack::AliMUONTrack(AliMUONHitForRec* hitForRec1, AliMUONHitForRec* hitForRec2)
+AliMUONTrack::AliMUONTrack(AliMUONObjectPair *segment)
   : TObject(),
     fTrackParamAtVertex(),
     fTrackParamAtHit(0x0),
     fHitForRecAtHit(0x0),
     fNTrackHits(0),
-    fExtrapTrackParam(),
     fFitWithVertex(kFALSE),
     fVertex(0x0),
-    fFitFMin(-1.),
+    fFitWithMCS(kFALSE),
+    fHitWeightsNonBending(0x0),
+    fHitWeightsBending(0x0),
+    fGlobalChi2(0.),
+    fImproved(kFALSE),
     fMatchTrigger(-1),
     floTrgNum(-1),    
     fChi2MatchTrigger(0.),
@@ -91,128 +96,181 @@ AliMUONTrack::AliMUONTrack(AliMUONHitForRec* hitForRec1, AliMUONHitForRec* hitFo
   fHitForRecAtHit = new TClonesArray("AliMUONHitForRec",10);
   fHitForRecAtHit->SetOwner(kTRUE);
   
-  if (!hitForRec1) return; //AZ
+  if (!segment) return; //AZ
   
-  // Add hits to the track
-  AddTrackParamAtHit(0,hitForRec1);
-  AddTrackParamAtHit(0,hitForRec2);
+  // Pointers to hits from the segment
+  AliMUONHitForRec* hit1 = (AliMUONHitForRec*) segment->First();
+  AliMUONHitForRec* hit2 = (AliMUONHitForRec*) segment->Second();
   
-  // sort TrackParamAtHit according to increasing -Z
-  fTrackParamAtHit->Sort();
+  // check sorting in -Z (spectro z<0)
+  if (hit1->GetZ() < hit2->GetZ()) {
+    hit1 = hit2;
+    hit2 = (AliMUONHitForRec*) segment->First();
+  }
+  
+  // order the hits into the track according to the station the segment belong to
+  //(the hit first attached is the one from which we will start the tracking procedure)
+  if (hit1->GetChamberNumber() == 8) {
+    AddTrackParamAtHit(0,hit1);
+    AddTrackParamAtHit(0,hit2);
+  } else {
+    AddTrackParamAtHit(0,hit2);
+    AddTrackParamAtHit(0,hit1);
+  }
   
-  // Set track parameters at first track hit
   AliMUONTrackParam* trackParamAtFirstHit = (AliMUONTrackParam*) fTrackParamAtHit->First();
   AliMUONHitForRec* firstHit = trackParamAtFirstHit->GetHitForRecPtr();
-  AliMUONHitForRec* lastHit = ((AliMUONTrackParam*) fTrackParamAtHit->Last())->GetHitForRecPtr();
+  AliMUONTrackParam* trackParamAtLastHit = (AliMUONTrackParam*) fTrackParamAtHit->Last();
+  AliMUONHitForRec* lastHit = trackParamAtLastHit->GetHitForRecPtr();
+  
+  
+  // Compute track parameters
   Double_t dZ = firstHit->GetZ() - lastHit->GetZ();
   // Non bending plane
-  Double_t nonBendingCoor = firstHit->GetNonBendingCoor();
-  trackParamAtFirstHit->SetNonBendingCoor(nonBendingCoor);
-  trackParamAtFirstHit->SetNonBendingSlope((nonBendingCoor - lastHit->GetNonBendingCoor()) / dZ);
+  Double_t nonBendingCoor1 = firstHit->GetNonBendingCoor();
+  Double_t nonBendingCoor2 = lastHit->GetNonBendingCoor();
+  Double_t nonBendingSlope = (nonBendingCoor1 - nonBendingCoor2) / dZ;
   // Bending plane
-  Double_t bendingCoor = firstHit->GetBendingCoor();
-  trackParamAtFirstHit->SetBendingCoor(bendingCoor);
-  Double_t bendingSlope = (bendingCoor - lastHit->GetBendingCoor()) / dZ;
-  trackParamAtFirstHit->SetBendingSlope(bendingSlope);
+  Double_t bendingCoor1 = firstHit->GetBendingCoor();
+  Double_t bendingCoor2 = lastHit->GetBendingCoor();
+  Double_t bendingSlope = (bendingCoor1 - bendingCoor2) / dZ;
   // Inverse bending momentum
-  Double_t bendingImpact = bendingCoor - firstHit->GetZ() * bendingSlope;
+  Double_t bendingImpact = bendingCoor1 - firstHit->GetZ() * bendingSlope;
   Double_t inverseBendingMomentum = 1. / AliMUONTrackExtrap::GetBendingMomentumFromImpactParam(bendingImpact);
+  
+  
+  // Set track parameters at first hit
+  trackParamAtFirstHit->SetNonBendingCoor(nonBendingCoor1);
+  trackParamAtFirstHit->SetNonBendingSlope(nonBendingSlope);
+  trackParamAtFirstHit->SetBendingCoor(bendingCoor1);
+  trackParamAtFirstHit->SetBendingSlope(bendingSlope);
   trackParamAtFirstHit->SetInverseBendingMomentum(inverseBendingMomentum);
   
-  // Evaluate covariances
-  TMatrixD *paramCov = trackParamAtFirstHit->GetCovariances();
-  (*paramCov) = 0;
+  
+  // Set track parameters at last hit
+  trackParamAtLastHit->SetNonBendingCoor(nonBendingCoor2);
+  trackParamAtLastHit->SetNonBendingSlope(nonBendingSlope);
+  trackParamAtLastHit->SetBendingCoor(bendingCoor2);
+  trackParamAtLastHit->SetBendingSlope(bendingSlope);
+  trackParamAtLastHit->SetInverseBendingMomentum(inverseBendingMomentum);
+  
+  
+  // Compute and set track parameters covariances at first hit
+  TMatrixD paramCov1(5,5);
+  paramCov1.Zero();
   // Non bending plane
-  (*paramCov)(0,0) = firstHit->GetNonBendingReso2();
-  (*paramCov)(0,1) = firstHit->GetNonBendingReso2() / dZ;
-  (*paramCov)(1,0) = (*paramCov)(0,1);
-  (*paramCov)(1,1) = ( firstHit->GetNonBendingReso2() + lastHit->GetNonBendingReso2() ) / dZ / dZ;
+  paramCov1(0,0) = firstHit->GetNonBendingReso2();
+  paramCov1(0,1) = firstHit->GetNonBendingReso2() / dZ;
+  paramCov1(1,0) = paramCov1(0,1);
+  paramCov1(1,1) = ( firstHit->GetNonBendingReso2() + lastHit->GetNonBendingReso2() ) / dZ / dZ;
   // Bending plane
-  (*paramCov)(2,2) = firstHit->GetBendingReso2();
-  (*paramCov)(2,3) = firstHit->GetBendingReso2() / dZ;
-  (*paramCov)(3,2) = (*paramCov)(2,3);
-  (*paramCov)(3,3) = ( firstHit->GetBendingReso2() + lastHit->GetBendingReso2() ) / dZ / dZ;
+  paramCov1(2,2) = firstHit->GetBendingReso2();
+  paramCov1(2,3) = firstHit->GetBendingReso2() / dZ;
+  paramCov1(3,2) = paramCov1(2,3);
+  paramCov1(3,3) = ( firstHit->GetBendingReso2() + lastHit->GetBendingReso2() ) / dZ / dZ;
   // Inverse bending momentum (50% error)
-  (*paramCov)(4,4) = 0.5*inverseBendingMomentum * 0.5*inverseBendingMomentum;
+  paramCov1(4,4) = 0.5*inverseBendingMomentum * 0.5*inverseBendingMomentum;
+  // Set covariances
+  trackParamAtFirstHit->SetCovariances(paramCov1);
+  
+  
+  // Compute and set track parameters covariances at last hit (as if the first hit did not exist)
+  TMatrixD paramCov2(5,5);
+  paramCov2.Zero();
+  // Non bending plane
+  paramCov2(0,0) = paramCov1(0,0);
+  paramCov2(1,1) = 100.*paramCov1(1,1);
+  // Bending plane
+  paramCov2(2,2) = paramCov1(2,2);
+  paramCov2(3,3) = 100.*paramCov1(3,3);
+  // Inverse bending momentum
+  paramCov2(4,4) = paramCov1(4,4);
+  // Set covariances
+  trackParamAtLastHit->SetCovariances(paramCov2);
+  
+  
+  // Flag first hit as being removable
+  trackParamAtFirstHit->SetRemovable(kTRUE);
+  
+  // Flag last hit as being removable
+  trackParamAtLastHit->SetRemovable(kTRUE);
   
 }
 
   //__________________________________________________________________________
-AliMUONTrack::~AliMUONTrack()
-{
-  /// Destructor
-  delete fTrackParamAtHit;
-  delete fHitForRecAtHit;  
-  delete fVertex;
-}
-
-  //__________________________________________________________________________
-AliMUONTrack::AliMUONTrack (const AliMUONTrack& theMUONTrack)
-  : TObject(theMUONTrack),
-    fTrackParamAtVertex(theMUONTrack.fTrackParamAtVertex),
+AliMUONTrack::AliMUONTrack (const AliMUONTrack& track)
+  : TObject(track),
+    fTrackParamAtVertex(track.fTrackParamAtVertex),
     fTrackParamAtHit(0x0),
     fHitForRecAtHit(0x0),
-    fNTrackHits(theMUONTrack.fNTrackHits),
-    fExtrapTrackParam(theMUONTrack.fExtrapTrackParam),
-    fFitWithVertex(theMUONTrack.fFitWithVertex),
+    fNTrackHits(track.fNTrackHits),
+    fFitWithVertex(track.fFitWithVertex),
     fVertex(0x0),
-    fFitFMin(theMUONTrack.fFitFMin),
-    fMatchTrigger(theMUONTrack.fMatchTrigger),
-    floTrgNum(theMUONTrack.floTrgNum),    
-    fChi2MatchTrigger(theMUONTrack.fChi2MatchTrigger),
-    fTrackID(theMUONTrack.fTrackID),
-    fHitsPatternInTrigCh(theMUONTrack.fHitsPatternInTrigCh),
-    fLocalTrigger(theMUONTrack.fLocalTrigger)
+    fFitWithMCS(track.fFitWithMCS),
+    fHitWeightsNonBending(0x0),
+    fHitWeightsBending(0x0),
+    fGlobalChi2(track.fGlobalChi2),
+    fImproved(track.fImproved),
+    fMatchTrigger(track.fMatchTrigger),
+    floTrgNum(track.floTrgNum),    
+    fChi2MatchTrigger(track.fChi2MatchTrigger),
+    fTrackID(track.fTrackID),
+    fHitsPatternInTrigCh(track.fHitsPatternInTrigCh),
+    fLocalTrigger(track.fLocalTrigger)
 {
   ///copy constructor
   Int_t maxIndex = 0;
   
   // necessary to make a copy of the objects and not only the pointers in TClonesArray.
-  if (theMUONTrack.fTrackParamAtHit) {
-    maxIndex = (theMUONTrack.fTrackParamAtHit)->GetEntriesFast();
+  if (track.fTrackParamAtHit) {
+    maxIndex = (track.fTrackParamAtHit)->GetEntriesFast();
     fTrackParamAtHit = new TClonesArray("AliMUONTrackParam",maxIndex);
     for (Int_t index = 0; index < maxIndex; index++) {
-      new ((*fTrackParamAtHit)[index]) AliMUONTrackParam(*(AliMUONTrackParam*)theMUONTrack.fTrackParamAtHit->At(index));
+      new ((*fTrackParamAtHit)[index]) AliMUONTrackParam(*(AliMUONTrackParam*)track.fTrackParamAtHit->At(index));
     }
   }
   
   // necessary to make a copy of the objects and not only the pointers in TClonesArray.
-  if (theMUONTrack.fHitForRecAtHit) {
-    maxIndex = (theMUONTrack.fHitForRecAtHit)->GetEntriesFast();
+  if (track.fHitForRecAtHit) {
+    maxIndex = (track.fHitForRecAtHit)->GetEntriesFast();
     fHitForRecAtHit = new TClonesArray("AliMUONHitForRec",maxIndex);
     for (Int_t index = 0; index < maxIndex; index++) {
-      new ((*fHitForRecAtHit)[index]) AliMUONHitForRec(*(AliMUONHitForRec*)theMUONTrack.fHitForRecAtHit->At(index));
+      new ((*fHitForRecAtHit)[index]) AliMUONHitForRec(*(AliMUONHitForRec*)track.fHitForRecAtHit->At(index));
     }
   }
   
   // copy vertex used during the tracking procedure if any
-  if (theMUONTrack.fVertex) fVertex = new AliMUONHitForRec(*(theMUONTrack.fVertex));
+  if (track.fVertex) fVertex = new AliMUONHitForRec(*(track.fVertex));
+  
+  // copy hit weights matrices if any
+  if (track.fHitWeightsNonBending) fHitWeightsNonBending = new TMatrixD(*(track.fHitWeightsNonBending));
+  if (track.fHitWeightsBending) fHitWeightsBending = new TMatrixD(*(track.fHitWeightsBending));
   
 }
 
   //__________________________________________________________________________
-AliMUONTrack & AliMUONTrack::operator=(const AliMUONTrack& theMUONTrack)
+AliMUONTrack & AliMUONTrack::operator=(const AliMUONTrack& track)
 {
   /// Asignment operator
   // check assignement to self
-  if (this == &theMUONTrack)
+  if (this == &track)
     return *this;
 
   // base class assignement
-  TObject::operator=(theMUONTrack);
+  TObject::operator=(track);
 
-  fTrackParamAtVertex = theMUONTrack.fTrackParamAtVertex;
+  fTrackParamAtVertex = track.fTrackParamAtVertex;
 
   Int_t maxIndex = 0;
   
   // necessary to make a copy of the objects and not only the pointers in TClonesArray.
-  if (theMUONTrack.fTrackParamAtHit) {
+  if (track.fTrackParamAtHit) {
     if (fTrackParamAtHit) fTrackParamAtHit->Clear();
     else fTrackParamAtHit = new TClonesArray("AliMUONTrackParam",10);
-    maxIndex = (theMUONTrack.fTrackParamAtHit)->GetEntriesFast();
+    maxIndex = (track.fTrackParamAtHit)->GetEntriesFast();
     for (Int_t index = 0; index < maxIndex; index++) {
       new ((*fTrackParamAtHit)[fTrackParamAtHit->GetEntriesFast()])
-       AliMUONTrackParam(*(AliMUONTrackParam*)(theMUONTrack.fTrackParamAtHit)->At(index));
+       AliMUONTrackParam(*(AliMUONTrackParam*)(track.fTrackParamAtHit)->At(index));
     }
   } else if (fTrackParamAtHit) {
     delete fTrackParamAtHit;
@@ -220,13 +278,13 @@ AliMUONTrack & AliMUONTrack::operator=(const AliMUONTrack& theMUONTrack)
   }
 
   // necessary to make a copy of the objects and not only the pointers in TClonesArray.
-  if (theMUONTrack.fHitForRecAtHit) {
+  if (track.fHitForRecAtHit) {
     if (fHitForRecAtHit) fHitForRecAtHit->Clear();
     else fHitForRecAtHit = new TClonesArray("AliMUONHitForRec",10);
-    maxIndex = (theMUONTrack.fHitForRecAtHit)->GetEntriesFast();
+    maxIndex = (track.fHitForRecAtHit)->GetEntriesFast();
     for (Int_t index = 0; index < maxIndex; index++) {
       new ((*fHitForRecAtHit)[fHitForRecAtHit->GetEntriesFast()])
-       AliMUONHitForRec(*(AliMUONHitForRec*)(theMUONTrack.fHitForRecAtHit)->At(index));
+       AliMUONHitForRec(*(AliMUONHitForRec*)(track.fHitForRecAtHit)->At(index));
     }
   } else if (fHitForRecAtHit) {
     delete fHitForRecAtHit;
@@ -234,31 +292,75 @@ AliMUONTrack & AliMUONTrack::operator=(const AliMUONTrack& theMUONTrack)
   }
   
   // copy vertex used during the tracking procedure if any.
-  if (theMUONTrack.fVertex) {
-    if (fVertex) *fVertex = *(theMUONTrack.fVertex);
-    else fVertex = new AliMUONHitForRec(*(theMUONTrack.fVertex));
+  if (track.fVertex) {
+    if (fVertex) *fVertex = *(track.fVertex);
+    else fVertex = new AliMUONHitForRec(*(track.fVertex));
   } else if (fVertex) {
     delete fVertex;
     fVertex = 0x0;
   }
   
-  fExtrapTrackParam = theMUONTrack.fExtrapTrackParam;
+  // copy hit weights matrix if any
+  if (track.fHitWeightsNonBending) {
+    if (fHitWeightsNonBending) {
+      fHitWeightsNonBending->ResizeTo(*(track.fHitWeightsNonBending));
+      *fHitWeightsNonBending = *(track.fHitWeightsNonBending);
+    } else fHitWeightsNonBending = new TMatrixD(*(track.fHitWeightsNonBending));
+  } else if (fHitWeightsNonBending) {
+    delete fHitWeightsNonBending;
+    fHitWeightsNonBending = 0x0;
+  }
+  
+  // copy hit weights matrix if any
+  if (track.fHitWeightsBending) {
+    if (fHitWeightsBending) {
+      fHitWeightsBending->ResizeTo(*(track.fHitWeightsBending));
+      *fHitWeightsBending = *(track.fHitWeightsBending);
+    } else fHitWeightsBending = new TMatrixD(*(track.fHitWeightsBending));
+  } else if (fHitWeightsBending) {
+    delete fHitWeightsBending;
+    fHitWeightsBending = 0x0;
+  }
   
-  fNTrackHits         =  theMUONTrack.fNTrackHits;
-  fFitWithVertex      =  theMUONTrack.fFitWithVertex;
-  fFitFMin            =  theMUONTrack.fFitFMin;
-  fMatchTrigger       =  theMUONTrack.fMatchTrigger;
-  floTrgNum           =  theMUONTrack.floTrgNum;
-  fChi2MatchTrigger   =  theMUONTrack.fChi2MatchTrigger;
-  fTrackID            =  theMUONTrack.fTrackID; 
-  fHitsPatternInTrigCh = theMUONTrack.fHitsPatternInTrigCh;
-  fLocalTrigger        = theMUONTrack.fLocalTrigger;
+  fNTrackHits         =  track.fNTrackHits;
+  fFitWithVertex      =  track.fFitWithVertex;
+  fFitWithMCS         =  track.fFitWithMCS;
+  fGlobalChi2         =  track.fGlobalChi2;
+  fImproved           =  track.fImproved;
+  fMatchTrigger       =  track.fMatchTrigger;
+  floTrgNum           =  track.floTrgNum;
+  fChi2MatchTrigger   =  track.fChi2MatchTrigger;
+  fTrackID            =  track.fTrackID; 
+  fHitsPatternInTrigCh = track.fHitsPatternInTrigCh;
+  fLocalTrigger        = track.fLocalTrigger;
 
   return *this;
 }
 
   //__________________________________________________________________________
-void AliMUONTrack::AddTrackParamAtHit(AliMUONTrackParam *trackParam, AliMUONHitForRec *hitForRec) 
+AliMUONTrack::~AliMUONTrack()
+{
+  /// Destructor
+  delete fTrackParamAtHit;
+  delete fHitForRecAtHit;
+  delete fVertex;
+  delete fHitWeightsNonBending;
+  delete fHitWeightsBending;
+}
+
+  //__________________________________________________________________________
+void AliMUONTrack::Clear(Option_t* opt)
+{
+  /// Clear arrays
+  if ( fTrackParamAtHit ) fTrackParamAtHit->Clear(opt);
+  if ( fHitForRecAtHit ) fHitForRecAtHit->Clear(opt);
+  delete fVertex; fVertex = 0x0;
+  delete fHitWeightsNonBending; fHitWeightsNonBending = 0x0;
+  delete fHitWeightsBending; fHitWeightsBending = 0x0;
+}
+
+  //__________________________________________________________________________
+void AliMUONTrack::AddTrackParamAtHit(const AliMUONTrackParam *trackParam, AliMUONHitForRec *hitForRec)
 {
   /// Add TrackParamAtHit if "trackParam" != NULL
   /// else create empty TrackParamAtHit and set the z position to the one of "hitForRec" if any
@@ -282,6 +384,24 @@ void AliMUONTrack::AddTrackParamAtHit(AliMUONTrackParam *trackParam, AliMUONHitF
   fNTrackHits++;
 }
 
+  //__________________________________________________________________________
+void AliMUONTrack::RemoveTrackParamAtHit(AliMUONTrackParam *trackParam)
+{
+  /// Remove trackParam from the array of TrackParamAtHit
+  if (!fTrackParamAtHit) {
+    AliWarning("array fTrackParamAtHit does not exist");
+    return;
+  }
+  
+  if (!fTrackParamAtHit->Remove(trackParam)) {
+    AliWarning("object to remove does not exist in array fTrackParamAtHit");
+    return;
+  }
+  
+  fTrackParamAtHit->Compress();
+  fNTrackHits--;
+}
+
   //__________________________________________________________________________
 void AliMUONTrack::AddHitForRecAtHit(const AliMUONHitForRec *hitForRec) 
 {
@@ -295,23 +415,501 @@ void AliMUONTrack::AddHitForRecAtHit(const AliMUONHitForRec *hitForRec)
   new ((*fHitForRecAtHit)[fHitForRecAtHit->GetEntriesFast()]) AliMUONHitForRec(*hitForRec);
 }
 
-//__________________________________________________________________________
-void
-AliMUONTrack::Clear(Option_t* opt)
+  //__________________________________________________________________________
+void AliMUONTrack::UpdateTrackParamAtHit()
 {
-  /// Clear arrays
-  if ( fTrackParamAtHit ) fTrackParamAtHit->Clear(opt);
-  if ( fHitForRecAtHit ) fHitForRecAtHit->Clear(opt);
+  /// Update track parameters at each attached hit
+  
+  if (fNTrackHits == 0) {
+    AliWarning("no hit attached to the track");
+    return;
+  }
+  
+  Double_t z;
+  AliMUONTrackParam* startingTrackParam = (AliMUONTrackParam*) fTrackParamAtHit->First();
+  AliMUONTrackParam* trackParamAtHit = (AliMUONTrackParam*) fTrackParamAtHit->After(startingTrackParam);
+  while (trackParamAtHit) {
+    
+    // save current z
+    z = trackParamAtHit->GetZ();
+    
+    // reset track parameters and their covariances
+    trackParamAtHit->SetParameters(startingTrackParam->GetParameters());
+    trackParamAtHit->SetZ(startingTrackParam->GetZ());
+    
+    // extrapolation to the given z
+    AliMUONTrackExtrap::ExtrapToZ(trackParamAtHit, z);
+    
+    // prepare next step
+    startingTrackParam = trackParamAtHit;
+    trackParamAtHit = (AliMUONTrackParam*) (fTrackParamAtHit->After(trackParamAtHit));
+  }
+
 }
 
   //__________________________________________________________________________
-void AliMUONTrack::SetVertex(AliMUONHitForRec* vertex)
+void AliMUONTrack::UpdateCovTrackParamAtHit()
+{
+  /// Update track parameters and their covariances at each attached hit
+  
+  if (fNTrackHits == 0) {
+    AliWarning("no hit attached to the track");
+    return;
+  }
+  
+  Double_t z;
+  AliMUONTrackParam* startingTrackParam = (AliMUONTrackParam*) fTrackParamAtHit->First();
+  AliMUONTrackParam* trackParamAtHit = (AliMUONTrackParam*) fTrackParamAtHit->After(startingTrackParam);
+  while (trackParamAtHit) {
+    
+    // save current z
+    z = trackParamAtHit->GetZ();
+    
+    // reset track parameters and their covariances
+    trackParamAtHit->SetParameters(startingTrackParam->GetParameters());
+    trackParamAtHit->SetZ(startingTrackParam->GetZ());
+    trackParamAtHit->SetCovariances(startingTrackParam->GetCovariances());
+    
+    // extrapolation to the given z
+    AliMUONTrackExtrap::ExtrapToZCov(trackParamAtHit, z);
+    
+    // prepare next step
+    startingTrackParam = trackParamAtHit;
+    trackParamAtHit = (AliMUONTrackParam*) (fTrackParamAtHit->After(trackParamAtHit));
+  }
+
+}
+
+  //__________________________________________________________________________
+void AliMUONTrack::SetVertex(const AliMUONHitForRec* vertex)
 {
   /// Set the vertex used during the tracking procedure
   if (!fVertex) fVertex = new AliMUONHitForRec(*vertex);
   else *fVertex = *vertex;
 }
 
+
+  //__________________________________________________________________________
+Bool_t AliMUONTrack::ComputeLocalChi2(Bool_t accountForMCS)
+{
+  /// Compute the removable hit contribution to the chi2 of the track
+  /// accounting for multiple scattering or not according to the flag
+  /// - Also recompute the weight matrices of the attached hits if accountForMCS=kTRUE
+  /// - Assume that track parameters at each hit are corrects
+  /// - Return kFALSE if computation failed
+  
+  // Check hits (if the first one exist, assume that the other ones exit too!)
+  AliMUONTrackParam* trackParamAtHit = (AliMUONTrackParam*) fTrackParamAtHit->First();
+  if (!trackParamAtHit->GetHitForRecPtr()) {
+    AliWarning("hit is missing");
+    return kFALSE;
+  }
+  
+  if (accountForMCS) { // Compute local chi2 taking into account multiple scattering effects
+      
+    // Compute MCS covariance matrix only once
+    TMatrixD mcsCovariances(AliMUONConstants::NTrackingCh(),AliMUONConstants::NTrackingCh());
+    ComputeMCSCovariances(mcsCovariances);
+    
+    // Make sure hit weights are consistent with following calculations
+    if (!ComputeHitWeights(&mcsCovariances)) {
+      AliWarning("cannot take into account the multiple scattering effects");
+      return ComputeLocalChi2(kFALSE);
+    }
+    
+    // Compute chi2 of the track
+    Double_t globalChi2 = ComputeGlobalChi2(kTRUE);
+    if (globalChi2 < 0.) return kFALSE;
+    
+    // Loop over removable hits and compute their local chi2
+    AliMUONTrackParam* trackParamAtHit1;
+    AliMUONHitForRec *hitForRec, *discardedHit;
+    Int_t hitNumber1, hitNumber2, currentHitNumber1, currentHitNumber2;
+    TMatrixD hitWeightsNB(fNTrackHits-1,fNTrackHits-1);
+    TMatrixD hitWeightsB(fNTrackHits-1,fNTrackHits-1);
+    Double_t *dX = new Double_t[fNTrackHits-1];
+    Double_t *dY = new Double_t[fNTrackHits-1];
+    Double_t globalChi2b;
+    while (trackParamAtHit) {
+      
+      discardedHit = trackParamAtHit->GetHitForRecPtr();
+      
+      // Recompute hit weights without the current hit
+      if (!ComputeHitWeights(hitWeightsNB, hitWeightsB, &mcsCovariances, discardedHit)) {
+       AliWarning("cannot take into account the multiple scattering effects");
+       ComputeLocalChi2(kFALSE);
+      }
+      
+      // Compute track chi2 without the current hit
+      globalChi2b = 0.;
+      currentHitNumber1 = 0;
+      for (hitNumber1 = 0; hitNumber1 < fNTrackHits ; hitNumber1++) { 
+       trackParamAtHit1 = (AliMUONTrackParam*) fTrackParamAtHit->UncheckedAt(hitNumber1);
+       hitForRec = trackParamAtHit1->GetHitForRecPtr();
+        
+        if (hitForRec == discardedHit) continue;
+        
+        // Compute and save residuals
+       dX[currentHitNumber1] = hitForRec->GetNonBendingCoor() - trackParamAtHit1->GetNonBendingCoor();
+       dY[currentHitNumber1] = hitForRec->GetBendingCoor() - trackParamAtHit1->GetBendingCoor();
+        
+        currentHitNumber2 = 0;
+       for (hitNumber2 = 0; hitNumber2 < hitNumber1; hitNumber2++) {
+         hitForRec = ((AliMUONTrackParam*) fTrackParamAtHit->UncheckedAt(hitNumber2))->GetHitForRecPtr();
+          
+          if (hitForRec == discardedHit) continue;
+          
+          // Add contribution from covariances
+          globalChi2b += (hitWeightsNB(currentHitNumber1, currentHitNumber2) +
+                         hitWeightsNB(currentHitNumber2, currentHitNumber1)) * dX[currentHitNumber1] * dX[currentHitNumber2] +
+                        (hitWeightsB(currentHitNumber1, currentHitNumber2) +
+                         hitWeightsB(currentHitNumber2, currentHitNumber1)) * dY[currentHitNumber1] * dY[currentHitNumber2];
+          
+          currentHitNumber2++;
+       }
+        
+        // Add contribution from variances
+       globalChi2b += hitWeightsNB(currentHitNumber1, currentHitNumber1) * dX[currentHitNumber1] * dX[currentHitNumber1] +
+                      hitWeightsB(currentHitNumber1, currentHitNumber1) * dY[currentHitNumber1] * dY[currentHitNumber1];
+       
+        currentHitNumber1++;
+      }
+
+      // Set local chi2
+      trackParamAtHit->SetLocalChi2(globalChi2 - globalChi2b);
+      
+      trackParamAtHit = (AliMUONTrackParam*) fTrackParamAtHit->After(trackParamAtHit);
+    }
+    
+    delete [] dX;
+    delete [] dY;
+    
+  } else { // without multiple scattering effects
+    
+    AliMUONHitForRec *discardedHit;
+    Double_t dX, dY;
+    while (trackParamAtHit) {
+      
+      // compute chi2 of removable hits only
+      if (!trackParamAtHit->IsRemovable()) {
+        trackParamAtHit = (AliMUONTrackParam*) fTrackParamAtHit->After(trackParamAtHit);
+        continue;
+      }
+      
+      discardedHit = trackParamAtHit->GetHitForRecPtr();
+      
+      // Compute residuals
+      dX = discardedHit->GetNonBendingCoor() - trackParamAtHit->GetNonBendingCoor();
+      dY = discardedHit->GetBendingCoor() - trackParamAtHit->GetBendingCoor();
+      
+      // Set local chi2
+      trackParamAtHit->SetLocalChi2(dX * dX / discardedHit->GetNonBendingReso2() + dY * dY / discardedHit->GetBendingReso2());
+    
+    trackParamAtHit = (AliMUONTrackParam*) fTrackParamAtHit->After(trackParamAtHit);
+    }
+  
+  }
+  
+  
+  return kTRUE;
+  
+}
+
+  //__________________________________________________________________________
+Double_t AliMUONTrack::ComputeGlobalChi2(Bool_t accountForMCS)
+{
+  /// Compute the chi2 of the track accounting for multiple scattering or not according to the flag
+  /// - Assume that track parameters at each hit are corrects
+  /// - Assume the hits weights matrices are corrects
+  /// - Return negative value if chi2 computation failed
+  
+  // Check hits (if the first one exist, assume that the other ones exit too!)
+  AliMUONTrackParam* trackParamAtHit = (AliMUONTrackParam*) fTrackParamAtHit->First();
+  if (!trackParamAtHit->GetHitForRecPtr()) {
+    AliWarning("hit is missing");
+    return -1.;
+  }
+  
+  Double_t chi2 = 0.;
+  
+  if (accountForMCS) {
+    
+    // Check the weight matrices
+    Bool_t weightsAvailable = kTRUE;
+    if (!fHitWeightsNonBending || !fHitWeightsBending) weightsAvailable = kFALSE;
+    else if (fHitWeightsNonBending->GetNrows() != fNTrackHits || fHitWeightsNonBending->GetNcols() != fNTrackHits ||
+            fHitWeightsBending->GetNrows()    != fNTrackHits || fHitWeightsBending->GetNcols()    != fNTrackHits) weightsAvailable = kFALSE;
+    
+    // if weight matrices are not available compute chi2 without MCS
+    if (!weightsAvailable) {
+      AliWarning("hit weights including multiple scattering effects are not available\n\t\t --> compute chi2 WITHOUT multiple scattering");
+      return ComputeGlobalChi2(kFALSE);
+    }
+    
+    // Compute chi2
+    AliMUONHitForRec *hitForRec;
+    Double_t *dX = new Double_t[fNTrackHits];
+    Double_t *dY = new Double_t[fNTrackHits];
+    Int_t hitNumber1, hitNumber2;
+    for (hitNumber1 = 0; hitNumber1 < fNTrackHits ; hitNumber1++) { 
+      trackParamAtHit = (AliMUONTrackParam*) fTrackParamAtHit->UncheckedAt(hitNumber1);
+      hitForRec = trackParamAtHit->GetHitForRecPtr();
+      dX[hitNumber1] = hitForRec->GetNonBendingCoor() - trackParamAtHit->GetNonBendingCoor();
+      dY[hitNumber1] = hitForRec->GetBendingCoor() - trackParamAtHit->GetBendingCoor();
+      for (hitNumber2 = 0; hitNumber2 < hitNumber1; hitNumber2++) {
+        chi2 += ((*fHitWeightsNonBending)(hitNumber1, hitNumber2) + (*fHitWeightsNonBending)(hitNumber2, hitNumber1)) * dX[hitNumber1] * dX[hitNumber2] +
+               ((*fHitWeightsBending)(hitNumber1, hitNumber2) + (*fHitWeightsBending)(hitNumber2, hitNumber1)) * dY[hitNumber1] * dY[hitNumber2];
+      }
+      chi2 += ((*fHitWeightsNonBending)(hitNumber1, hitNumber1) * dX[hitNumber1] * dX[hitNumber1]) +
+             ((*fHitWeightsBending)(hitNumber1, hitNumber1) * dY[hitNumber1] * dY[hitNumber1]);
+    }
+    delete [] dX;
+    delete [] dY;
+    
+  } else {
+    
+    AliMUONHitForRec *hitForRec;
+    Double_t dX, dY;
+    for (Int_t hitNumber = 0; hitNumber < fNTrackHits ; hitNumber++) { 
+      trackParamAtHit = (AliMUONTrackParam*) fTrackParamAtHit->UncheckedAt(hitNumber);
+      hitForRec = trackParamAtHit->GetHitForRecPtr();
+      dX = hitForRec->GetNonBendingCoor() - trackParamAtHit->GetNonBendingCoor();
+      dY = hitForRec->GetBendingCoor() - trackParamAtHit->GetBendingCoor();
+      chi2 += dX * dX / hitForRec->GetNonBendingReso2() + dY * dY / hitForRec->GetBendingReso2();
+    }
+    
+  }
+  
+  return chi2;
+  
+}
+
+  //__________________________________________________________________________
+Bool_t AliMUONTrack::ComputeHitWeights(TMatrixD* mcsCovariances)
+{
+  /// Compute the weight matrices of the attached hits, in non bending and bending direction,
+  /// accounting for multiple scattering correlations and hits resolution
+  /// - Use the provided MCS covariance matrix if any (otherwise build it temporarily)
+  /// - Assume that track parameters at each hit are corrects
+  /// - Return kFALSE if computation failed
+  
+  // Alocate memory
+  if (!fHitWeightsNonBending) fHitWeightsNonBending = new TMatrixD(fNTrackHits,fNTrackHits);
+  if (!fHitWeightsBending) fHitWeightsBending = new TMatrixD(fNTrackHits,fNTrackHits);
+  
+  // Check hits (if the first one exist, assume that the other ones exit too!)
+  if (!((AliMUONTrackParam*) fTrackParamAtHit->First())->GetHitForRecPtr()) {
+    AliWarning("hit is missing");
+    fHitWeightsNonBending->ResizeTo(0,0);
+    fHitWeightsBending->ResizeTo(0,0);
+    return kFALSE;
+  }
+  
+  // Compute weights matrices
+  if (!ComputeHitWeights(*fHitWeightsNonBending, *fHitWeightsBending, mcsCovariances)) return kFALSE;
+  
+  return kTRUE;
+  
+}
+
+  //__________________________________________________________________________
+Bool_t AliMUONTrack::ComputeHitWeights(TMatrixD& hitWeightsNB, TMatrixD& hitWeightsB, TMatrixD* mcsCovariances, AliMUONHitForRec* discardedHit) const
+{
+  /// Compute the weight matrices, in non bending and bending direction,
+  /// of the other attached hits assuming the discarded one does not exist
+  /// accounting for multiple scattering correlations and hits resolution
+  /// - Use the provided MCS covariance matrix if any (otherwise build it temporarily)
+  /// - Return kFALSE if computation failed
+  
+  // Check MCS covariance matrix and recompute it if need
+  Bool_t deleteMCSCov = kFALSE;
+  if (!mcsCovariances) {
+    
+    // build MCS covariance matrix
+    mcsCovariances = new TMatrixD(AliMUONConstants::NTrackingCh(),AliMUONConstants::NTrackingCh());
+    deleteMCSCov = kTRUE;
+    ComputeMCSCovariances(*mcsCovariances);
+    
+  } else {
+    
+    // check MCS covariance matrix size
+    if (mcsCovariances->GetNrows() != AliMUONConstants::NTrackingCh() || mcsCovariances->GetNcols() != AliMUONConstants::NTrackingCh()) {
+      ComputeMCSCovariances(*mcsCovariances);
+    }
+    
+  }
+  
+  // Resize the weights matrices; alocate memory
+  if (discardedHit) {
+    hitWeightsNB.ResizeTo(fNTrackHits-1,fNTrackHits-1);
+    hitWeightsB.ResizeTo(fNTrackHits-1,fNTrackHits-1);
+  } else {
+    hitWeightsNB.ResizeTo(fNTrackHits,fNTrackHits);
+    hitWeightsB.ResizeTo(fNTrackHits,fNTrackHits);
+  }
+  
+  // Define variables
+  AliMUONHitForRec *hitForRec1, *hitForRec2;
+  Int_t chamber1, chamber2, currentHitNumber1, currentHitNumber2;
+  
+  // Compute the covariance matrices
+  currentHitNumber1 = 0;
+  for (Int_t hitNumber1 = 0; hitNumber1 < fNTrackHits; hitNumber1++) { 
+    hitForRec1 = ((AliMUONTrackParam*) fTrackParamAtHit->UncheckedAt(hitNumber1))->GetHitForRecPtr();
+    
+    if (hitForRec1 == discardedHit) continue;
+    
+    chamber1 = hitForRec1->GetChamberNumber();
+    
+    // Loop over next hits
+    currentHitNumber2 = currentHitNumber1;
+    for (Int_t hitNumber2 = hitNumber1; hitNumber2 < fNTrackHits; hitNumber2++) {
+      hitForRec2 = ((AliMUONTrackParam*) fTrackParamAtHit->UncheckedAt(hitNumber2))->GetHitForRecPtr();
+      
+      if (hitForRec2 == discardedHit) continue;
+      
+      chamber2 = hitForRec2->GetChamberNumber();
+    
+      // Fill with MCS covariances
+      hitWeightsNB(currentHitNumber1, currentHitNumber2) = (*mcsCovariances)(chamber1,chamber2);
+      
+      // Equal contribution from multiple scattering in non bending and bending directions
+      hitWeightsB(currentHitNumber1, currentHitNumber2) = hitWeightsNB(currentHitNumber1, currentHitNumber2);
+      
+      // Add contribution from hit resolution to diagonal element and symmetrize the matrix
+      if (currentHitNumber1 == currentHitNumber2) {
+       
+       // In non bending plane
+        hitWeightsNB(currentHitNumber1, currentHitNumber1) += hitForRec1->GetNonBendingReso2();
+       // In bending plane
+       hitWeightsB(currentHitNumber1, currentHitNumber1) += hitForRec1->GetBendingReso2();
+       
+      } else {
+       
+       // In non bending plane
+       hitWeightsNB(currentHitNumber2, currentHitNumber1) = hitWeightsNB(currentHitNumber1, currentHitNumber2);
+       // In bending plane
+       hitWeightsB(currentHitNumber2, currentHitNumber1) = hitWeightsB(currentHitNumber1, currentHitNumber2);
+       
+      }
+      
+      currentHitNumber2++;
+    }
+    
+    currentHitNumber1++;
+  }
+    
+  // Inversion of covariance matrices to get the weights
+  if (hitWeightsNB.Determinant() != 0 && hitWeightsB.Determinant() != 0) {
+    hitWeightsNB.Invert();
+    hitWeightsB.Invert();
+  } else {
+    AliWarning(" Determinant = 0");
+    hitWeightsNB.ResizeTo(0,0);
+    hitWeightsB.ResizeTo(0,0);
+    if(deleteMCSCov) delete mcsCovariances;
+    return kFALSE;
+  }
+  
+  if(deleteMCSCov) delete mcsCovariances;
+  
+  return kTRUE;
+  
+}
+
+  //__________________________________________________________________________
+void AliMUONTrack::ComputeMCSCovariances(TMatrixD& mcsCovariances) const
+{
+  /// Compute the multiple scattering covariance matrix
+  /// - Assume that track parameters at each hit are corrects
+  /// - Return kFALSE if computation failed
+  
+  // Make sure the size of the covariance matrix is correct
+  Int_t nChambers = AliMUONConstants::NTrackingCh();
+  mcsCovariances.ResizeTo(nChambers,nChambers);
+  
+  // check for too many track hits
+  if (fNTrackHits > nChambers) {
+    AliWarning("more than 1 hit per chamber!!");
+    mcsCovariances.Zero();
+    return;
+  }
+  
+  // Define variables
+  AliMUONTrackParam* trackParamAtHit;
+  AliMUONHitForRec *hitForRec;
+  AliMUONTrackParam extrapTrackParam;
+  Int_t currentChamber, expectedChamber;
+  Double_t *mcsAngle2 = new Double_t[nChambers];
+  Double_t *zMCS = new Double_t[nChambers];
+  
+  // Compute multiple scattering dispersion angle at each chamber
+  // and save the z position where it is calculated
+  currentChamber = 0;
+  expectedChamber = 0;
+  for (Int_t hitNumber = 0; hitNumber < fNTrackHits; hitNumber++) {
+    trackParamAtHit = (AliMUONTrackParam*) fTrackParamAtHit->UncheckedAt(hitNumber);
+    hitForRec = trackParamAtHit->GetHitForRecPtr();
+    
+    // look for missing chambers if any
+    currentChamber = hitForRec->GetChamberNumber();
+    while (currentChamber > expectedChamber) {
+      
+      // Save the z position where MCS dispersion is calculated
+      zMCS[expectedChamber] = AliMUONConstants::DefaultChamberZ(expectedChamber);
+      
+      // Do not take into account MCS in chambers prior the first hit
+      if (hitNumber > 0) {
+        
+        // Get track parameters at missing chamber z
+        extrapTrackParam = *trackParamAtHit;
+        AliMUONTrackExtrap::ExtrapToZ(&extrapTrackParam, zMCS[expectedChamber]);
+        
+        // Save multiple scattering dispersion angle in missing chamber
+        mcsAngle2[expectedChamber] = AliMUONTrackExtrap::GetMCSAngle2(extrapTrackParam,AliMUONConstants::ChamberThicknessInX0(),1.);
+        
+      } else mcsAngle2[expectedChamber] = 0.;
+      
+      expectedChamber++;
+    }
+    
+    // Save z position where MCS dispersion is calculated
+    zMCS[currentChamber] = trackParamAtHit->GetZ();
+    
+    // Save multiple scattering dispersion angle in current chamber
+    mcsAngle2[currentChamber] = AliMUONTrackExtrap::GetMCSAngle2(*trackParamAtHit,AliMUONConstants::ChamberThicknessInX0(),1.);
+    
+    expectedChamber++;
+  }
+  
+  // complete array of z if last hit is on the last but one chamber
+  if (currentChamber != nChambers-1) zMCS[nChambers-1] = AliMUONConstants::DefaultChamberZ(nChambers-1);
+  
+  
+  // Compute the covariance matrix
+  for (Int_t chamber1 = 0; chamber1 < nChambers; chamber1++) { 
+    
+    for (Int_t chamber2 = chamber1; chamber2 < nChambers; chamber2++) {
+      
+      // Initialization to 0 (diagonal plus upper triangular part)
+      mcsCovariances(chamber1, chamber2) = 0.;
+      
+      // Compute contribution from multiple scattering in upstream chambers
+      for (currentChamber = 0; currentChamber < chamber1; currentChamber++) {  
+       mcsCovariances(chamber1, chamber2) += (zMCS[chamber1] - zMCS[currentChamber]) * (zMCS[chamber2] - zMCS[currentChamber]) * mcsAngle2[currentChamber];
+      }
+      
+      // Symetrize the matrix
+      mcsCovariances(chamber2, chamber1) = mcsCovariances(chamber1, chamber2);
+    }
+    
+  }
+    
+  delete [] mcsAngle2;
+  delete [] zMCS;
+  
+}
+
   //__________________________________________________________________________
 Int_t AliMUONTrack::HitsInCommon(AliMUONTrack* track) const
 {
@@ -337,6 +935,16 @@ Int_t AliMUONTrack::HitsInCommon(AliMUONTrack* track) const
   return hitsInCommon;
 }
 
+  //__________________________________________________________________________
+Double_t AliMUONTrack::GetNormalizedChi2() const
+{
+  /// return the chi2 value divided by the number of degrees of freedom (or 1.e10 if ndf < 0)
+  
+  Double_t numberOfDegFree = (2. * fNTrackHits - 5.);
+  if (numberOfDegFree > 0.) return fGlobalChi2 / numberOfDegFree;
+  else return 1.e10;
+}
+
   //__________________________________________________________________________
 Bool_t* AliMUONTrack::CompatibleTrack(AliMUONTrack * track, Double_t sigma2Cut) const
 {
@@ -374,156 +982,6 @@ Bool_t* AliMUONTrack::CompatibleTrack(AliMUONTrack * track, Double_t sigma2Cut)
   }
   
   return nCompHit;
-}
-
-  //__________________________________________________________________________
-Double_t AliMUONTrack::TryOneHitForRec(AliMUONHitForRec* hitForRec)
-{
-/// Test the compatibility between the track and the hitForRec:
-/// return the corresponding Chi2
-  
-  // Get track parameters and their covariances at the z position of hitForRec
-  AliMUONTrackParam extrapTrackParam(fExtrapTrackParam);
-  AliMUONTrackExtrap::ExtrapToZCov(&extrapTrackParam, hitForRec->GetZ());
-  
-  // Set differences between trackParam and hitForRec in the bending and non bending directions
-  TMatrixD dPos(2,1);
-  dPos(0,0) = hitForRec->GetNonBendingCoor() - extrapTrackParam.GetNonBendingCoor();
-  dPos(1,0) = hitForRec->GetBendingCoor() - extrapTrackParam.GetBendingCoor();
-  
-  // quick test of hitForRec compatibility within a wide road of x*y = 10*1 cm2 to save computing time
-  if (TMath::Abs(dPos(0,0)) > fgkMaxTrackingDistanceNonBending ||
-      TMath::Abs(dPos(1,0)) > fgkMaxTrackingDistanceBending) return 1.e10;
-  
-  // Set the error matrix from trackParam covariances and hitForRec resolution
-  TMatrixD* paramCov = extrapTrackParam.GetCovariances();
-  TMatrixD error(2,2);
-  error(0,0) = (*paramCov)(0,0) + hitForRec->GetNonBendingReso2();
-  error(0,1) = (*paramCov)(0,2);
-  error(1,0) = (*paramCov)(2,0);
-  error(1,1) = (*paramCov)(2,2) + hitForRec->GetBendingReso2();
-  
-  // Invert the error matrix for Chi2 calculation
-  if (error.Determinant() != 0) {
-    error.Invert();
-  } else {
-    AliWarning(" Determinant error=0");
-    return 1.e10;
-  }
-  
-  // Compute the Chi2 value
-  TMatrixD tmp(error,TMatrixD::kMult,dPos);
-  TMatrixD result(dPos,TMatrixD::kTransposeMult,tmp);
-  
-  return result(0,0);
-  
-}
-
-  //__________________________________________________________________________
-Double_t AliMUONTrack::TryTwoHitForRec(AliMUONHitForRec* hitForRec1, AliMUONHitForRec* hitForRec2)
-{
-/// Test the compatibility between the track and the 2 hitForRec together:
-/// return the corresponding Chi2 accounting for covariances between the 2 hitForRec
-  
-  // Get track parameters and their covariances at the z position of the first hitForRec
-  AliMUONTrackParam extrapTrackParam1(fExtrapTrackParam);
-  AliMUONTrackExtrap::ExtrapToZCov(&extrapTrackParam1, hitForRec1->GetZ());
-  
-  // Get track parameters at second hitForRec
-  AliMUONTrackParam extrapTrackParam2(extrapTrackParam1);
-  AliMUONTrackExtrap::ExtrapToZ(&extrapTrackParam2, hitForRec2->GetZ());
-  
-  // Set differences between track and the 2 hitForRec in the bending and non bending directions
-  TMatrixD dPos(4,1);
-  dPos(0,0) = hitForRec1->GetNonBendingCoor() - extrapTrackParam1.GetNonBendingCoor();
-  dPos(1,0) = hitForRec1->GetBendingCoor() - extrapTrackParam1.GetBendingCoor();
-  dPos(2,0) = hitForRec2->GetNonBendingCoor() - extrapTrackParam2.GetNonBendingCoor();
-  dPos(3,0) = hitForRec2->GetBendingCoor() - extrapTrackParam2.GetBendingCoor();
-  
-  // quick tests of hitForRec compatibility within a wide road of x*y = 1*1 cm2 to save computing time
-  if (TMath::Abs(dPos(0,0)) > fgkMaxTrackingDistanceNonBending ||
-      TMath::Abs(dPos(1,0)) > fgkMaxTrackingDistanceBending    ||
-      TMath::Abs(dPos(2,0)) > fgkMaxTrackingDistanceNonBending ||
-      TMath::Abs(dPos(3,0)) > fgkMaxTrackingDistanceBending) return 1.e10;
-  
-  // Calculate the error matrix from the track parameter covariances at first hitForRec
-  TMatrixD error(4,4);
-  error = 0.;
-  if (extrapTrackParam1.CovariancesExist()) {
-    // Get the pointer to the parameter covariance matrix at first hitForRec
-    TMatrixD* paramCov = extrapTrackParam1.GetCovariances();
-    
-    // Save track parameters at first hitForRec
-    AliMUONTrackParam extrapTrackParam1Save(extrapTrackParam1);
-    Double_t nonBendingCoor1        = extrapTrackParam1Save.GetNonBendingCoor();
-    Double_t nonBendingSlope1       = extrapTrackParam1Save.GetNonBendingSlope();
-    Double_t bendingCoor1           = extrapTrackParam1Save.GetBendingCoor();
-    Double_t bendingSlope1          = extrapTrackParam1Save.GetBendingSlope();
-    Double_t inverseBendingMomentum1 = extrapTrackParam1Save.GetInverseBendingMomentum();
-    Double_t z1                             = extrapTrackParam1Save.GetZ();
-    
-    // Save track coordinates at second hitForRec
-    Double_t nonBendingCoor2        = extrapTrackParam2.GetNonBendingCoor();
-    Double_t bendingCoor2           = extrapTrackParam2.GetBendingCoor();
-    
-    // Calculate the jacobian related to the transformation between track parameters
-    // at first hitForRec and track coordinates at the 2 hitForRec z-position
-    TMatrixD jacob(4,5);
-    jacob = 0.;
-    // first derivative at the first hitForRec:
-    jacob(0,0) = 1.; // dx1/dx
-    jacob(1,2) = 1.; // dy1/dy
-    // first derivative at the second hitForRec:
-    Double_t dParam[5];
-    for (Int_t i=0; i<5; i++) {
-      // Skip jacobian calculation for parameters with no associated error
-      if ((*paramCov)(i,i) == 0.) continue;
-      // Small variation of parameter i only
-      for (Int_t j=0; j<5; j++) {
-        if (j==i) {
-          dParam[j] = TMath::Sqrt((*paramCov)(i,i));
-         if (j == 4) dParam[j] *= TMath::Sign(1.,-inverseBendingMomentum1); // variation always in the same direction
-        } else dParam[j] = 0.;
-      }
-      // Set new track parameters at first hitForRec
-      extrapTrackParam1Save.SetNonBendingCoor       (nonBendingCoor1         + dParam[0]);
-      extrapTrackParam1Save.SetNonBendingSlope      (nonBendingSlope1        + dParam[1]);
-      extrapTrackParam1Save.SetBendingCoor          (bendingCoor1            + dParam[2]);
-      extrapTrackParam1Save.SetBendingSlope         (bendingSlope1           + dParam[3]);
-      extrapTrackParam1Save.SetInverseBendingMomentum(inverseBendingMomentum1 + dParam[4]);
-      extrapTrackParam1Save.SetZ                    (z1);
-      // Extrapolate new track parameters to the z position of the second hitForRec
-      AliMUONTrackExtrap::ExtrapToZ(&extrapTrackParam1Save,hitForRec2->GetZ());
-      // Calculate the jacobian
-      jacob(2,i) = (extrapTrackParam1Save.GetNonBendingCoor()  - nonBendingCoor2) / dParam[i]; // dx2/dParami
-      jacob(3,i) = (extrapTrackParam1Save.GetBendingCoor()     - bendingCoor2   ) / dParam[i]; // dy2/dParami
-    }
-    
-    // Calculate the error matrix
-    TMatrixD tmp((*paramCov),TMatrixD::kMultTranspose,jacob);
-    error = TMatrixD(jacob,TMatrixD::kMult,tmp);
-  }
-  
-  // Add hitForRec resolution to the error matrix
-  error(0,0) += hitForRec1->GetNonBendingReso2();
-  error(1,1) += hitForRec1->GetBendingReso2();
-  error(2,2) += hitForRec2->GetNonBendingReso2();
-  error(3,3) += hitForRec2->GetBendingReso2();
-  
-  // invert the error matrix for Chi2 calculation
-  if (error.Determinant() != 0) {
-    error.Invert();
-  } else {
-    AliWarning(" Determinant error=0");
-    return 1.e10;
-  }
-  
-  // Compute the Chi2 value
-  TMatrixD tmp2(error,TMatrixD::kMult,dPos);
-  TMatrixD result(dPos,TMatrixD::kTransposeMult,tmp2);
-  
-  return result(0,0);
-  
 }
 
   //__________________________________________________________________________
index 57161df957ac7ff454169d69c093b4622ee69d17..87936e19ac221e85b7059803e95a022c683d5d5c 100644 (file)
 /// Reconstructed track in ALICE dimuon spectrometer
 ////////////////////////////////////////////////////
 
-#include <TClonesArray.h>
-
 #include "AliMUONTrackParam.h" // object belongs to the class
+#include <TClonesArray.h>
 
 class AliMUONHitForRec;
+class AliMUONObjectPair;
 
 class AliMUONTrack : public TObject 
 {
  public:
   AliMUONTrack(); // Default constructor
+  AliMUONTrack(AliMUONObjectPair *segment); // Constructor from a segment
   virtual ~AliMUONTrack(); // Destructor
-  AliMUONTrack (const AliMUONTrack& AliMUONTrack); // copy constructor
-  AliMUONTrack& operator=(const AliMUONTrack& AliMUONTrack); // assignment operator
+  AliMUONTrack (const AliMUONTrack& track); // copy constructor
+  AliMUONTrack& operator=(const AliMUONTrack& track); // assignment operator
 
-  AliMUONTrack(AliMUONHitForRec* hitForRec1, AliMUONHitForRec* hitForRec2); // Constructor from a segment
 
        /// return pointeur to track parameters at vertex
-  AliMUONTrackParam*         GetTrackParamAtVertex(void) {return &fTrackParamAtVertex;}
+  AliMUONTrackParam*         GetTrackParamAtVertex() {return &fTrackParamAtVertex;}
        /// set track parameters at vertex
-  void                       SetTrackParamAtVertex(AliMUONTrackParam* trackParam) {fTrackParamAtVertex = *trackParam;}
+  void                       SetTrackParamAtVertex(const AliMUONTrackParam* trackParam) {fTrackParamAtVertex = *trackParam;}
 
        /// return array of track parameters at hit
-  TClonesArray*              GetTrackParamAtHit(void) const {return fTrackParamAtHit;}
+  TClonesArray*              GetTrackParamAtHit() const {return fTrackParamAtHit;}
        /// reset array of track parameters at hit
-  void                       ResetTrackParamAtHit(void) { fTrackParamAtHit->Delete(); }
-  void                       AddTrackParamAtHit(AliMUONTrackParam *trackParam, AliMUONHitForRec *hitForRec); 
+  void                       ResetTrackParamAtHit() { fTrackParamAtHit->Delete(); }
+  void                       AddTrackParamAtHit(const AliMUONTrackParam *trackParam, AliMUONHitForRec *hitForRec); 
+  void                       RemoveTrackParamAtHit(AliMUONTrackParam *trackParam);
+  void                       UpdateTrackParamAtHit();
+  void                       UpdateCovTrackParamAtHit();
   
        /// return array of hitForRec at hit
-  TClonesArray*              GetHitForRecAtHit(void) const {return fHitForRecAtHit;}
+  TClonesArray*              GetHitForRecAtHit() const {return fHitForRecAtHit;}
        /// reset array of hitForRec at hit
-  void                       ResetHitForRecAtHit(void) { fHitForRecAtHit->Delete(); }
+  void                       ResetHitForRecAtHit() { fHitForRecAtHit->Delete(); }
   void                       AddHitForRecAtHit(const AliMUONHitForRec *hitForRec); 
 
        /// return the number of hits attached to the track
-  Int_t                      GetNTrackHits(void) const {return fNTrackHits;}
+  Int_t                      GetNTrackHits() const {return fNTrackHits;}
        /// set the number of hits attached to the track
   void                       SetNTrackHits(Int_t nTrackHits) {fNTrackHits = nTrackHits;}
 
-       /// return pointeur to track parameters extrapolated to the next station
-  AliMUONTrackParam*         GetExtrapTrackParam(void) {return &fExtrapTrackParam;}
-       /// set track parameters extrapolated to next station
-  void                       SetExtrapTrackParam(AliMUONTrackParam* trackParam) {fExtrapTrackParam = *trackParam;}
-
        /// return kTrue if the vertex must be used to constrain the fit, kFalse if not
-  Bool_t                     GetFitWithVertex(void) const {return fFitWithVertex;}
+  Bool_t                     GetFitWithVertex() const {return fFitWithVertex;}
        /// set the flag telling whether the vertex must be used to constrain the fit or not
   void                       SetFitWithVertex(Bool_t fitWithVertex) { fFitWithVertex = fitWithVertex; }
        /// return the vertex used during the tracking procedure
-  AliMUONHitForRec*          GetVertex(void) const {return fVertex;}
-  void                       SetVertex(AliMUONHitForRec* vertex);
+  AliMUONHitForRec*          GetVertex() const {return fVertex;}
+  void                       SetVertex(const AliMUONHitForRec* vertex);
+
+       /// return kTrue if the multiple scattering must be accounted for in the fit, kFalse if not
+  Bool_t                     GetFitWithMCS() const {return fFitWithMCS;}
+       /// set the flag telling whether the multiple scattering must be accounted for in the fit or not
+  void                       SetFitWithMCS(Bool_t fitWithMCS) {fFitWithMCS = fitWithMCS;}
+  
+  Bool_t    ComputeHitWeights(TMatrixD* mcsCovariances = 0);
+  Bool_t    ComputeLocalChi2(Bool_t accountForMCS);
+  Double_t  ComputeGlobalChi2(Bool_t accountForMCS);
 
        /// return the minimum value of the function minimized by the fit
-  Double_t                   GetFitFMin(void) const {return fFitFMin;}
+  Double_t                   GetFitFMin() const {return fGlobalChi2;}
        /// set the minimum value of the function minimized by the fit
-  void                       SetFitFMin(Double_t chi2) { fFitFMin = chi2; }
+  void                       SetFitFMin(Double_t chi2) { fGlobalChi2 = chi2;}
+  
+       /// return kTRUE if the track has been improved
+  Bool_t                     IsImproved() const {return fImproved;}
+       /// set the flag telling whether the track has been improved or not
+  void                       SetImproved(Bool_t improved) { fImproved = improved;}
+  
         /// return 1,2,3 if track matches with trigger track, 0 if not
-  Int_t                     GetMatchTrigger(void) const {return fMatchTrigger;}
+  Int_t                      GetMatchTrigger(void) const {return fMatchTrigger;}
   /// returns the local trigger number corresponding to the trigger track 
   Int_t                      GetLoTrgNum(void) const {return floTrgNum;}
        /// set the flag telling whether track matches with trigger track or not
@@ -81,8 +94,11 @@ class AliMUONTrack : public TObject
   Double_t                   GetChi2MatchTrigger(void) const {return fChi2MatchTrigger;}
        /// set the chi2 of trigger/track matching 
   void                       SetChi2MatchTrigger(Double_t chi2MatchTrigger) {fChi2MatchTrigger = chi2MatchTrigger;}
-  
+
   Int_t                      HitsInCommon(AliMUONTrack* track) const;
+
+  Double_t                   GetNormalizedChi2() const;
+
   Bool_t*                    CompatibleTrack(AliMUONTrack* track, Double_t sigma2Cut) const; // return array of compatible chamber
   
        /// return track number in TrackRefs
@@ -113,30 +129,34 @@ class AliMUONTrack : public TObject
   /// high pt decision local trigger 
   Int_t LoHpt(void)    const  { return fLocalTrigger >> 24 & 0x03; }
 
-  Double_t                   TryOneHitForRec(AliMUONHitForRec* hitForRec);
-  Double_t                   TryTwoHitForRec(AliMUONHitForRec* hitForRec1, AliMUONHitForRec* hitForRec2); 
-  
   void                       RecursiveDump(void) const; // Recursive dump (with track hits)
 
   virtual void               Print(Option_t* opt="") const;
 
   virtual void Clear(Option_t* opt="");
 
+
  private:
-  static const Double_t fgkMaxTrackingDistanceBending;    ///< Maximum distance to the track to search for compatible hitForRec(s) in bending direction
-  static const Double_t fgkMaxTrackingDistanceNonBending; ///< Maximum distance to the track to search for compatible hitForRec(s) in non bending direction
-  
   AliMUONTrackParam fTrackParamAtVertex; //!< Track parameters at vertex
   TClonesArray *fTrackParamAtHit; ///< Track parameters at hit
   TClonesArray *fHitForRecAtHit; ///< Cluster parameters at hit
   Int_t fNTrackHits; ///< Number of hits attached to the track
   
-  AliMUONTrackParam fExtrapTrackParam; //!< Track parameters extrapolated to a given z position
-  
-  Bool_t fFitWithVertex; //!< 1 if using the vertex to constrain the fit, 0 if not
+  Bool_t fFitWithVertex; //!< kTRUE if using the vertex to constrain the fit, kFALSE if not
   AliMUONHitForRec *fVertex; //!< Vertex used during the tracking procedure if required
   
-  Double_t fFitFMin; ///< minimum value of the function minimized by the fit
+  Bool_t fFitWithMCS; //!< kTRUE if accounting for multiple scattering in the fit, kFALSE if not
+  
+  TMatrixD* fHitWeightsNonBending; //!< weights matrix, in non bending direction, of hits attached to the track
+                                  //!< (accounting for multiple scattering and hits resolution)
+  TMatrixD* fHitWeightsBending;    //!< weights matrix, in bending direction, of hits attached to the track
+                                  //!< (accounting for multiple scattering and hits resolution)
+  
+  Double_t fGlobalChi2; ///< Global chi2 of the track
+  
+  Bool_t fImproved; //!< kTRUE if the track has been improved
+  
   Int_t fMatchTrigger;  ///<  0 track does not match trigger
                         ///<  1 track match but does not pass pt cut
                         ///<  2 track match Low pt cut
@@ -149,7 +169,13 @@ class AliMUONTrack : public TObject
 
   Int_t fLocalTrigger;    ///< packed local trigger information
   
-  ClassDef(AliMUONTrack,6) // Reconstructed track in ALICE dimuon spectrometer
+  
+  // methods
+  Bool_t ComputeHitWeights(TMatrixD& hitWeightsNB, TMatrixD& hitWeightsB, TMatrixD* mcsCovariances = 0, AliMUONHitForRec* discardedHit = 0) const;
+  void   ComputeMCSCovariances(TMatrixD& mcsCovariances) const;
+  
+  
+  ClassDef(AliMUONTrack, 7) // Reconstructed track in ALICE dimuon spectrometer
 };
        
 #endif
index 2565ba14fa262594ec26c8ffb869f1df13d93e84..c0aae90b7862e9ba38bb26cd264616b8aa8fed51 100644 (file)
 
 #include "AliMagF.h" 
 
-#include <Riostream.h>
 #include <TMath.h>
 #include <TMatrixD.h>
 #include <TGeoManager.h>
 
+#include <Riostream.h>
+
 /// \cond CLASSIMP
 ClassImp(AliMUONTrackExtrap) // Class implementation in ROOT context
 /// \endcond
@@ -234,72 +235,72 @@ void AliMUONTrackExtrap::RecoverTrackParam(Double_t *v3, Double_t charge, AliMUO
 }
 
   //__________________________________________________________________________
-void AliMUONTrackExtrap::ExtrapToZCov(AliMUONTrackParam* trackParam, Double_t zEnd)
+void AliMUONTrackExtrap::ExtrapToZCov(AliMUONTrackParam* trackParam, Double_t zEnd, Bool_t updatePropagator)
 {
   /// Track parameters and their covariances extrapolated to the plane at "zEnd".
   /// On return, results from the extrapolation are updated in trackParam.
   
   if (trackParam->GetZ() == zEnd) return; // nothing to be done if same z
   
+  // No need to propagate the covariance matrix if it does not exist
+  if (!trackParam->CovariancesExist()) {
+    cout<<"W-AliMUONTrackExtrap::ExtrapToZCov: Covariance matrix does not exist"<<endl;
+    // Extrapolate track parameters to "zEnd"
+    ExtrapToZ(trackParam,zEnd);
+    return;
+  }
+  
   // Save the actual track parameters
   AliMUONTrackParam trackParamSave(*trackParam);
-  Double_t nonBendingCoor        = trackParamSave.GetNonBendingCoor();
-  Double_t nonBendingSlope       = trackParamSave.GetNonBendingSlope();
-  Double_t bendingCoor                   = trackParamSave.GetBendingCoor();
-  Double_t bendingSlope          = trackParamSave.GetBendingSlope();
-  Double_t inverseBendingMomentum = trackParamSave.GetInverseBendingMomentum();
-  Double_t zBegin                = trackParamSave.GetZ();
+  TMatrixD paramSave(trackParamSave.GetParameters());
+  Double_t zBegin = trackParamSave.GetZ();
+  
+  // Get reference to the parameter covariance matrix
+  const TMatrixD& kParamCov = trackParam->GetCovariances();
   
   // Extrapolate track parameters to "zEnd"
   ExtrapToZ(trackParam,zEnd);
-  Double_t extrapNonBendingCoor        = trackParam->GetNonBendingCoor();
-  Double_t extrapNonBendingSlope       = trackParam->GetNonBendingSlope();
-  Double_t extrapBendingCoor           = trackParam->GetBendingCoor();
-  Double_t extrapBendingSlope          = trackParam->GetBendingSlope();
-  Double_t extrapInverseBendingMomentum = trackParam->GetInverseBendingMomentum();
   
-  // Get the pointer to the parameter covariance matrix
-  if (!trackParam->CovariancesExist()) {
-    //cout<<"W-AliMUONTrackExtrap::ExtrapToZCov: track parameter covariance matrix does not exist"<<endl;
-    //cout<<"                                    -> nothing to extrapolate !!"<<endl;
-    return;
-  }
-  TMatrixD* paramCov = trackParam->GetCovariances();
+  // Get reference to the extrapolated parameters
+  const TMatrixD& extrapParam = trackParam->GetParameters();
   
   // Calculate the jacobian related to the track parameters extrapolation to "zEnd"
   TMatrixD jacob(5,5);
-  jacob = 0.;
-  Double_t dParam[5];
+  jacob.Zero();
+  TMatrixD dParam(5,1);
   for (Int_t i=0; i<5; i++) {
     // Skip jacobian calculation for parameters with no associated error
-    if ((*paramCov)(i,i) == 0.) continue;
+    if (kParamCov(i,i) == 0.) continue;
+    
     // Small variation of parameter i only
     for (Int_t j=0; j<5; j++) {
       if (j==i) {
-        dParam[j] = TMath::Sqrt((*paramCov)(i,i));
-       if (j == 4) dParam[j] *= TMath::Sign(1.,-inverseBendingMomentum); // variation always in the same direction
-      } else dParam[j] = 0.;
+        dParam(j,0) = TMath::Sqrt(kParamCov(i,i));
+       if (j == 4) dParam(j,0) *= TMath::Sign(1.,-paramSave(4,0)); // variation always in the same direction
+      } else dParam(j,0) = 0.;
     }
+    
     // Set new parameters
-    trackParamSave.SetNonBendingCoor       (nonBendingCoor         + dParam[0]);
-    trackParamSave.SetNonBendingSlope      (nonBendingSlope        + dParam[1]);
-    trackParamSave.SetBendingCoor          (bendingCoor            + dParam[2]);
-    trackParamSave.SetBendingSlope         (bendingSlope           + dParam[3]);
-    trackParamSave.SetInverseBendingMomentum(inverseBendingMomentum + dParam[4]);
-    trackParamSave.SetZ                            (zBegin);
+    trackParamSave.SetParameters(paramSave);
+    trackParamSave.AddParameters(dParam);
+    trackParamSave.SetZ(zBegin);
+    
     // Extrapolate new track parameters to "zEnd"
     ExtrapToZ(&trackParamSave,zEnd);
+    
     // Calculate the jacobian
-    jacob(0,i) = (trackParamSave.GetNonBendingCoor()        - extrapNonBendingCoor        ) / dParam[i];
-    jacob(1,i) = (trackParamSave.GetNonBendingSlope()       - extrapNonBendingSlope       ) / dParam[i];
-    jacob(2,i) = (trackParamSave.GetBendingCoor()           - extrapBendingCoor           ) / dParam[i];
-    jacob(3,i) = (trackParamSave.GetBendingSlope()          - extrapBendingSlope          ) / dParam[i];
-    jacob(4,i) = (trackParamSave.GetInverseBendingMomentum() - extrapInverseBendingMomentum) / dParam[i];
+    TMatrixD jacobji(trackParamSave.GetParameters(),TMatrixD::kMinus,extrapParam);
+    jacobji *= 1. / dParam(i,0);
+    jacob.SetSub(0,i,jacobji);
   }
   
   // Extrapolate track parameter covariances to "zEnd"
-  TMatrixD tmp((*paramCov),TMatrixD::kMultTranspose,jacob);
-  (*paramCov) = TMatrixD(jacob,TMatrixD::kMult,tmp);
+  TMatrixD tmp(kParamCov,TMatrixD::kMultTranspose,jacob);
+  TMatrixD tmp2(jacob,TMatrixD::kMult,tmp);
+  trackParam->SetCovariances(tmp2);
+  
+  // Update the propagator if required
+  if (updatePropagator) trackParam->UpdatePropagator(jacob);
   
 }
 
@@ -349,53 +350,36 @@ void AliMUONTrackExtrap::ExtrapToVertexUncorrected(AliMUONTrackParam* trackParam
     exit(-1);
   }
   
-/*
-  // Check whether the geometry is available and get absorber boundaries
-  if (!gGeoManager) {
-    cout<<"E-AliMUONTrackExtrap::ExtrapToVertexUncorrected: no TGeo"<<endl;
-    return;
-  }
-  TGeoNode *absNode = gGeoManager->GetVolume("ALIC")->GetNode("ABSM_1");
-  if (!absNode) {
-    cout<<"E-AliMUONTrackExtrap::ExtrapToVertexUncorrected: failed to get absorber node"<<endl;
-    return;
-  }
-  Double_t kZAbsBeg, kZAbsEnd;
-  absNode->GetVolume()->GetShape()->GetAxisRange(3,kZAbsBeg,kZAbsEnd);
-  const Double_t *absPos = absNode->GetMatrix()->GetTranslation();
-  kZAbsBeg = absPos[2] - kZAbsBeg; // spectro. (z<0)
-  kZAbsEnd = absPos[2] - kZAbsEnd; // spectro. (z<0)
-*/
-  static const Double_t kZAbsBeg = -90.;
-  static const Double_t kZAbsEnd = -505.;
-    
   // Check the vertex position relatively to the absorber
-  if (zVtx < kZAbsBeg && zVtx > kZAbsEnd) { // spectro. (z<0)
+  if (zVtx < AliMUONConstants::AbsZBeg() && zVtx > AliMUONConstants::AbsZEnd()) { // spectro. (z<0)
     cout<<"W-AliMUONTrackExtrap::ExtrapToVertex: Ending Z ("<<zVtx
-       <<") inside the front absorber ("<<kZAbsBeg<<","<<kZAbsEnd<<")"<<endl;
-  } else if (zVtx < kZAbsEnd ) { // spectro. (z<0)
+       <<") inside the front absorber ("<<AliMUONConstants::AbsZBeg()<<","<<AliMUONConstants::AbsZEnd()<<")"<<endl;
+  } else if (zVtx < AliMUONConstants::AbsZEnd() ) { // spectro. (z<0)
     cout<<"W-AliMUONTrackExtrap::ExtrapToVertex: Ending Z ("<<zVtx
-       <<") downstream the front absorber (zAbsorberEnd = "<<kZAbsEnd<<")"<<endl;
-    ExtrapToZCov(trackParam,zVtx);
+       <<") downstream the front absorber (zAbsorberEnd = "<<AliMUONConstants::AbsZEnd()<<")"<<endl;
+    if (trackParam->CovariancesExist()) ExtrapToZCov(trackParam,zVtx);
+    else ExtrapToZ(trackParam,zVtx);
     return;
   }
   
   // Check the track position relatively to the absorber and extrapolate track parameters to the end of the absorber if needed
-  if (trackParam->GetZ() > kZAbsBeg) { // spectro. (z<0)
+  if (trackParam->GetZ() > AliMUONConstants::AbsZBeg()) { // spectro. (z<0)
     cout<<"W-AliMUONTrackExtrap::ExtrapToVertex: Starting Z ("<<trackParam->GetZ()
-       <<") upstream the front absorber (zAbsorberBegin = "<<kZAbsBeg<<")"<<endl;
-    ExtrapToZCov(trackParam,zVtx);
+       <<") upstream the front absorber (zAbsorberBegin = "<<AliMUONConstants::AbsZBeg()<<")"<<endl;
+    if (trackParam->CovariancesExist()) ExtrapToZCov(trackParam,zVtx);
+    else ExtrapToZ(trackParam,zVtx);
     return;
-  } else if (trackParam->GetZ() > kZAbsEnd) { // spectro. (z<0)
+  } else if (trackParam->GetZ() > AliMUONConstants::AbsZEnd()) { // spectro. (z<0)
     cout<<"W-AliMUONTrackExtrap::ExtrapToVertex: Starting Z ("<<trackParam->GetZ()
-       <<") inside the front absorber ("<<kZAbsBeg<<","<<kZAbsEnd<<")"<<endl;
+       <<") inside the front absorber ("<<AliMUONConstants::AbsZBeg()<<","<<AliMUONConstants::AbsZEnd()<<")"<<endl;
   } else {
-    ExtrapToZCov(trackParam,kZAbsEnd);
+    if (trackParam->CovariancesExist()) ExtrapToZCov(trackParam,AliMUONConstants::AbsZEnd());
+    else ExtrapToZ(trackParam,AliMUONConstants::AbsZEnd());
   }
   
   // Then add MCS effect in absorber to the parameters covariances
   AliMUONTrackParam trackParamIn(*trackParam);
-  ExtrapToZ(&trackParamIn, TMath::Min(zVtx, kZAbsBeg));
+  ExtrapToZ(&trackParamIn, TMath::Min(zVtx, AliMUONConstants::AbsZBeg()));
   Double_t trackXYZIn[3];
   trackXYZIn[0] = trackParamIn.GetNonBendingCoor();
   trackXYZIn[1] = trackParamIn.GetBendingCoor();
@@ -433,13 +417,16 @@ void AliMUONTrackExtrap::AddMCSEffectInAbsorber(AliMUONTrackParam* param, Double
   Double_t covCorrSlope = alpha2 * (pathLength * f0 - f1);
   Double_t varSlop = alpha2 * f0;
   
-  TMatrixD* paramCov = param->GetCovariances();
+  TMatrixD newParamCov(param->GetCovariances());
   // Non bending plane
-  (*paramCov)(0,0) += varCoor;         (*paramCov)(0,1) += covCorrSlope;
-  (*paramCov)(1,0) += covCorrSlope;    (*paramCov)(1,1) += varSlop;
+  newParamCov(0,0) += varCoor;       newParamCov(0,1) += covCorrSlope;
+  newParamCov(1,0) += covCorrSlope;  newParamCov(1,1) += varSlop;
   // Bending plane
-  (*paramCov)(2,2) += varCoor;         (*paramCov)(2,3) += covCorrSlope;
-  (*paramCov)(3,2) += covCorrSlope;    (*paramCov)(3,3) += varSlop;
+  newParamCov(2,2) += varCoor;       newParamCov(2,3) += covCorrSlope;
+  newParamCov(3,2) += covCorrSlope;  newParamCov(3,3) += varSlop;
+  
+  // Set new covariances
+  param->SetCovariances(newParamCov);
   
 }
 
@@ -539,6 +526,28 @@ void AliMUONTrackExtrap::GetAbsorberCorrectionParam(Double_t trackXYZIn[3], Doub
   meanRho /= pathLength;
 }
 
+  //__________________________________________________________________________
+Double_t AliMUONTrackExtrap::GetMCSAngle2(const AliMUONTrackParam& param, Double_t dZ, Double_t x0)
+{
+  /// Return the angular dispersion square due to multiple Coulomb scattering
+  /// through a material of thickness "dZ" and of radiation length "x0"
+  /// assuming linear propagation and using the small angle approximation.
+  
+  Double_t bendingSlope = param.GetBendingSlope();
+  Double_t nonBendingSlope = param.GetNonBendingSlope();
+  Double_t inverseTotalMomentum2 = param.GetInverseBendingMomentum() * param.GetInverseBendingMomentum() *
+                                  (1.0 + bendingSlope * bendingSlope) /
+                                  (1.0 + bendingSlope *bendingSlope + nonBendingSlope * nonBendingSlope); 
+  // Path length in the material
+  Double_t pathLength = TMath::Abs(dZ) * TMath::Sqrt(1.0 + bendingSlope*bendingSlope + nonBendingSlope*nonBendingSlope);
+  // relativistic velocity
+  Double_t velo = 1.;
+  // Angular dispersion square of the track (variance) in a plane perpendicular to the trajectory
+  Double_t theta02 = 0.0136 / velo * (1 + 0.038 * TMath::Log(pathLength/x0));
+  
+  return theta02 * theta02 * inverseTotalMomentum2 * pathLength / x0;
+}
+
   //__________________________________________________________________________
 void AliMUONTrackExtrap::AddMCSEffect(AliMUONTrackParam *param, Double_t dZ, Double_t x0)
 {
@@ -560,18 +569,21 @@ void AliMUONTrackExtrap::AddMCSEffect(AliMUONTrackParam *param, Double_t dZ, Dou
   Double_t theta02 = 0.0136 / velo * (1 + 0.038 * TMath::Log(pathLength/x0));
   theta02 *= theta02 * inverseTotalMomentum2 * pathLength / x0;
   
-  // Add effects of multiple Coulomb scattering in track parameter covariances
-  TMatrixD* paramCov = param->GetCovariances();
   Double_t varCoor     = pathLength2 * theta02 / 3.;
   Double_t varSlop     = theta02;
   Double_t covCorrSlope = pathLength * theta02 / 2.;
+  
+  // Add effects of multiple Coulomb scattering in track parameter covariances
+  TMatrixD newParamCov(param->GetCovariances());
   // Non bending plane
-  (*paramCov)(0,0) += varCoor;         (*paramCov)(0,1) += covCorrSlope;
-  (*paramCov)(1,0) += covCorrSlope;    (*paramCov)(1,1) += varSlop;
+  newParamCov(0,0) += varCoor;       newParamCov(0,1) += covCorrSlope;
+  newParamCov(1,0) += covCorrSlope;  newParamCov(1,1) += varSlop;
   // Bending plane
-  (*paramCov)(2,2) += varCoor;         (*paramCov)(2,3) += covCorrSlope;
-  (*paramCov)(3,2) += covCorrSlope;    (*paramCov)(3,3) += varSlop;
+  newParamCov(2,2) += varCoor;       newParamCov(2,3) += covCorrSlope;
+  newParamCov(3,2) += covCorrSlope;  newParamCov(3,3) += varSlop;
   
+  // Set new covariances
+  param->SetCovariances(newParamCov);
 }
 
   //__________________________________________________________________________
@@ -596,48 +608,28 @@ void AliMUONTrackExtrap::ExtrapToVertex(AliMUONTrackParam* trackParam, Double_t
     return;
   }
   
-/*
-  // Check whether the geometry is available and get absorber boundaries
-  if (!gGeoManager) {
-    cout<<"E-AliMUONTrackExtrap::ExtrapToVertex: no TGeo"<<endl;
-    return;
-  }
-  TGeoNode *absNode = gGeoManager->GetVolume("ALIC")->GetNode("ABSM_1");
-  if (!absNode) {
-    cout<<"E-AliMUONTrackExtrap::ExtrapToVertex: failed to get absorber node"<<endl;
-    return;
-  }
-  Double_t kZAbsBeg, kZAbsEnd;
-  absNode->GetVolume()->GetShape()->GetAxisRange(3,kZAbsBeg,kZAbsEnd);
-  const Double_t *absPos = absNode->GetMatrix()->GetTranslation();
-  kZAbsBeg = absPos[2] - kZAbsBeg; // spectro. (z<0)
-  kZAbsEnd = absPos[2] - kZAbsEnd; // spectro. (z<0)
-*/
-  static const Double_t kZAbsBeg = -90.;
-  static const Double_t kZAbsEnd = -505.;
-  
   // Check the vertex position relatively to the absorber
-  if (zVtx < kZAbsBeg && zVtx > kZAbsEnd) { // spectro. (z<0)
+  if (zVtx < AliMUONConstants::AbsZBeg() && zVtx > AliMUONConstants::AbsZEnd()) { // spectro. (z<0)
     cout<<"W-AliMUONTrackExtrap::ExtrapToVertex: Ending Z ("<<zVtx
-       <<") inside the front absorber ("<<kZAbsBeg<<","<<kZAbsEnd<<")"<<endl;
-  } else if (zVtx < kZAbsEnd ) { // spectro. (z<0)
+       <<") inside the front absorber ("<<AliMUONConstants::AbsZBeg()<<","<<AliMUONConstants::AbsZEnd()<<")"<<endl;
+  } else if (zVtx < AliMUONConstants::AbsZEnd() ) { // spectro. (z<0)
     cout<<"W-AliMUONTrackExtrap::ExtrapToVertex: Ending Z ("<<zVtx
-       <<") downstream the front absorber (zAbsorberEnd = "<<kZAbsEnd<<")"<<endl;
+       <<") downstream the front absorber (zAbsorberEnd = "<<AliMUONConstants::AbsZEnd()<<")"<<endl;
     ExtrapToZ(trackParam,zVtx);
     return;
   }
   
   // Check the track position relatively to the absorber and extrapolate track parameters to the end of the absorber if needed
-  if (trackParam->GetZ() > kZAbsBeg) { // spectro. (z<0)
+  if (trackParam->GetZ() > AliMUONConstants::AbsZBeg()) { // spectro. (z<0)
     cout<<"W-AliMUONTrackExtrap::ExtrapToVertex: Starting Z ("<<trackParam->GetZ()
-       <<") upstream the front absorber (zAbsorberBegin = "<<kZAbsBeg<<")"<<endl;
+       <<") upstream the front absorber (zAbsorberBegin = "<<AliMUONConstants::AbsZBeg()<<")"<<endl;
     ExtrapToZ(trackParam,zVtx);
     return;
-  } else if (trackParam->GetZ() > kZAbsEnd) { // spectro. (z<0)
+  } else if (trackParam->GetZ() > AliMUONConstants::AbsZEnd()) { // spectro. (z<0)
     cout<<"W-AliMUONTrackExtrap::ExtrapToVertex: Starting Z ("<<trackParam->GetZ()
-       <<") inside the front absorber ("<<kZAbsBeg<<","<<kZAbsEnd<<")"<<endl;
+       <<") inside the front absorber ("<<AliMUONConstants::AbsZBeg()<<","<<AliMUONConstants::AbsZEnd()<<")"<<endl;
   } else {
-    ExtrapToZ(trackParam,kZAbsEnd);
+    ExtrapToZ(trackParam,AliMUONConstants::AbsZEnd());
   }
   
   // Get absorber correction parameters assuming linear propagation from vertex to the track position
@@ -646,7 +638,7 @@ void AliMUONTrackExtrap::ExtrapToVertex(AliMUONTrackParam* trackParam, Double_t
   trackXYZOut[1] = trackParam->GetBendingCoor();
   trackXYZOut[2] = trackParam->GetZ();
   Double_t trackXYZIn[3];
-  trackXYZIn[2] = TMath::Min(zVtx, kZAbsBeg); // spectro. (z<0)
+  trackXYZIn[2] = TMath::Min(zVtx, AliMUONConstants::AbsZBeg()); // spectro. (z<0)
   trackXYZIn[0] = trackXYZOut[0] + (xVtx - trackXYZOut[0]) / (zVtx - trackXYZOut[2]) * (trackXYZIn[2] - trackXYZOut[2]);
   trackXYZIn[1] = trackXYZOut[1] + (yVtx - trackXYZOut[1]) / (zVtx - trackXYZOut[2]) * (trackXYZIn[2] - trackXYZOut[2]);
   Double_t pathLength = 0.;
index 0aa630d756fa5025abdf47ba102c36a2ec4f0a62..e3312f6b20ef9de89af6150fc881280f95e4df43 100644 (file)
@@ -34,7 +34,7 @@ class AliMUONTrackExtrap : public TObject
   static Double_t GetBendingMomentumFromImpactParam(Double_t impactParam);
   
   static void ExtrapToZ(AliMUONTrackParam *trackParam, Double_t Z);
-  static void ExtrapToZCov(AliMUONTrackParam* trackParam, Double_t zEnd);
+  static void ExtrapToZCov(AliMUONTrackParam* trackParam, Double_t zEnd, Bool_t updatePropagator = kFALSE);
   static void ExtrapToStation(AliMUONTrackParam *trackParamIn, Int_t station, AliMUONTrackParam *trackParamOut);
   static void ExtrapToVertexUncorrected(AliMUONTrackParam* trackParam, Double_t zVtx);
   static void ExtrapToVertex(AliMUONTrackParam *trackParam, Double_t xVtx, Double_t yVtx, Double_t zVtx,
@@ -42,7 +42,8 @@ class AliMUONTrackExtrap : public TObject
   
   static Double_t TotalMomentumEnergyLoss(AliMUONTrackParam* trackParam, Double_t xVtx, Double_t yVtx, Double_t zVtx);
   
-  static void AddMCSEffect(AliMUONTrackParam *param, Double_t dZ, Double_t x0);
+  static Double_t GetMCSAngle2(const AliMUONTrackParam& param, Double_t dZ, Double_t x0);
+  static void     AddMCSEffect(AliMUONTrackParam *param, Double_t dZ, Double_t x0);
   
   static void ExtrapOneStepRungekutta(Double_t charge, Double_t step, Double_t* vect, Double_t* vout);
   
index f09bddc59f6af74ee8ba1fc63ebff94bae305610..31fe6dd199e137a48fe43d6b10824fc9fbf25664 100644 (file)
@@ -13,6 +13,9 @@
  * provided "as is" without express or implied warranty.                  *
  **************************************************************************/
 
+/* $Id$ */
+
+
 ////////////////////////////////////
 ///
 /// \class AliMUONTrackHitPattern
@@ -39,7 +42,6 @@
 
 #include "AliMUONTrackHitPattern.h"
 
-#include "AliLog.h"
 #include "AliMUONConstants.h"
 #include "AliMUONVDigit.h"
 #include "AliMUONDigitMaker.h"
 #include "AliMUONTrackParam.h"
 #include "AliMUONVTrackStore.h"
 #include "AliMUONVTriggerStore.h"
-#include "AliMagF.h"
 #include "AliMpPad.h"
 #include "AliMpSegmentation.h"
 #include "AliMpVSegmentation.h"
+
+#include "AliMagF.h"
+#include "AliLog.h"
 #include "AliTracker.h"
+
 #include <Riostream.h>
 #include <TArrayS.h>
 #include <TClonesArray.h>
@@ -228,10 +233,10 @@ AliMUONTrackHitPattern::GetPosUncertainty(const AliMUONTrackParam& trackParam,
     Float_t zDistFromWall = TMath::Abs(zChamber - kZBranson);
     Float_t zDistFromLastTrackCh = TMath::Abs(zChamber - AliMUONConstants::DefaultChamberZ(9));
 
-    TMatrixD *covParam = trackParam.GetCovariances();
+    const TMatrixD& kCovParam = trackParam.GetCovariances();
     
-    sigmaX = (*covParam)(0,0);
-    sigmaY = (*covParam)(2,2);
+    sigmaX = kCovParam(0,0);
+    sigmaY = kCovParam(2,2);
 
     // If covariance matrix is not extrapolated, use "reasonable" errors
     // (To be removed as soon as covariance matrix is correctly propagated).
index 9ab7c17e62cb80aa55291c11e5e76762b9fc1938..9b0d21e616cd8c89112266376897c5201154b4a2 100644 (file)
@@ -3,6 +3,8 @@
 /* Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
  * See cxx source for full Copyright notice                               */
 
+/*$Id$*/
+
 /// \ingroup rec
 /// \class AliMUONTrackHitPattern
 /// \brief Class for the MUON track hit pattern
index 9507634b1c276e3b0fcfcfb3bbf22990b7172334..7cea71b7b5a2a12d81b2b0e156cc84f39d9a55c5 100644 (file)
@@ -31,9 +31,9 @@
 #include "AliESDMuonTrack.h"
 #include "AliLog.h"
 
-#include <Riostream.h>
 #include <TMath.h>
-#include <TMatrixD.h>
+
+#include <Riostream.h>
 
 /// \cond CLASSIMP
 ClassImp(AliMUONTrackParam) // Class implementation in ROOT context
@@ -42,14 +42,18 @@ ClassImp(AliMUONTrackParam) // Class implementation in ROOT context
   //_________________________________________________________________________
 AliMUONTrackParam::AliMUONTrackParam()
   : TObject(),
-    fNonBendingCoor(0.),
-    fNonBendingSlope(0.),
-    fBendingCoor(0.),
-    fBendingSlope(0.),
-    fInverseBendingMomentum(0.),
     fZ(0.),
+    fParameters(5,1),
     fCovariances(0x0),
-    fHitForRecPtr(0x0)
+    fPropagator(0x0),
+    fExtrapParameters(0x0),
+    fExtrapCovariances(0x0),
+    fSmoothParameters(0x0),
+    fSmoothCovariances(0x0),
+    fHitForRecPtr(0x0),
+    fRemovable(kFALSE),
+    fTrackChi2(0.),
+    fLocalChi2(0.)
 {
   /// Constructor
 }
@@ -57,17 +61,26 @@ AliMUONTrackParam::AliMUONTrackParam()
   //_________________________________________________________________________
 AliMUONTrackParam::AliMUONTrackParam(const AliMUONTrackParam& theMUONTrackParam)
   : TObject(theMUONTrackParam),
-    fNonBendingCoor(theMUONTrackParam.fNonBendingCoor),
-    fNonBendingSlope(theMUONTrackParam.fNonBendingSlope),
-    fBendingCoor(theMUONTrackParam.fBendingCoor),
-    fBendingSlope(theMUONTrackParam.fBendingSlope),
-    fInverseBendingMomentum(theMUONTrackParam.fInverseBendingMomentum), 
     fZ(theMUONTrackParam.fZ),
+    fParameters(theMUONTrackParam.fParameters),
     fCovariances(0x0),
-    fHitForRecPtr(theMUONTrackParam.fHitForRecPtr)
+    fPropagator(0x0),
+    fExtrapParameters(0x0),
+    fExtrapCovariances(0x0),
+    fSmoothParameters(0x0),
+    fSmoothCovariances(0x0),
+    fHitForRecPtr(theMUONTrackParam.fHitForRecPtr),
+    fRemovable(theMUONTrackParam.fRemovable),
+    fTrackChi2(theMUONTrackParam.fTrackChi2),
+    fLocalChi2(theMUONTrackParam.fLocalChi2)
 {
   /// Copy constructor
   if (theMUONTrackParam.fCovariances) fCovariances = new TMatrixD(*(theMUONTrackParam.fCovariances));
+  if (theMUONTrackParam.fPropagator) fPropagator = new TMatrixD(*(theMUONTrackParam.fPropagator));
+  if (theMUONTrackParam.fExtrapParameters) fExtrapParameters = new TMatrixD(*(theMUONTrackParam.fExtrapParameters));
+  if (theMUONTrackParam.fExtrapCovariances) fExtrapCovariances = new TMatrixD(*(theMUONTrackParam.fExtrapCovariances));
+  if (theMUONTrackParam.fSmoothParameters) fSmoothParameters = new TMatrixD(*(theMUONTrackParam.fSmoothParameters));
+  if (theMUONTrackParam.fSmoothCovariances) fSmoothCovariances = new TMatrixD(*(theMUONTrackParam.fSmoothCovariances));
 }
 
   //_________________________________________________________________________
@@ -80,12 +93,9 @@ AliMUONTrackParam& AliMUONTrackParam::operator=(const AliMUONTrackParam& theMUON
   // base class assignement
   TObject::operator=(theMUONTrackParam);
 
-  fNonBendingCoor              =  theMUONTrackParam.fNonBendingCoor;
-  fNonBendingSlope             =  theMUONTrackParam.fNonBendingSlope; 
-  fBendingCoor                 =  theMUONTrackParam.fBendingCoor; 
-  fBendingSlope                =  theMUONTrackParam.fBendingSlope; 
-  fInverseBendingMomentum      =  theMUONTrackParam.fInverseBendingMomentum; 
-  fZ                           =  theMUONTrackParam.fZ; 
+  fZ = theMUONTrackParam.fZ; 
+  
+  fParameters = theMUONTrackParam.fParameters;
   
   if (theMUONTrackParam.fCovariances) {
     if (fCovariances) *fCovariances = *(theMUONTrackParam.fCovariances);
@@ -95,6 +105,53 @@ AliMUONTrackParam& AliMUONTrackParam::operator=(const AliMUONTrackParam& theMUON
     fCovariances = 0x0;
   }
   
+  if (theMUONTrackParam.fPropagator) {
+    if (fPropagator) *fPropagator = *(theMUONTrackParam.fPropagator);
+    else fPropagator = new TMatrixD(*(theMUONTrackParam.fPropagator));
+  } else if (fPropagator) {
+    delete fPropagator;
+    fPropagator = 0x0;
+  }
+  
+  if (theMUONTrackParam.fExtrapParameters) {
+    if (fExtrapParameters) *fExtrapParameters = *(theMUONTrackParam.fExtrapParameters);
+    else fExtrapParameters = new TMatrixD(*(theMUONTrackParam.fExtrapParameters));
+  } else if (fExtrapParameters) {
+    delete fExtrapParameters;
+    fExtrapParameters = 0x0;
+  }
+  
+  if (theMUONTrackParam.fExtrapCovariances) {
+    if (fExtrapCovariances) *fExtrapCovariances = *(theMUONTrackParam.fExtrapCovariances);
+    else fExtrapCovariances = new TMatrixD(*(theMUONTrackParam.fExtrapCovariances));
+  } else if (fExtrapCovariances) {
+    delete fExtrapCovariances;
+    fExtrapCovariances = 0x0;
+  }
+  
+  if (theMUONTrackParam.fSmoothParameters) {
+    if (fSmoothParameters) *fSmoothParameters = *(theMUONTrackParam.fSmoothParameters);
+    else fSmoothParameters = new TMatrixD(*(theMUONTrackParam.fSmoothParameters));
+  } else if (fSmoothParameters) {
+    delete fSmoothParameters;
+    fSmoothParameters = 0x0;
+  }
+  
+  if (theMUONTrackParam.fSmoothCovariances) {
+    if (fSmoothCovariances) *fSmoothCovariances = *(theMUONTrackParam.fSmoothCovariances);
+    else fSmoothCovariances = new TMatrixD(*(theMUONTrackParam.fSmoothCovariances));
+  } else if (fSmoothCovariances) {
+    delete fSmoothCovariances;
+    fSmoothCovariances = 0x0;
+  }
+  
+  fHitForRecPtr = theMUONTrackParam.fHitForRecPtr;
+  
+  fRemovable = theMUONTrackParam.fRemovable;
+  
+  fTrackChi2 = theMUONTrackParam.fTrackChi2;
+  fLocalChi2 = theMUONTrackParam.fLocalChi2;
+  
   return *this;
 }
 
@@ -103,18 +160,24 @@ AliMUONTrackParam::~AliMUONTrackParam()
 {
 /// Destructor
   DeleteCovariances();
+  delete fPropagator;
+  delete fExtrapParameters;
+  delete fExtrapCovariances;
+  delete fSmoothParameters;
+  delete fSmoothCovariances;
 }
 
   //__________________________________________________________________________
-void AliMUONTrackParam::SetTrackParam(AliMUONTrackParam& theMUONTrackParam)
-{
-  /// Set track parameters from "TrackParam" leaving pointer to fHitForRecPtr and parameter covariances unchanged
-  fNonBendingCoor              =  theMUONTrackParam.fNonBendingCoor;
-  fNonBendingSlope             =  theMUONTrackParam.fNonBendingSlope; 
-  fBendingCoor                 =  theMUONTrackParam.fBendingCoor; 
-  fBendingSlope                =  theMUONTrackParam.fBendingSlope; 
-  fInverseBendingMomentum      =  theMUONTrackParam.fInverseBendingMomentum; 
-  fZ                           =  theMUONTrackParam.fZ; 
+void
+AliMUONTrackParam::Clear(Option_t* /*opt*/)
+{
+  /// Delete the covariance matrix
+  DeleteCovariances();
+  delete fPropagator; fPropagator = 0x0;
+  delete fExtrapParameters; fExtrapParameters = 0x0;
+  delete fExtrapCovariances; fExtrapCovariances = 0x0;
+  delete fSmoothParameters; fSmoothParameters = 0x0;
+  delete fSmoothCovariances; fSmoothCovariances = 0x0;
 }
 
   //__________________________________________________________________________
@@ -130,48 +193,48 @@ AliMUONHitForRec* AliMUONTrackParam::GetHitForRecPtr(void) const
 void AliMUONTrackParam::GetParamFrom(const AliESDMuonTrack& esdMuonTrack)
 {
   /// assigned value form ESD track.
-  fInverseBendingMomentum      =  esdMuonTrack.GetInverseBendingMomentum();
-  fBendingSlope                =  TMath::Tan(esdMuonTrack.GetThetaY());
-  fNonBendingSlope             =  TMath::Tan(esdMuonTrack.GetThetaX());
-  fZ                           =  esdMuonTrack.GetZ(); 
-  fBendingCoor                 =  esdMuonTrack.GetBendingCoor(); 
-  fNonBendingCoor              =  esdMuonTrack.GetNonBendingCoor();
+  fZ = esdMuonTrack.GetZ(); 
+  fParameters(0,0) = esdMuonTrack.GetNonBendingCoor();
+  fParameters(1,0) = TMath::Tan(esdMuonTrack.GetThetaX());
+  fParameters(2,0) = esdMuonTrack.GetBendingCoor(); 
+  fParameters(3,0) = TMath::Tan(esdMuonTrack.GetThetaY());
+  fParameters(4,0) = esdMuonTrack.GetInverseBendingMomentum();
 }
 
   //_________________________________________________________________________
-void AliMUONTrackParam::SetParamFor(AliESDMuonTrack& esdMuonTrack)
+void AliMUONTrackParam::SetParamFor(AliESDMuonTrack& esdMuonTrack) const
 {
   /// assigned value form ESD track.
-  esdMuonTrack.SetInverseBendingMomentum(fInverseBendingMomentum);
-  esdMuonTrack.SetThetaX(TMath::ATan(fNonBendingSlope));
-  esdMuonTrack.SetThetaY(TMath::ATan(fBendingSlope));
-  esdMuonTrack.SetZ(fZ); 
-  esdMuonTrack.SetBendingCoor(fBendingCoor); 
-  esdMuonTrack.SetNonBendingCoor(fNonBendingCoor);
+  esdMuonTrack.SetZ(fZ);
+  esdMuonTrack.SetNonBendingCoor(fParameters(0,0));
+  esdMuonTrack.SetThetaX(TMath::ATan(fParameters(1,0)));
+  esdMuonTrack.SetBendingCoor(fParameters(2,0)); 
+  esdMuonTrack.SetThetaY(TMath::ATan(fParameters(3,0)));
+  esdMuonTrack.SetInverseBendingMomentum(fParameters(4,0));
 }
 
   //_________________________________________________________________________
 void AliMUONTrackParam::GetParamFromUncorrected(const AliESDMuonTrack& esdMuonTrack)
 {
   /// assigned value form ESD track.
-  fInverseBendingMomentum      =  esdMuonTrack.GetInverseBendingMomentumUncorrected();
-  fBendingSlope                =  TMath::Tan(esdMuonTrack.GetThetaYUncorrected());
-  fNonBendingSlope             =  TMath::Tan(esdMuonTrack.GetThetaXUncorrected());
-  fZ                           =  esdMuonTrack.GetZUncorrected(); 
-  fBendingCoor                 =  esdMuonTrack.GetBendingCoorUncorrected(); 
-  fNonBendingCoor              =  esdMuonTrack.GetNonBendingCoorUncorrected();
+  fZ = esdMuonTrack.GetZUncorrected(); 
+  fParameters(0,0) = esdMuonTrack.GetNonBendingCoorUncorrected();
+  fParameters(1,0) = TMath::Tan(esdMuonTrack.GetThetaXUncorrected());
+  fParameters(2,0) = esdMuonTrack.GetBendingCoorUncorrected(); 
+  fParameters(3,0) = TMath::Tan(esdMuonTrack.GetThetaYUncorrected());
+  fParameters(4,0) = esdMuonTrack.GetInverseBendingMomentumUncorrected();
 }
 
   //_________________________________________________________________________
-void AliMUONTrackParam::SetParamForUncorrected(AliESDMuonTrack& esdMuonTrack)
+void AliMUONTrackParam::SetParamForUncorrected(AliESDMuonTrack& esdMuonTrack) const
 {
   /// assigned value form ESD track.
-  esdMuonTrack.SetInverseBendingMomentumUncorrected(fInverseBendingMomentum);
-  esdMuonTrack.SetThetaXUncorrected(TMath::ATan(fNonBendingSlope));
-  esdMuonTrack.SetThetaYUncorrected(TMath::ATan(fBendingSlope));
-  esdMuonTrack.SetZUncorrected(fZ); 
-  esdMuonTrack.SetBendingCoorUncorrected(fBendingCoor); 
-  esdMuonTrack.SetNonBendingCoorUncorrected(fNonBendingCoor);
+  esdMuonTrack.SetZUncorrected(fZ);
+  esdMuonTrack.SetNonBendingCoorUncorrected(fParameters(0,0));
+  esdMuonTrack.SetThetaXUncorrected(TMath::ATan(fParameters(1,0)));
+  esdMuonTrack.SetBendingCoorUncorrected(fParameters(2,0)); 
+  esdMuonTrack.SetThetaYUncorrected(TMath::ATan(fParameters(3,0)));
+  esdMuonTrack.SetInverseBendingMomentumUncorrected(fParameters(4,0));
 }
 
   //__________________________________________________________________________
@@ -180,10 +243,10 @@ Double_t AliMUONTrackParam::Px() const
   /// return p_x from track parameters
   Double_t pYZ, pZ, pX;
   pYZ = 0;
-  if (  TMath::Abs(fInverseBendingMomentum) > 0 )
-    pYZ = TMath::Abs(1.0 / fInverseBendingMomentum);
-  pZ = -pYZ / (TMath::Sqrt(1.0 + fBendingSlope * fBendingSlope));  // spectro. (z<0)
-  pX = pZ * fNonBendingSlope
+  if (  TMath::Abs(fParameters(4,0)) > 0 )
+    pYZ = TMath::Abs(1.0 / fParameters(4,0));
+  pZ = -pYZ / (TMath::Sqrt(1.0 + fParameters(3,0) * fParameters(3,0)));  // spectro. (z<0)
+  pX = pZ * fParameters(1,0)
   return pX;
 }
 
@@ -193,10 +256,10 @@ Double_t AliMUONTrackParam::Py() const
   /// return p_y from track parameters
   Double_t pYZ, pZ, pY;
   pYZ = 0;
-  if (  TMath::Abs(fInverseBendingMomentum) > 0 )
-    pYZ = TMath::Abs(1.0 / fInverseBendingMomentum);
-  pZ = -pYZ / (TMath::Sqrt(1.0 + fBendingSlope * fBendingSlope));  // spectro. (z<0)
-  pY = pZ * fBendingSlope
+  if (  TMath::Abs(fParameters(4,0)) > 0 )
+    pYZ = TMath::Abs(1.0 / fParameters(4,0));
+  pZ = -pYZ / (TMath::Sqrt(1.0 + fParameters(3,0) * fParameters(3,0)));  // spectro. (z<0)
+  pY = pZ * fParameters(3,0)
   return pY;
 }
 
@@ -206,9 +269,9 @@ Double_t AliMUONTrackParam::Pz() const
   /// return p_z from track parameters
   Double_t pYZ, pZ;
   pYZ = 0;
-  if (  TMath::Abs(fInverseBendingMomentum) > 0 )
-    pYZ = TMath::Abs(1.0 / fInverseBendingMomentum);
-  pZ = -pYZ / (TMath::Sqrt(1.0 + fBendingSlope * fBendingSlope));  // spectro. (z<0)
+  if (  TMath::Abs(fParameters(4,0)) > 0 )
+    pYZ = TMath::Abs(1.0 / fParameters(4,0));
+  pZ = -pYZ / (TMath::Sqrt(1.0 + fParameters(3,0) * fParameters(3,0)));  // spectro. (z<0)
   return pZ;
 }
 
@@ -218,37 +281,37 @@ Double_t AliMUONTrackParam::P() const
   /// return p from track parameters
   Double_t  pYZ, pZ, p;
   pYZ = 0;
-  if (  TMath::Abs(fInverseBendingMomentum) > 0 )
-    pYZ = TMath::Abs(1.0 / fInverseBendingMomentum);
-  pZ = -pYZ / (TMath::Sqrt(1.0 + fBendingSlope * fBendingSlope));  // spectro. (z<0)
+  if (  TMath::Abs(fParameters(4,0)) > 0 )
+    pYZ = TMath::Abs(1.0 / fParameters(4,0));
+  pZ = -pYZ / (TMath::Sqrt(1.0 + fParameters(3,0) * fParameters(3,0)));  // spectro. (z<0)
   p = TMath::Abs(pZ) * 
-    TMath::Sqrt(1.0 + fBendingSlope * fBendingSlope + fNonBendingSlope * fNonBendingSlope);
+    TMath::Sqrt(1.0 + fParameters(3,0) * fParameters(3,0) + fParameters(1,0) * fParameters(1,0));
   return p;
   
 }
 
   //__________________________________________________________________________
-TMatrixD* AliMUONTrackParam::GetCovariances() const
+const TMatrixD& AliMUONTrackParam::GetCovariances() const
 {
   /// Return the covariance matrix (create it before if needed)
   if (!fCovariances) {
     fCovariances = new TMatrixD(5,5);
-    (*fCovariances) = 0;
-  }
-  return fCovariances;
+    fCovariances->Zero();
   }
+  return *fCovariances;
+}
 
   //__________________________________________________________________________
-void AliMUONTrackParam::SetCovariances(TMatrixD* covariances)
+void AliMUONTrackParam::SetCovariances(const TMatrixD& covariances)
 {
   /// Set the covariance matrix
-  if (covariances == fCovariances) return; // nothing to be done
-  if (fCovariances) *fCovariances = *covariances;
-  else fCovariances = new TMatrixD(*covariances);
+  if (&covariances == fCovariances) return; // nothing to be done
+  if (fCovariances) *fCovariances = covariances;
+  else fCovariances = new TMatrixD(covariances);
 }
 
   //__________________________________________________________________________
-void AliMUONTrackParam::SetCovariances(Double_t matrix[5][5])
+void AliMUONTrackParam::SetCovariances(const Double_t matrix[5][5])
 {
   /// Set the covariance matrix
   if (fCovariances) fCovariances->SetMatrixArray(&(matrix[0][0]));
@@ -256,22 +319,14 @@ void AliMUONTrackParam::SetCovariances(Double_t matrix[5][5])
 }
 
   //__________________________________________________________________________
-void AliMUONTrackParam::SetVariances(Double_t matrix[5][5])
+void AliMUONTrackParam::SetVariances(const Double_t matrix[5][5])
 {
   /// Set the diagonal terms of the covariance matrix (variances)
   if (!fCovariances) fCovariances = new TMatrixD(5,5);
-  (*fCovariances) = 0;
+  fCovariances->Zero();
   for (Int_t i=0; i<5; i++) (*fCovariances)(i,i) = matrix[i][i];
 }
 
-//__________________________________________________________________________
-void
-AliMUONTrackParam::Clear(Option_t* /*opt*/)
-{
-  /// Delete the covariance matrix
-  DeleteCovariances();
-}
-
   //__________________________________________________________________________
 void AliMUONTrackParam::DeleteCovariances()
 {
@@ -281,38 +336,111 @@ void AliMUONTrackParam::DeleteCovariances()
 }
 
   //__________________________________________________________________________
-void AliMUONTrackParam::EvalCovariances(AliMUONHitForRec* hit2)
+const TMatrixD& AliMUONTrackParam::GetPropagator() const
 {
-  /// Evaluate covariances assuming the track is only a straight line
-  /// between the HitForRec attached to the current TrackParam and hit2.
-  /// Nothing can be done on fInverseBendingMomentum (-> 50% err).
-  
-  // Allocate memory if needed
-  if (!fCovariances) fCovariances = new TMatrixD(5,5);
-  
-  // Reset the covariance matrix
-  (*fCovariances) = 0;
-  
-  if (!fHitForRecPtr) {
-    AliWarning("fHitForRecPtr == NULL: cannot calculate TrackParam covariances");
-    return;
+  /// Return the propagator (create it before if needed)
+  if (!fPropagator) {
+    fPropagator = new TMatrixD(5,5);
+    fPropagator->Zero();
   }
-  
-  Double_t dz = fHitForRecPtr->GetZ() - hit2->GetZ();
-  
-  // Non bending plane
-  (*fCovariances)(0,0) = fHitForRecPtr->GetNonBendingReso2();
-  (*fCovariances)(0,1) = fHitForRecPtr->GetNonBendingReso2() / dz;
-  (*fCovariances)(1,0) = (*fCovariances)(0,1);
-  (*fCovariances)(1,1) = ( fHitForRecPtr->GetNonBendingReso2() + hit2->GetNonBendingReso2() ) / dz / dz;
-  // Bending plane
-  (*fCovariances)(2,2) = fHitForRecPtr->GetBendingReso2();
-  (*fCovariances)(2,3) = fHitForRecPtr->GetBendingReso2() / dz;
-  (*fCovariances)(3,2) = (*fCovariances)(2,3);
-  (*fCovariances)(3,3) = ( fHitForRecPtr->GetBendingReso2() + hit2->GetBendingReso2() ) / dz / dz;
-  // Inverse bending momentum
-  (*fCovariances)(4,4) = 0.5*fInverseBendingMomentum * 0.5*fInverseBendingMomentum; // error 50%
-  
+  return *fPropagator;
+  }
+
+  //__________________________________________________________________________
+void AliMUONTrackParam::ResetPropagator()
+{
+  /// Reset the propagator
+  if (!fPropagator) fPropagator = new TMatrixD(5,5);
+  fPropagator->UnitMatrix();
+}
+
+  //__________________________________________________________________________
+void AliMUONTrackParam::UpdatePropagator(const TMatrixD& propagator)
+{
+  /// Update the propagator
+  if (&propagator == fPropagator) return; // nothing to be done
+  if (fPropagator) *fPropagator = TMatrixD(propagator,TMatrixD::kMult,*fPropagator);
+  else fPropagator = new TMatrixD(propagator);
+}
+
+  //__________________________________________________________________________
+const TMatrixD& AliMUONTrackParam::GetExtrapParameters() const
+{
+  /// Return extrapolated parameters (create it before if needed)
+  if (!fExtrapParameters) {
+    fExtrapParameters = new TMatrixD(5,1);
+    fExtrapParameters->Zero();
+  }
+  return *fExtrapParameters;
+  }
+
+  //__________________________________________________________________________
+void AliMUONTrackParam::SetExtrapParameters(const TMatrixD& extrapParameters)
+{
+  /// Set extrapolated parameters
+  if (&extrapParameters == fExtrapParameters) return; // nothing to be done
+  if (fExtrapParameters) *fExtrapParameters = extrapParameters;
+  else fExtrapParameters = new TMatrixD(extrapParameters);
+}
+
+  //__________________________________________________________________________
+const TMatrixD& AliMUONTrackParam::GetExtrapCovariances() const
+{
+  /// Return the extrapolated covariance matrix (create it before if needed)
+  if (!fExtrapCovariances) {
+    fExtrapCovariances = new TMatrixD(5,5);
+    fExtrapCovariances->Zero();
+  }
+  return *fExtrapCovariances;
+  }
+
+  //__________________________________________________________________________
+void AliMUONTrackParam::SetExtrapCovariances(const TMatrixD& extrapCovariances)
+{
+  /// Set the extrapolated covariance matrix
+  if (&extrapCovariances == fExtrapCovariances) return; // nothing to be done
+  if (fExtrapCovariances) *fExtrapCovariances = extrapCovariances;
+  else fExtrapCovariances = new TMatrixD(extrapCovariances);
+}
+
+  //__________________________________________________________________________
+const TMatrixD& AliMUONTrackParam::GetSmoothParameters() const
+{
+  /// Return the smoothed parameters (create it before if needed)
+  if (!fSmoothParameters) {
+    fSmoothParameters = new TMatrixD(5,1);
+    fSmoothParameters->Zero();
+  }
+  return *fSmoothParameters;
+  }
+
+  //__________________________________________________________________________
+void AliMUONTrackParam::SetSmoothParameters(const TMatrixD& smoothParameters)
+{
+  /// Set the smoothed parameters
+  if (&smoothParameters == fSmoothParameters) return; // nothing to be done
+  if (fSmoothParameters) *fSmoothParameters = smoothParameters;
+  else fSmoothParameters = new TMatrixD(smoothParameters);
+}
+
+  //__________________________________________________________________________
+const TMatrixD& AliMUONTrackParam::GetSmoothCovariances() const
+{
+  /// Return the smoothed covariance matrix (create it before if needed)
+  if (!fSmoothCovariances) {
+    fSmoothCovariances = new TMatrixD(5,5);
+    fSmoothCovariances->Zero();
+  }
+  return *fSmoothCovariances;
+  }
+
+  //__________________________________________________________________________
+void AliMUONTrackParam::SetSmoothCovariances(const TMatrixD& smoothCovariances)
+{
+  /// Set the smoothed covariance matrix
+  if (&smoothCovariances == fSmoothCovariances) return; // nothing to be done
+  if (fSmoothCovariances) *fSmoothCovariances = smoothCovariances;
+  else fSmoothCovariances = new TMatrixD(smoothCovariances);
 }
 
   //__________________________________________________________________________
@@ -339,12 +467,12 @@ void AliMUONTrackParam::Print(Option_t* opt) const
   sopt.ToUpper();
  
   if ( sopt.Contains("FULL") ) { 
-    cout << "<AliMUONTrackParam> Bending P=" << setw(5) << setprecision(3)  << 1./GetInverseBendingMomentum() << 
-      ", NonBendSlope=" << setw(5) << setprecision(3)  << GetNonBendingSlope()*180./TMath::Pi() <<
-      ", BendSlope=" << setw(5) << setprecision(3)     << GetBendingSlope()*180./TMath::Pi()  << 
-      ", (x,y,z)_IP=(" <<  setw(5) << setprecision(3) << GetNonBendingCoor() <<
-      "," <<  setw(5) << setprecision(3) << GetBendingCoor() <<
-      "," <<  setw(5) << setprecision(3) << GetZ() <<
+    cout << "<AliMUONTrackParam> Bending P=" << setw(5) << setprecision(3)  << 1./fParameters(4,0) << 
+      ", NonBendSlope=" << setw(5) << setprecision(3)  << fParameters(1,0)*180./TMath::Pi() <<
+      ", BendSlope=" << setw(5) << setprecision(3)     << fParameters(3,0)*180./TMath::Pi()  << 
+      ", (x,y,z)_IP=(" <<  setw(5) << setprecision(3) << fParameters(0,0) <<
+      "," <<  setw(5) << setprecision(3) << fParameters(2,0) <<
+      "," <<  setw(5) << setprecision(3) << fZ <<
       ") cm, (px,py,pz)=(" << setw(5) << setprecision(3) << Px() <<
       "," << setw(5) << setprecision(3) << Py() <<
       "," << setw(5) << setprecision(3) << Pz() << ") GeV/c" << endl;
index 68d0236cce6114c67f12594283d9b91e6010a0ee..c40e6d6283ff80dfc9f2d6c6cd3891b8e86bbe14 100644 (file)
@@ -15,9 +15,9 @@
 ////////////////////////////////////////////////////
 
 #include <TObject.h>
-#include <TMatrixDfwd.h>
-#include "AliMUONHitForRec.h"
+#include <TMatrixD.h>
 
+class AliMUONHitForRec;
 class AliESDMuonTrack;
 
 class AliMUONTrackParam : public TObject 
@@ -30,41 +30,46 @@ class AliMUONTrackParam : public TObject
   AliMUONTrackParam& operator=(const  AliMUONTrackParam& theMUONTrackParam);
 
   void GetParamFrom(const AliESDMuonTrack& esdMuonTrack);
-  void SetParamFor(AliESDMuonTrack& esdMuonTrack);
+  void SetParamFor(AliESDMuonTrack& esdMuonTrack) const;
   void GetParamFromUncorrected(const AliESDMuonTrack& esdMuonTrack);
-  void SetParamForUncorrected(AliESDMuonTrack& esdMuonTrack);
+  void SetParamForUncorrected(AliESDMuonTrack& esdMuonTrack) const;
 
   // Get and Set methods for data
-       /// return inverse bending momentum (GeV/c ** -1) times the charge (assumed forward motion)
-  Double_t GetInverseBendingMomentum(void) const {return fInverseBendingMomentum;}
-       /// set inverse bending momentum (GeV/c ** -1) times the charge (assumed forward motion)
-  void     SetInverseBendingMomentum(Double_t inverseBendingMomentum) {fInverseBendingMomentum = inverseBendingMomentum;}
-       /// return bending slope (cm ** -1)
-  Double_t GetBendingSlope(void) const {return fBendingSlope;}
-       /// set bending slope (cm ** -1)
-  void     SetBendingSlope(Double_t bendingSlope) {fBendingSlope = bendingSlope;}
-       /// return non bending slope (cm ** -1)
-  Double_t GetNonBendingSlope(void) const {return fNonBendingSlope;}
-       /// set non bending slope (cm ** -1)
-  void     SetNonBendingSlope(Double_t nonBendingSlope) {fNonBendingSlope = nonBendingSlope;}
        /// return Z coordinate (cm)
-  Double_t GetZ(void) const {return fZ;}
+  Double_t GetZ() const {return fZ;}
        /// set Z coordinate (cm)
   void     SetZ(Double_t z) {fZ = z;}
-       /// return bending coordinate (cm)
-  Double_t GetBendingCoor(void) const {return fBendingCoor;}
-       /// set bending coordinate (cm)
-  void     SetBendingCoor(Double_t bendingCoor) {fBendingCoor = bendingCoor;}
        /// return non bending coordinate (cm)
-  Double_t GetNonBendingCoor(void) const {return fNonBendingCoor;}
+  Double_t GetNonBendingCoor() const {return fParameters(0,0);}
        /// set non bending coordinate (cm)
-  void     SetNonBendingCoor(Double_t nonBendingCoor) {fNonBendingCoor = nonBendingCoor;}
-  
-  void     SetTrackParam(AliMUONTrackParam& theMUONTrackParam);
+  void     SetNonBendingCoor(Double_t nonBendingCoor) {fParameters(0,0) = nonBendingCoor;}
+       /// return non bending slope (cm ** -1)
+  Double_t GetNonBendingSlope() const {return fParameters(1,0);}
+       /// set non bending slope (cm ** -1)
+  void     SetNonBendingSlope(Double_t nonBendingSlope) {fParameters(1,0) = nonBendingSlope;}
+       /// return bending coordinate (cm)
+  Double_t GetBendingCoor() const {return fParameters(2,0);}
+       /// set bending coordinate (cm)
+  void     SetBendingCoor(Double_t bendingCoor) {fParameters(2,0) = bendingCoor;}
+       /// return bending slope (cm ** -1)
+  Double_t GetBendingSlope() const {return fParameters(3,0);}
+       /// set bending slope (cm ** -1)
+  void     SetBendingSlope(Double_t bendingSlope) {fParameters(3,0) = bendingSlope;}
+       /// return inverse bending momentum (GeV/c ** -1) times the charge (assumed forward motion)
+  Double_t GetInverseBendingMomentum() const {return fParameters(4,0);}
+       /// set inverse bending momentum (GeV/c ** -1) times the charge (assumed forward motion)
+  void     SetInverseBendingMomentum(Double_t inverseBendingMomentum) {fParameters(4,0) = inverseBendingMomentum;}
+       /// return the charge (assumed forward motion)
+  Double_t GetCharge() const {return TMath::Sign(1.,fParameters(4,0));}
+       /// set the charge (assumed forward motion)
+  void     SetCharge(Double_t charge) {if (charge*fParameters(4,0) < 0.) fParameters(4,0) *= -1.;}
   
-  AliMUONHitForRec* GetHitForRecPtr(void) const;
-       /// set pointeur to associated HitForRec
-  void     SetHitForRecPtr(AliMUONHitForRec* hitForRec) {fHitForRecPtr = hitForRec;}
+       /// return track parameters
+  const TMatrixD& GetParameters() const {return fParameters;}
+       /// set track parameters
+  void            SetParameters(const TMatrixD& parameters) {fParameters = parameters;}
+       /// add track parameters
+  void            AddParameters(const TMatrixD& parameters) {fParameters += parameters;}
   
   Double_t Px() const;  // return px
   Double_t Py() const;  // return py
@@ -72,15 +77,48 @@ class AliMUONTrackParam : public TObject
   Double_t P()  const;  // return total momentum
 
        /// return kTRUE if the covariance matrix exist, kFALSE if not
-  Bool_t    CovariancesExist(void) {return (fCovariances) ? kTRUE : kFALSE;}
-  TMatrixD* GetCovariances(void) const;
-  void      SetCovariances(TMatrixD* covariances);
-  void      SetCovariances(Double_t matrix[5][5]);
-  void      SetVariances(Double_t matrix[5][5]);
-  void      DeleteCovariances(void);
-  
-  void EvalCovariances(AliMUONHitForRec* hit2);
-
+  Bool_t    CovariancesExist() const {return (fCovariances) ? kTRUE : kFALSE;}
+  
+  const TMatrixD& GetCovariances() const;
+  void            SetCovariances(const TMatrixD& covariances);
+  void            SetCovariances(const Double_t matrix[5][5]);
+  void            SetVariances(const Double_t matrix[5][5]);
+  void            DeleteCovariances();
+  
+  const TMatrixD& GetPropagator() const;
+  void            ResetPropagator();
+  void            UpdatePropagator(const TMatrixD& propagator);
+  
+  const TMatrixD& GetExtrapParameters() const;
+  void            SetExtrapParameters(const TMatrixD& parameters);
+  
+  const TMatrixD& GetExtrapCovariances() const;
+  void            SetExtrapCovariances(const TMatrixD& covariances);
+  
+  const TMatrixD& GetSmoothParameters() const;
+  void            SetSmoothParameters(const TMatrixD& parameters);
+  
+  const TMatrixD& GetSmoothCovariances() const;
+  void            SetSmoothCovariances(const TMatrixD& covariances);
+  
+  AliMUONHitForRec* GetHitForRecPtr() const;
+       /// set pointeur to associated HitForRec
+  void              SetHitForRecPtr(AliMUONHitForRec* hitForRec) {fHitForRecPtr = hitForRec;}
+  
+       /// return kTRUE if the associated hit can be removed from the track it belongs to
+  Bool_t IsRemovable() const {return fRemovable;}
+       /// set the flag telling whether the associated hit can be removed from the track it belongs to or not
+  void   SetRemovable(Bool_t removable) {fRemovable = removable;}
+  
+       /// return the chi2 of the track when the associated HitForRec was attached
+  Double_t GetTrackChi2() const {return fTrackChi2;}
+       /// set the chi2 of the track when the associated HitForRec was attached
+  void     SetTrackChi2(Double_t chi2) {fTrackChi2 = chi2;}
+       /// return the local chi2 of the associated HitForRec with respect to the track
+  Double_t GetLocalChi2() const {return fLocalChi2;}
+       /// set the local chi2 of the associated HitForRec with respect to the track
+  void     SetLocalChi2(Double_t chi2) {fLocalChi2 = chi2;}
+  
        /// necessary for sorting TClonesArray of TrackHit's
   Bool_t IsSortable () const {return kTRUE;}
   Int_t Compare(const TObject* trackParam) const;
@@ -90,14 +128,17 @@ class AliMUONTrackParam : public TObject
   virtual void Clear(Option_t* opt="");
 
  private:
-  // Parameters
-  Double_t fNonBendingCoor; ///< Non bending coordinate (cm)
-  Double_t fNonBendingSlope; ///< Non bending slope (cm ** -1)
-  Double_t fBendingCoor; ///< Bending coordinate (cm)
-  Double_t fBendingSlope; ///< Bending slope (cm ** -1)
-  Double_t fInverseBendingMomentum; ///< Inverse bending momentum (GeV/c ** -1) times the charge (assumed forward motion)
+  
   Double_t fZ; ///< Z coordinate (cm)
   
+  /// Track parameters ordered as follow:      <pre>
+  /// X       = Non bending coordinate   (cm)
+  /// SlopeX  = Non bending slope        (cm ** -1)
+  /// Y       = Bending coordinate       (cm)
+  /// SlopeY  = Bending slope            (cm ** -1)
+  /// InvP_yz = Inverse bending momentum (GeV/c ** -1) times the charge (assumed forward motion)  </pre>
+  TMatrixD fParameters; ///< \brief Track parameters 
+  
   /// Covariance matrix of track parameters, ordered as follow:      <pre>
   ///    <X,X>      <X,SlopeX>        <X,Y>      <X,SlopeY>       <X,InvP_yz>
   /// <X,SlopeX>  <SlopeX,SlopeX>  <Y,SlopeX>  <SlopeX,SlopeY>  <SlopeX,InvP_yz>
@@ -106,9 +147,21 @@ class AliMUONTrackParam : public TObject
   /// <X,InvP_yz> <SlopeX,InvP_yz> <Y,InvP_yz> <SlopeY,InvP_yz> <InvP_yz,InvP_yz>  </pre>
   mutable TMatrixD *fCovariances; ///< \brief Covariance matrix of track parameters 
   
+  mutable TMatrixD *fPropagator; //!< Jacobian used to extrapolate the track parameters and covariances to the actual z position
+  mutable TMatrixD *fExtrapParameters; //!< Track parameters extrapolated to the actual z position (not filtered by Kalman)
+  mutable TMatrixD *fExtrapCovariances; //!< Covariance matrix extrapolated to the actual z position (not filtered by Kalman)
+  
+  mutable TMatrixD *fSmoothParameters; //!< Track parameters obtained using smoother
+  mutable TMatrixD *fSmoothCovariances; //!< Covariance matrix obtained using smoother
+  
   AliMUONHitForRec *fHitForRecPtr; //!< Pointer to associated HitForRec if any
   
-  ClassDef(AliMUONTrackParam, 3) // Track parameters in ALICE dimuon spectrometer
+  Bool_t fRemovable; //!< kTRUE if the associated hit can be removed from the track it belongs to
+  
+  Double_t fTrackChi2; //!< Chi2 of the track when the associated HitForRec was attached
+  Double_t fLocalChi2; //!< Local chi2 of the associated HitForRec with respect to the track
+  
+  ClassDef(AliMUONTrackParam, 4) // Track parameters in ALICE dimuon spectrometer
 };
        
 #endif
index 3412ce42d4cebf453e4d1fc6072fcf4817ae1830..32002e0aa19587b017058a15c1ad57cd85684a47 100644 (file)
@@ -28,9 +28,7 @@
 #include "AliMUONTrackReconstructor.h"
 
 #include "AliMUONConstants.h"
-#include "AliMUONRawCluster.h"
 #include "AliMUONHitForRec.h"
-#include "AliMUONObjectPair.h"
 #include "AliMUONTrack.h"
 #include "AliMUONTrackParam.h"
 #include "AliMUONTrackExtrap.h"
 
 #include <TMinuit.h>
 #include <Riostream.h>
+#include <TMath.h>
 #include <TMatrixD.h>
 
 // Functions to be minimized with Minuit
-void TrackChi2(Int_t &NParam, Double_t *Gradient, Double_t &Chi2, Double_t *Param, Int_t Flag);
-void TrackChi2MCS(Int_t &NParam, Double_t *Gradient, Double_t &Chi2, Double_t *Param, Int_t Flag);
-
-Double_t MultipleScatteringAngle2(AliMUONTrackParam *param);
+void TrackChi2(Int_t &nParam, Double_t *gradient, Double_t &chi2, Double_t *param, Int_t flag);
 
 /// \cond CLASSIMP
 ClassImp(AliMUONTrackReconstructor) // Class implementation in ROOT context
 /// \endcond
 
-//************* Defaults parameters for reconstruction
-const Double_t AliMUONTrackReconstructor::fgkMaxNormChi2 = 100.0;
-const Bool_t AliMUONTrackReconstructor::fgkTrackAllTracks = kFALSE;
+//************* Parameters for reconstruction
+const Double_t AliMUONTrackReconstructor::fgkBendingVertexDispersion = 10.;
+const Double_t AliMUONTrackReconstructor::fgkNonBendingVertexDispersion = 10.;
+
 
 //__________________________________________________________________________
 AliMUONTrackReconstructor::AliMUONTrackReconstructor()
   : AliMUONVTrackReconstructor()
 {
   /// Constructor for class AliMUONTrackReconstructor
-  
-  // Memory allocation for the TClonesArray of reconstructed tracks
-  fRecTracksPtr = new TClonesArray("AliMUONTrack", 10);
+  AliInfo("*** Original tracking ***");
 }
 
 //__________________________________________________________________________
-AliMUONTrackReconstructor::~AliMUONTrackReconstructor(void)
+AliMUONTrackReconstructor::~AliMUONTrackReconstructor()
 {
-  /// Destructor for class AliMUONTrackReconstructor
-  delete fRecTracksPtr;
-}
-
-//__________________________________________________________________________
-void AliMUONTrackReconstructor::MakeTracks(void)
-{
-  /// To make the tracks from the list of segments and points in all stations
-  AliDebug(1,"Enter MakeTracks");
-  // Look for candidates from at least 3 aligned points in stations(1..) 4 and 5
-  MakeTrackCandidates();
-  // Follow tracks in stations(1..) 3, 2 and 1
-  FollowTracks();
-  // Remove double tracks
-  RemoveDoubleTracks();
-  // Fill out the AliMUONTrack's
-  FillMUONTrack();
-}
+/// Destructor
+} 
 
   //__________________________________________________________________________
-void AliMUONTrackReconstructor::MakeTrackCandidates(void)
+void AliMUONTrackReconstructor::MakeTrackCandidates()
 {
   /// To make track candidates:
   /// Start with segments station(1..) 4 or 5 then follow track in station 5 or 4.
   /// Good candidates are made of at least three hitForRec's.
   /// Keep only best candidates or all of them according to the flag fgkTrackAllTracks.
   TClonesArray *segments;
-  AliMUONObjectPair *segment;
-  AliMUONHitForRec *hitForRec1, *hitForRec2;
   AliMUONTrack *track;
-  AliMUONTrackParam *trackParamAtFirstHit;
   Int_t iCandidate = 0;
 
   AliDebug(1,"Enter MakeTrackCandidates");
 
   // Loop over stations(1..) 5 and 4 and make track candidates
-  for (Int_t istat=4; istat>=3; istat--) 
-  {
+  for (Int_t istat=4; istat>=3; istat--) {
+    
     // Make segments in the station
     segments = MakeSegmentsInStation(istat);
+    
     // Loop over segments
     for (Int_t iseg=0; iseg<segments->GetEntriesFast(); iseg++) 
     {
       AliDebug(1,Form("Making primary candidate(1..) %d",++iCandidate));
+      
       // Transform segments to tracks and put them at the end of fRecTracksPtr
-      segment = (AliMUONObjectPair*) ((*segments)[iseg]);
-      hitForRec1 = (AliMUONHitForRec*) segment->First();
-      hitForRec2 = (AliMUONHitForRec*) segment->Second();
-      track = new ((*fRecTracksPtr)[fRecTracksPtr->GetLast()+1]) AliMUONTrack(hitForRec1, hitForRec2);
+      track = new ((*fRecTracksPtr)[fRecTracksPtr->GetLast()+1]) AliMUONTrack((AliMUONObjectPair*)((*segments)[iseg]));
       fNRecTracks++;
-      // Add MCS effects in parameter covariances
-      trackParamAtFirstHit = (AliMUONTrackParam*) (track->GetTrackParamAtHit()->First());
-      AliMUONTrackExtrap::AddMCSEffect(trackParamAtFirstHit,AliMUONConstants::ChamberThicknessInX0(),1.);
+      
       // Printout for debuging
       if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructor") >= 2) || (AliLog::GetGlobalDebugLevel() >= 2))
       {
         cout<<endl<<"Track parameter covariances at first hit with multiple Coulomb scattering effects:"<<endl;
-        trackParamAtFirstHit->GetCovariances()->Print();
+        ((AliMUONTrackParam*) track->GetTrackParamAtHit()->First())->GetCovariances().Print();
       }
+      
       // Look for compatible hitForRec(s) in the other station
-      FollowTrackInStation(track,7-istat);
+      if (!FollowTrackInStation(*track,7-istat)) {
+        fRecTracksPtr->Remove(track);
+       fNRecTracks--;
+      }
+      
     }
+    
     // delete the array of segments
     delete segments;
   }
+  
   fRecTracksPtr->Compress(); // this is essential before checking tracks
   
   // Keep all different tracks or only the best ones as required
@@ -143,155 +123,70 @@ void AliMUONTrackReconstructor::MakeTrackCandidates(void)
 }
 
   //__________________________________________________________________________
-void AliMUONTrackReconstructor::RemoveIdenticalTracks(void)
-{
-  /// To remove identical tracks:
-  /// Tracks are considered identical if they have all their hits in common.
-  /// One keeps the track with the larger number of hits if need be
-  AliMUONTrack *track1, *track2, *trackToRemove;
-  Int_t hitsInCommon, nHits1, nHits2;
-  Bool_t removedTrack1;
-  // Loop over first track of the pair
-  track1 = (AliMUONTrack*) fRecTracksPtr->First();
-  while (track1) {
-    removedTrack1 = kFALSE;
-    nHits1 = track1->GetNTrackHits();
-    // Loop over second track of the pair
-    track2 = (AliMUONTrack*) fRecTracksPtr->After(track1);
-    while (track2) {
-      nHits2 = track2->GetNTrackHits();
-      // number of hits in common between two tracks
-      hitsInCommon = track1->HitsInCommon(track2);
-      // check for identical tracks
-      if ((hitsInCommon == nHits1) || (hitsInCommon == nHits2)) {
-        // decide which track to remove
-        if (nHits2 > nHits1) {
-         // remove track1 and continue the first loop with the track next to track1
-         trackToRemove = track1;
-         track1 = (AliMUONTrack*) fRecTracksPtr->After(track1);
-          fRecTracksPtr->Remove(trackToRemove);
-         fRecTracksPtr->Compress(); // this is essential to retrieve the TClonesArray afterwards
-         fNRecTracks--;
-         removedTrack1 = kTRUE;
-         break;
-       } else {
-         // remove track2 and continue the second loop with the track next to track2
-         trackToRemove = track2;
-         track2 = (AliMUONTrack*) fRecTracksPtr->After(track2);
-         fRecTracksPtr->Remove(trackToRemove);
-         fRecTracksPtr->Compress(); // this is essential to retrieve the TClonesArray afterwards
-         fNRecTracks--;
-        }
-      } else track2 = (AliMUONTrack*) fRecTracksPtr->After(track2);
-    } // track2
-    if (removedTrack1) continue;
-    track1 = (AliMUONTrack*) fRecTracksPtr->After(track1);
-  } // track1
-  return;
-}
-
-  //__________________________________________________________________________
-void AliMUONTrackReconstructor::RemoveDoubleTracks(void)
-{
-  /// To remove double tracks:
-  /// Tracks are considered identical if more than half of the hits of the track
-  /// which has the smaller number of hits are in common with the other track.
-  /// Among two identical tracks, one keeps the track with the larger number of hits
-  /// or, if these numbers are equal, the track with the minimum chi2.
-  AliMUONTrack *track1, *track2, *trackToRemove;
-  Int_t hitsInCommon, nHits1, nHits2;
-  Bool_t removedTrack1;
-  // Loop over first track of the pair
-  track1 = (AliMUONTrack*) fRecTracksPtr->First();
-  while (track1) {
-    removedTrack1 = kFALSE;
-    nHits1 = track1->GetNTrackHits();
-    // Loop over second track of the pair
-    track2 = (AliMUONTrack*) fRecTracksPtr->After(track1);
-    while (track2) {
-      nHits2 = track2->GetNTrackHits();
-      // number of hits in common between two tracks
-      hitsInCommon = track1->HitsInCommon(track2);
-      // check for identical tracks
-      if (((nHits1 < nHits2) && (2 * hitsInCommon > nHits1)) || (2 * hitsInCommon > nHits2)) {
-        // decide which track to remove
-        if ((nHits1 > nHits2) || ((nHits1 == nHits2) && (track1->GetFitFMin() <= track2->GetFitFMin()))) {
-         // remove track2 and continue the second loop with the track next to track2
-         trackToRemove = track2;
-         track2 = (AliMUONTrack*) fRecTracksPtr->After(track2);
-         fRecTracksPtr->Remove(trackToRemove);
-         fRecTracksPtr->Compress(); // this is essential to retrieve the TClonesArray afterwards
-         fNRecTracks--;
-        } else {
-         // else remove track1 and continue the first loop with the track next to track1
-         trackToRemove = track1;
-         track1 = (AliMUONTrack*) fRecTracksPtr->After(track1);
-          fRecTracksPtr->Remove(trackToRemove);
-         fRecTracksPtr->Compress(); // this is essential to retrieve the TClonesArray afterwards
-         fNRecTracks--;
-         removedTrack1 = kTRUE;
-         break;
-        }
-      } else track2 = (AliMUONTrack*) fRecTracksPtr->After(track2);
-    } // track2
-    if (removedTrack1) continue;
-    track1 = (AliMUONTrack*) fRecTracksPtr->After(track1);
-  } // track1
-  return;
-}
-
-  //__________________________________________________________________________
-void AliMUONTrackReconstructor::FollowTracks(void)
+void AliMUONTrackReconstructor::FollowTracks()
 {
   /// Follow tracks in stations(1..) 3, 2 and 1
   AliDebug(1,"Enter FollowTracks");
   
   AliMUONTrack *track, *nextTrack;
-  AliMUONTrackParam *trackParamAtFirstHit;
-  Double_t numberOfDegFree, chi2Norm;
   Int_t currentNRecTracks;
+  Bool_t hitFound;
   
   for (Int_t station = 2; station >= 0; station--) {
+    
     // Save the actual number of reconstructed track in case of
     // tracks are added or suppressed during the tracking procedure
     // !! Do not compress fRecTracksPtr until the end of the loop over tracks !!
     currentNRecTracks = fNRecTracks;
+    
     for (Int_t iRecTrack = 0; iRecTrack <currentNRecTracks; iRecTrack++) {
       AliDebug(1,Form("FollowTracks: track candidate(1..) %d", iRecTrack+1));
+      
       track = (AliMUONTrack*) fRecTracksPtr->UncheckedAt(iRecTrack);
+      
       // Fit the track:
       // Do not take into account the multiple scattering to speed up the fit
       // Calculate the track parameter covariance matrix
       // If "station" is station(1..) 3 then use the vertex to better constrain the fit
       if (station==2) {
-        SetVertexForFit(track);
+        SetVertexForFit(*track);
         track->SetFitWithVertex(kTRUE);
       } else track->SetFitWithVertex(kFALSE);
-      Fit(track,kFALSE, kTRUE);
+      Fit(*track, kFALSE, kTRUE);
+      
       // Remove the track if the normalized chi2 is too high
-      numberOfDegFree = (2. * track->GetNTrackHits() - 5.);
-      if (numberOfDegFree > 0) chi2Norm = track->GetFitFMin() / numberOfDegFree;
-      else chi2Norm = 1.e10;
-      if (chi2Norm > fgkMaxNormChi2) {
+      if (track->GetNormalizedChi2() > fgkSigmaToCutForTracking * fgkSigmaToCutForTracking) {
        fRecTracksPtr->Remove(track);
        fNRecTracks--;
        continue;
       }
-      // Add MCS effects in parameter covariances
-      trackParamAtFirstHit = (AliMUONTrackParam*) (track->GetTrackParamAtHit()->First());
-      AliMUONTrackExtrap::AddMCSEffect(trackParamAtFirstHit,AliMUONConstants::ChamberThicknessInX0(),1.);
+      
       // Printout for debuging
       if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructor") >= 2) || (AliLog::GetGlobalDebugLevel() >= 2)) {
         cout<<endl<<"Track parameter covariances at first hit with multiple Coulomb scattering effects:"<<endl;
-        trackParamAtFirstHit->GetCovariances()->Print();
+        ((AliMUONTrackParam*) track->GetTrackParamAtHit()->First())->GetCovariances().Print();
       }
+      
       // Look for compatible hitForRec in station(0..) "station"
-      FollowTrackInStation(track,station);
+      hitFound = FollowTrackInStation(*track,station);
+      
+      // Try to recover track if required
+      if (!hitFound && fgkRecoverTracks) hitFound = RecoverTrack(*track,station);
+      
+      // remove track if no hit found
+      if (!hitFound) {
+       fRecTracksPtr->Remove(track);
+       fNRecTracks--;
+      }
+      
     }
+    
     // Compress fRecTracksPtr for the next step
     fRecTracksPtr->Compress();
+    
     // Keep only the best tracks if required
     if (!fgkTrackAllTracks) RemoveDoubleTracks();
+    
   }
   
   // Last fit of track candidates with all station
@@ -299,31 +194,35 @@ void AliMUONTrackReconstructor::FollowTracks(void)
   Int_t trackIndex = -1;
   track = (AliMUONTrack*) fRecTracksPtr->First();
   while (track) {
+    
     trackIndex++;
     nextTrack = (AliMUONTrack*) fRecTracksPtr->After(track); // prepare next track
+    
     track->SetFitWithVertex(kFALSE); // just to be sure
-    Fit(track,kTRUE, kTRUE);
+    Fit(*track, kTRUE, kTRUE);
+    
     // Printout for debuging
     if (AliLog::GetGlobalDebugLevel() >= 3) {
       cout << "FollowTracks: track candidate(0..) " << trackIndex << " after final fit" << endl;
       track->RecursiveDump();
     } 
+    
     // Remove the track if the normalized chi2 is too high
-    numberOfDegFree = (2.0 * track->GetNTrackHits() - 5);
-    if (numberOfDegFree > 0) chi2Norm = track->GetFitFMin() / numberOfDegFree;
-    else chi2Norm = 1.e10;
-    if (chi2Norm > fgkMaxNormChi2) {
+    if (track->GetNormalizedChi2() > fgkSigmaToCutForTracking * fgkSigmaToCutForTracking) {
       fRecTracksPtr->Remove(track);
       fNRecTracks--;
     }
+    
     track = nextTrack;
+    
   }
+  
   fRecTracksPtr->Compress();
   
 }
 
   //__________________________________________________________________________
-void AliMUONTrackReconstructor::FollowTrackInStation(AliMUONTrack* trackCandidate, Int_t nextStation)
+Bool_t AliMUONTrackReconstructor::FollowTrackInStation(AliMUONTrack &trackCandidate, Int_t nextStation)
 {
   /// Follow trackCandidate in station(0..) nextStation and search for compatible HitForRec(s)
   /// Keep all possibilities or only the best one(s) according to the flag fgkTrackAllTracks:
@@ -333,203 +232,469 @@ void AliMUONTrackReconstructor::FollowTrackInStation(AliMUONTrack* trackCandidat
   /// kFALSE: add only the best hit(s) to the "trackCandidate". Try to add a couple of hits in priority.
   AliDebug(1,Form("Enter FollowTrackInStation(1..) %d", nextStation+1));
   
-  Int_t ch1 = 2*nextStation;
-  Int_t ch2 = 2*nextStation+1;
+  // Order the chamber according to the propagation direction (tracking starts with chamber 2):
+  // - nextStation == station(1...) 5 => forward propagation
+  // - nextStation < station(1...) 5 => backward propagation
+  Int_t ch1, ch2;
+  if (nextStation==4) {
+    ch1 = 2*nextStation+1;
+    ch2 = 2*nextStation;
+  } else {
+    ch1 = 2*nextStation;
+    ch2 = 2*nextStation+1;
+  }
+  
   Double_t zCh2 = AliMUONConstants::DefaultChamberZ(ch2);
   Double_t chi2WithOneHitForRec = 1.e10;
   Double_t chi2WithTwoHitForRec = 1.e10;
-  Double_t maxChi2WithOneHitForRec = 2.*fgkMaxNormChi2; // 2 because 2 quantities in chi2
-  Double_t maxChi2WithTwoHitForRec = 4.*fgkMaxNormChi2; // 4 because 4 quantities in chi2
+  Double_t maxChi2WithOneHitForRec = 2. * fgkSigmaToCutForTracking * fgkSigmaToCutForTracking; // 2 because 2 quantities in chi2
+  Double_t maxChi2WithTwoHitForRec = 4. * fgkSigmaToCutForTracking * fgkSigmaToCutForTracking; // 4 because 4 quantities in chi2
   Double_t bestChi2WithOneHitForRec = maxChi2WithOneHitForRec;
   Double_t bestChi2WithTwoHitForRec = maxChi2WithTwoHitForRec;
+  Bool_t foundOneHit = kFALSE;
+  Bool_t foundTwoHits = kFALSE;
   AliMUONTrack *newTrack = 0x0;
   AliMUONHitForRec *hitForRecCh1, *hitForRecCh2;
-  AliMUONHitForRec *bestHitForRec1 = 0x0, *bestHitForRec2 = 0x0;
+  AliMUONTrackParam extrapTrackParamAtHit1;
+  AliMUONTrackParam extrapTrackParamAtHit2;
+  AliMUONTrackParam bestTrackParamAtHit1;
+  AliMUONTrackParam bestTrackParamAtHit2;
   Bool_t *hitForRecCh1Used = new Bool_t[fNHitsForRecPerChamber[ch1]];
   for (Int_t hit1 = 0; hit1 < fNHitsForRecPerChamber[ch1]; hit1++) hitForRecCh1Used[hit1] = kFALSE;
-  //
-  //Extrapolate trackCandidate to chamber "ch2" to save computing time in the next steps
-  AliMUONTrackParam *extrapTrackParamPtr = trackCandidate->GetExtrapTrackParam();
-  *extrapTrackParamPtr = *((AliMUONTrackParam*)(trackCandidate->GetTrackParamAtHit()->First()));
-  AliMUONTrackExtrap::ExtrapToZCov(extrapTrackParamPtr, zCh2);
-  AliMUONTrackParam extrapTrackParamSave(*extrapTrackParamPtr);
-  //
+  
+  // Get track parameters and extrapolate them to chamber "ch2" to save computing time in the next steps
+  AliMUONTrackParam extrapTrackParamAtCh2(*(AliMUONTrackParam*)trackCandidate.GetTrackParamAtHit()->First());
+  
+  // Add MCS effect
+  AliMUONTrackExtrap::AddMCSEffect(&extrapTrackParamAtCh2,AliMUONConstants::ChamberThicknessInX0(),1.);
+  
+  // Add MCS in the missing chamber if any (only 1 chamber can be missing according to tracking criteria)
+  if (ch1 < ch2 && extrapTrackParamAtCh2.GetHitForRecPtr()->GetChamberNumber() > ch2 + 1) {
+    // extrapolation to the missing chamber
+    AliMUONTrackExtrap::ExtrapToZCov(&extrapTrackParamAtCh2, AliMUONConstants::DefaultChamberZ(ch2 + 1));
+    // add MCS effect
+    AliMUONTrackExtrap::AddMCSEffect(&extrapTrackParamAtCh2,AliMUONConstants::ChamberThicknessInX0(),1.);
+  }
+  
+  //Extrapolate trackCandidate to chamber "ch2"
+  AliMUONTrackExtrap::ExtrapToZCov(&extrapTrackParamAtCh2, zCh2);
+  
   // Printout for debuging
   if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructor") >= 2) || (AliLog::GetGlobalDebugLevel() >= 2)) {
-    TMatrixD* paramCovForDebug = extrapTrackParamPtr->GetCovariances();
     cout<<endl<<"Track parameter covariances at first hit extrapolated to z = "<<zCh2<<":"<<endl;
-    paramCovForDebug->Print();
+    extrapTrackParamAtCh2.GetCovariances().Print();
   }
-  //
-  // look for candidates in chamber 2 
+  
   // Printout for debuging
   if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructor") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
     cout << "FollowTrackInStation: look for hits in chamber(1..): " << ch2+1 << endl;
   }
+  
+  // look for candidates in chamber 2 
   for (Int_t hit2 = 0; hit2 < fNHitsForRecPerChamber[ch2]; hit2++) {
+    
     hitForRecCh2 = (AliMUONHitForRec*) fHitsForRecPtr->UncheckedAt(fIndexOfFirstHitForRecPerChamber[ch2]+hit2);
-    // extrapolate track parameters and covariances only once for this hit
-    AliMUONTrackExtrap::ExtrapToZCov(extrapTrackParamPtr, hitForRecCh2->GetZ());
-    chi2WithOneHitForRec = trackCandidate->TryOneHitForRec(hitForRecCh2);
+    
+    // try to add the current hit
+    chi2WithOneHitForRec = TryOneHitForRec(extrapTrackParamAtCh2, hitForRecCh2, extrapTrackParamAtHit2);
+    
     // if good chi2 then try to attach a hitForRec in the other chamber too
     if (chi2WithOneHitForRec < maxChi2WithOneHitForRec) {
+      Bool_t foundSecondHit = kFALSE;
+      
       // Printout for debuging
       if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructor") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
-        cout << "FollowTrackInStation: look for second hits in chamber(1..): " << ch1+1 << endl;
+        cout << "FollowTrackInStation: found one hit in chamber(1..): " << ch2+1
+            << " (Chi2 = " << chi2WithOneHitForRec << ")" << endl;
+        cout << "                      look for second hits in chamber(1..): " << ch1+1 << " ..." << endl;
       }
-      Bool_t foundSecondHit = kFALSE;
+      
+      // add MCS effect for next step
+      AliMUONTrackExtrap::AddMCSEffect(&extrapTrackParamAtHit2,AliMUONConstants::ChamberThicknessInX0(),1.);
+      
       for (Int_t hit1 = 0; hit1 < fNHitsForRecPerChamber[ch1]; hit1++) {
-        hitForRecCh1 = (AliMUONHitForRec*) fHitsForRecPtr->UncheckedAt(fIndexOfFirstHitForRecPerChamber[ch1]+hit1);
-       chi2WithTwoHitForRec = trackCandidate->TryTwoHitForRec(hitForRecCh2, hitForRecCh1); // order hits like that to save computing time
-        // if good chi2 then create a new track by adding the 2 hitForRec to the "trackCandidate"
+        
+       hitForRecCh1 = (AliMUONHitForRec*) fHitsForRecPtr->UncheckedAt(fIndexOfFirstHitForRecPerChamber[ch1]+hit1);
+       
+       // try to add the current hit in addition to the one found on the previous chamber
+       chi2WithTwoHitForRec = TryTwoHitForRec(extrapTrackParamAtHit2, hitForRecCh1, extrapTrackParamAtHit1);
+        
+       // if good chi2 then create a new track by adding the 2 hitForRec to the "trackCandidate"
        if (chi2WithTwoHitForRec < maxChi2WithTwoHitForRec) {
          foundSecondHit = kTRUE;
-          if (fgkTrackAllTracks) {
+          foundTwoHits = kTRUE;
+          
+         // Printout for debuging
+         if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructor") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
+           cout << "FollowTrackInStation: found second hit in chamber(1..): " << ch1+1
+                << " (Global Chi2 = " << chi2WithTwoHitForRec << ")" << endl;
+         }
+         
+         if (fgkTrackAllTracks) {
            // copy trackCandidate into a new track put at the end of fRecTracksPtr and add the new hitForRec's
-            newTrack = new ((*fRecTracksPtr)[fRecTracksPtr->GetLast()+1]) AliMUONTrack(*trackCandidate);
+            newTrack = new ((*fRecTracksPtr)[fRecTracksPtr->GetLast()+1]) AliMUONTrack(trackCandidate);
+           UpdateTrack(*newTrack,extrapTrackParamAtHit1,extrapTrackParamAtHit2);
            fNRecTracks++;
-            AliMUONTrackParam trackParam1(extrapTrackParamSave);
-            AliMUONTrackExtrap::ExtrapToZ(&trackParam1, hitForRecCh1->GetZ());
-           newTrack->AddTrackParamAtHit(&trackParam1,hitForRecCh1);
-            AliMUONTrackParam trackParam2(extrapTrackParamSave);
-            AliMUONTrackExtrap::ExtrapToZ(&trackParam2, hitForRecCh2->GetZ());
-           newTrack->AddTrackParamAtHit(&trackParam2,hitForRecCh2);
-            // Sort TrackParamAtHit according to increasing Z
-            newTrack->GetTrackParamAtHit()->Sort();
-           // Update the chi2 of the new track
-           if (newTrack->GetFitFMin()<0) newTrack->SetFitFMin(chi2WithTwoHitForRec);
-           else newTrack->SetFitFMin(newTrack->GetFitFMin() + chi2WithTwoHitForRec);
+           
            // Tag hitForRecCh1 as used
            hitForRecCh1Used[hit1] = kTRUE;
+           
            // Printout for debuging
            if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructor") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
-             cout << "FollowTrackInStation: added two hits in station(1..): " << nextStation+1
-                  << " (Chi2 = " << chi2WithTwoHitForRec << ")" << endl;
+             cout << "FollowTrackInStation: added two hits in station(1..): " << nextStation+1 << endl;
              if (AliLog::GetGlobalDebugLevel() >= 3) newTrack->RecursiveDump();
            }
+           
           } else if (chi2WithTwoHitForRec < bestChi2WithTwoHitForRec) {
            // keep track of the best couple of hits
            bestChi2WithTwoHitForRec = chi2WithTwoHitForRec;
-           bestHitForRec1 = hitForRecCh1;
-           bestHitForRec2 = hitForRecCh2;
+           bestTrackParamAtHit1 = extrapTrackParamAtHit1;
+           bestTrackParamAtHit2 = extrapTrackParamAtHit2;
           }
+         
        }
+       
       }
+      
       // if no hitForRecCh1 found then consider to add hitForRecCh2 only
       if (!foundSecondHit) {
-        if (fgkTrackAllTracks) {
+        foundOneHit = kTRUE;
+        
+       if (fgkTrackAllTracks) {
          // copy trackCandidate into a new track put at the end of fRecTracksPtr and add the new hitForRec's
-          newTrack = new ((*fRecTracksPtr)[fRecTracksPtr->GetLast()+1]) AliMUONTrack(*trackCandidate);
+          newTrack = new ((*fRecTracksPtr)[fRecTracksPtr->GetLast()+1]) AliMUONTrack(trackCandidate);
+         UpdateTrack(*newTrack,extrapTrackParamAtHit2);
          fNRecTracks++;
-          AliMUONTrackParam trackParam1(extrapTrackParamSave);
-          AliMUONTrackExtrap::ExtrapToZ(&trackParam1, hitForRecCh2->GetZ());
-          newTrack->AddTrackParamAtHit(&trackParam1,hitForRecCh2);
-          // Sort TrackParamAtHit according to increasing Z
-          newTrack->GetTrackParamAtHit()->Sort();
-         // Update the chi2 of the new track
-         if (newTrack->GetFitFMin()<0) newTrack->SetFitFMin(chi2WithOneHitForRec);
-         else newTrack->SetFitFMin(newTrack->GetFitFMin() + chi2WithOneHitForRec);
+         
          // Printout for debuging
          if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructor") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
-           cout << "FollowTrackInStation: added one hit in chamber(1..): " << ch2+1
-                << " (Chi2 = " << chi2WithOneHitForRec << ")" << endl;
+           cout << "FollowTrackInStation: added one hit in chamber(1..): " << ch2+1 << endl;
            if (AliLog::GetGlobalDebugLevel() >= 3) newTrack->RecursiveDump();
          }
-       } if (!bestHitForRec2 && chi2WithOneHitForRec < bestChi2WithOneHitForRec) {
+         
+       } else if (!foundTwoHits && chi2WithOneHitForRec < bestChi2WithOneHitForRec) {
          // keep track of the best single hitForRec except if a couple
           // of hits has already been found (i.e. bestHitForRec2!=0x0)
          bestChi2WithOneHitForRec = chi2WithOneHitForRec;
-         bestHitForRec1 = hitForRecCh2;
+         bestTrackParamAtHit1 = extrapTrackParamAtHit2;
         }
+       
       }
+      
     }
-    // reset the extrapolated track parameter for next step
-    trackCandidate->SetExtrapTrackParam(&extrapTrackParamSave);
+    
   }
-  //
+  
   // look for candidates in chamber 1 not already attached to a track
   // if we want to keep all possible tracks or if no good couple of hitForRec has been found
-  if (fgkTrackAllTracks || !bestHitForRec2) {
+  if (fgkTrackAllTracks || !foundTwoHits) {
+    
+    // Printout for debuging
     if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructor") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
       cout << "FollowTrackInStation: look for single hits in chamber(1..): " << ch1+1 << endl;
     }
+    
+    // add MCS effect for next step
+    AliMUONTrackExtrap::AddMCSEffect(&extrapTrackParamAtCh2,AliMUONConstants::ChamberThicknessInX0(),1.);
+      
     for (Int_t hit1 = 0; hit1 < fNHitsForRecPerChamber[ch1]; hit1++) {
+      
       hitForRecCh1 = (AliMUONHitForRec*) fHitsForRecPtr->UncheckedAt(fIndexOfFirstHitForRecPerChamber[ch1]+hit1);
+      
       if (hitForRecCh1Used[hit1]) continue; // Skip hitForRec already used
-      chi2WithOneHitForRec = trackCandidate->TryOneHitForRec(hitForRecCh1);
-      // if good chi2 then create a new track by adding the good hitForRec in "ch1" to the "trackCandidate"
+      
+      // try to add the current hit
+      chi2WithOneHitForRec = TryOneHitForRec(extrapTrackParamAtCh2, hitForRecCh1, extrapTrackParamAtHit1);
+    
+      // if good chi2 then consider to add hitForRecCh1
       // We do not try to attach a hitForRec in the other chamber too since it has already been done above
       if (chi2WithOneHitForRec < maxChi2WithOneHitForRec) {
+        foundOneHit = kTRUE;
+         
+       // Printout for debuging
+       if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructor") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
+         cout << "FollowTrackInStation: found one hit in chamber(1..): " << ch1+1
+              << " (Chi2 = " << chi2WithOneHitForRec << ")" << endl;
+       }
+       
        if (fgkTrackAllTracks) {
          // copy trackCandidate into a new track put at the end of fRecTracksPtr and add the new hitForRec's
-         newTrack = new ((*fRecTracksPtr)[fRecTracksPtr->GetLast()+1]) AliMUONTrack(*trackCandidate);
+         newTrack = new ((*fRecTracksPtr)[fRecTracksPtr->GetLast()+1]) AliMUONTrack(trackCandidate);
+         UpdateTrack(*newTrack,extrapTrackParamAtHit1);
          fNRecTracks++;
-         AliMUONTrackParam trackParam1(extrapTrackParamSave);
-         AliMUONTrackExtrap::ExtrapToZ(&trackParam1, hitForRecCh1->GetZ());
-         newTrack->AddTrackParamAtHit(&trackParam1,hitForRecCh1);
-         // Sort TrackParamAtHit according to increasing Z
-         newTrack->GetTrackParamAtHit()->Sort();
-         // Update the chi2 of the new track
-         if (newTrack->GetFitFMin()<0) newTrack->SetFitFMin(chi2WithOneHitForRec);
-         else newTrack->SetFitFMin(newTrack->GetFitFMin() + chi2WithOneHitForRec);
-         // Printout for debuging
+         
+         // Printout for debuging
          if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructor") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
-           cout << "FollowTrackInStation: added one hit in chamber(1..): " << ch1+1
-                << " (Chi2 = " << chi2WithOneHitForRec << ")" << endl;
+           cout << "FollowTrackInStation: added one hit in chamber(1..): " << ch1+1 << endl;
            if (AliLog::GetGlobalDebugLevel() >= 3) newTrack->RecursiveDump();
          }
-       } if (!bestHitForRec2 && chi2WithOneHitForRec < bestChi2WithOneHitForRec) {
+         
+       } else if (chi2WithOneHitForRec < bestChi2WithOneHitForRec) {
          // keep track of the best single hitForRec except if a couple
          // of hits has already been found (i.e. bestHitForRec1!=0x0)
          bestChi2WithOneHitForRec = chi2WithOneHitForRec;
-         bestHitForRec1 = hitForRecCh1;
+         bestTrackParamAtHit1 = extrapTrackParamAtHit1;
        }
+       
       }
+      
     }
+    
   }
-  //
+  
   // fill out the best track if required else clean up the fRecTracksPtr array
-  if (!fgkTrackAllTracks && bestHitForRec1) {
-    AliMUONTrackParam trackParam1(extrapTrackParamSave);
-    AliMUONTrackExtrap::ExtrapToZ(&trackParam1, bestHitForRec1->GetZ());
-    trackCandidate->AddTrackParamAtHit(&trackParam1,bestHitForRec1);
-    if (bestHitForRec2) {
-      AliMUONTrackParam trackParam2(extrapTrackParamSave);
-      AliMUONTrackExtrap::ExtrapToZ(&trackParam2, bestHitForRec2->GetZ());
-      trackCandidate->AddTrackParamAtHit(&trackParam2,bestHitForRec2);
-      // Sort TrackParamAtHit according to increasing Z
-      trackCandidate->GetTrackParamAtHit()->Sort();
-      // Update the chi2 of the new track
-      if (trackCandidate->GetFitFMin()<0) trackCandidate->SetFitFMin(bestChi2WithTwoHitForRec);
-      else trackCandidate->SetFitFMin(trackCandidate->GetFitFMin() + bestChi2WithTwoHitForRec);
+  if (!fgkTrackAllTracks) {
+    if (foundTwoHits) {
+      UpdateTrack(trackCandidate,bestTrackParamAtHit1,bestTrackParamAtHit2);
+      
       // Printout for debuging
       if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructor") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
-        cout << "FollowTrackInStation: added the two best hits in station(1..): " << nextStation+1
-             << " (Chi2 = " << bestChi2WithTwoHitForRec << ")" << endl;
+        cout << "FollowTrackInStation: added the two best hits in station(1..): " << nextStation+1 << endl;
         if (AliLog::GetGlobalDebugLevel() >= 3) newTrack->RecursiveDump();
       }
-    } else {
-      // Sort TrackParamAtHit according to increasing Z
-      trackCandidate->GetTrackParamAtHit()->Sort();
-      // Update the chi2 of the new track
-      if (trackCandidate->GetFitFMin()<0) trackCandidate->SetFitFMin(bestChi2WithOneHitForRec);
-      else trackCandidate->SetFitFMin(trackCandidate->GetFitFMin() + bestChi2WithOneHitForRec);
+      
+    } else if (foundOneHit) {
+      UpdateTrack(trackCandidate,bestTrackParamAtHit1);
+      
       // Printout for debuging
       if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructor") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
-        cout << "FollowTrackInStation: added the best hit in station(1..): " << nextStation+1
-             << " (Chi2 = " << bestChi2WithOneHitForRec << ")" << endl;
+        cout << "FollowTrackInStation: added the best hit in chamber(1..): " << bestTrackParamAtHit1.GetHitForRecPtr()->GetChamberNumber()+1 << endl;
         if (AliLog::GetGlobalDebugLevel() >= 3) newTrack->RecursiveDump();
       }
+      
+    } else return kFALSE;
+    
+  } else if (foundOneHit || foundTwoHits) {
+    
+    // remove obsolete track
+    fRecTracksPtr->Remove(&trackCandidate);
+    fNRecTracks--;
+    
+  } else return kFALSE;
+  
+  return kTRUE;
+  
+}
+
+  //__________________________________________________________________________
+Double_t AliMUONTrackReconstructor::TryTwoHitForRec(const AliMUONTrackParam &trackParamAtHit1, AliMUONHitForRec* hitForRec2, AliMUONTrackParam &trackParamAtHit2)
+{
+/// Test the compatibility between the track and the 2 hitForRec together (using trackParam's covariance matrix):
+/// return the corresponding Chi2 accounting for covariances between the 2 hitForRec
+/// return trackParamAtHit1 & 2
+  
+  if (!trackParamAtHit1.CovariancesExist()) AliWarning(" track parameter covariance matrix does not exist");
+  AliMUONHitForRec* hitForRec1 = trackParamAtHit1.GetHitForRecPtr();
+  if (!hitForRec1) AliFatal(" no hitForRec attached to trackParamAtHit1");
+  
+  // extrapolate track parameters at the z position of the second hit
+  trackParamAtHit2.SetParameters(trackParamAtHit1.GetParameters());
+  trackParamAtHit2.SetZ(trackParamAtHit1.GetZ());
+  AliMUONTrackExtrap::ExtrapToZ(&trackParamAtHit2, hitForRec2->GetZ());
+  
+  // set pointer to hit2 into trackParamAtHit2
+  trackParamAtHit2.SetHitForRecPtr(hitForRec2);
+  
+  // Set differences between track and the 2 hitForRec in the bending and non bending directions
+  TMatrixD dPos(4,1);
+  dPos(0,0) = hitForRec1->GetNonBendingCoor() - trackParamAtHit1.GetNonBendingCoor();
+  dPos(1,0) = hitForRec1->GetBendingCoor() - trackParamAtHit1.GetBendingCoor();
+  dPos(2,0) = hitForRec2->GetNonBendingCoor() - trackParamAtHit2.GetNonBendingCoor();
+  dPos(3,0) = hitForRec2->GetBendingCoor() - trackParamAtHit2.GetBendingCoor();
+  
+  // quick tests of hitForRec compatibility within a wide road of x*y = 1*1 cm2 to save computing time
+  if (TMath::Abs(dPos(0,0)) > fgkMaxTrackingDistanceNonBending ||
+      TMath::Abs(dPos(1,0)) > fgkMaxTrackingDistanceBending    ||
+      TMath::Abs(dPos(2,0)) > fgkMaxTrackingDistanceNonBending ||
+      TMath::Abs(dPos(3,0)) > fgkMaxTrackingDistanceBending) return 1.e10;
+  
+  // Calculate the error matrix from the track parameter covariances at first hitForRec
+  TMatrixD error(4,4);
+  error.Zero();
+  if (trackParamAtHit1.CovariancesExist()) {
+    // Save track parameters at first hitForRec
+    AliMUONTrackParam trackParamAtHit1Save(trackParamAtHit1);
+    TMatrixD paramAtHit1Save(trackParamAtHit1Save.GetParameters());
+    Double_t z1 = trackParamAtHit1Save.GetZ();
+    
+    // Save track coordinates at second hitForRec
+    Double_t nonBendingCoor2        = trackParamAtHit2.GetNonBendingCoor();
+    Double_t bendingCoor2           = trackParamAtHit2.GetBendingCoor();
+    
+    // add MCS effect at first hitForRec
+    AliMUONTrackExtrap::AddMCSEffect(&trackParamAtHit1Save,AliMUONConstants::ChamberThicknessInX0(),1.);
+    
+    // Get the pointer to the parameter covariance matrix at first hitForRec
+    const TMatrixD& kParamCov = trackParamAtHit1Save.GetCovariances();
+    
+    // Calculate the jacobian related to the transformation between track parameters
+    // at first hitForRec and track coordinates at the 2 hitForRec z-position
+    TMatrixD jacob(4,5);
+    jacob.Zero();
+    // first derivative at the first hitForRec:
+    jacob(0,0) = 1.; // dx1/dx
+    jacob(1,2) = 1.; // dy1/dy
+    // first derivative at the second hitForRec:
+    TMatrixD dParam(5,1);
+    for (Int_t i=0; i<5; i++) {
+      // Skip jacobian calculation for parameters with no associated error
+      if (kParamCov(i,i) == 0.) continue;
+      // Small variation of parameter i only
+      for (Int_t j=0; j<5; j++) {
+        if (j==i) {
+          dParam(j,0) = TMath::Sqrt(kParamCov(i,i));
+         if (j == 4) dParam(j,0) *= TMath::Sign(1.,-paramAtHit1Save(4,0)); // variation always in the same direction
+        } else dParam(j,0) = 0.;
+      }
+      
+      // Set new track parameters at first hitForRec
+      trackParamAtHit1Save.SetParameters(paramAtHit1Save);
+      trackParamAtHit1Save.AddParameters(dParam);
+      trackParamAtHit1Save.SetZ(z1);
+      
+      // Extrapolate new track parameters to the z position of the second hitForRec
+      AliMUONTrackExtrap::ExtrapToZ(&trackParamAtHit1Save,hitForRec2->GetZ());
+      
+      // Calculate the jacobian
+      jacob(2,i) = (trackParamAtHit1Save.GetNonBendingCoor()  - nonBendingCoor2) / dParam(i,0); // dx2/dParami
+      jacob(3,i) = (trackParamAtHit1Save.GetBendingCoor()     - bendingCoor2   ) / dParam(i,0); // dy2/dParami
     }
+    
+    // Calculate the error matrix
+    TMatrixD tmp(jacob,TMatrixD::kMult,kParamCov);
+    error = TMatrixD(tmp,TMatrixD::kMultTranspose,jacob);
+  }
+  
+  // Add hitForRec resolution to the error matrix
+  error(0,0) += hitForRec1->GetNonBendingReso2();
+  error(1,1) += hitForRec1->GetBendingReso2();
+  error(2,2) += hitForRec2->GetNonBendingReso2();
+  error(3,3) += hitForRec2->GetBendingReso2();
+  
+  // invert the error matrix for Chi2 calculation
+  if (error.Determinant() != 0) {
+    error.Invert();
   } else {
-    fRecTracksPtr->Remove(trackCandidate); // obsolete track
-    fNRecTracks--;
+    AliWarning(" Determinant error=0");
+    return 1.e10;
   }
   
+  // Compute the Chi2 value
+  TMatrixD tmp2(dPos,TMatrixD::kTransposeMult,error);
+  TMatrixD result(tmp2,TMatrixD::kMult,dPos);
+  
+  return result(0,0);
+  
+}
+
+  //__________________________________________________________________________
+void AliMUONTrackReconstructor::UpdateTrack(AliMUONTrack &track, AliMUONTrackParam &trackParamAtHit)
+{
+  /// Add 1 hit to the track candidate
+  /// Update chi2 of the track 
+  
+  // Compute local chi2
+  AliMUONHitForRec* hit = trackParamAtHit.GetHitForRecPtr();
+  Double_t deltaX = trackParamAtHit.GetNonBendingCoor() - hit->GetNonBendingCoor();
+  Double_t deltaY = trackParamAtHit.GetBendingCoor() - hit->GetBendingCoor();
+  Double_t localChi2 = deltaX*deltaX / hit->GetNonBendingReso2() +
+                      deltaY*deltaY / hit->GetBendingReso2();
+  
+  // Update the chi2 of the new track
+  track.SetFitFMin(track.GetFitFMin() + localChi2);
+  
+  // Update TrackParamAtHit
+  track.AddTrackParamAtHit(&trackParamAtHit,trackParamAtHit.GetHitForRecPtr());
+  track.GetTrackParamAtHit()->Sort();
+  
 }
 
   //__________________________________________________________________________
-void AliMUONTrackReconstructor::SetVertexForFit(AliMUONTrack* trackCandidate)
+void AliMUONTrackReconstructor::UpdateTrack(AliMUONTrack &track, AliMUONTrackParam &trackParamAtHit1, AliMUONTrackParam &trackParamAtHit2)
+{
+  /// Add 2 hits to the track candidate
+  /// Update track and local chi2
+  
+  // Update local chi2 at first hit
+  AliMUONHitForRec* hit1 = trackParamAtHit1.GetHitForRecPtr();
+  Double_t deltaX = trackParamAtHit1.GetNonBendingCoor() - hit1->GetNonBendingCoor();
+  Double_t deltaY = trackParamAtHit1.GetBendingCoor() - hit1->GetBendingCoor();
+  Double_t localChi2AtHit1 = deltaX*deltaX / hit1->GetNonBendingReso2() +
+                            deltaY*deltaY / hit1->GetBendingReso2();
+  trackParamAtHit1.SetLocalChi2(localChi2AtHit1);
+  
+  // Flag first hit as being removable
+  trackParamAtHit1.SetRemovable(kTRUE);
+  
+  // Update local chi2 at second hit
+  AliMUONHitForRec* hit2 = trackParamAtHit2.GetHitForRecPtr();
+  deltaX = trackParamAtHit2.GetNonBendingCoor() - hit2->GetNonBendingCoor();
+  deltaY = trackParamAtHit2.GetBendingCoor() - hit2->GetBendingCoor();
+  Double_t localChi2AtHit2 = deltaX*deltaX / hit2->GetNonBendingReso2() +
+                            deltaY*deltaY / hit2->GetBendingReso2();
+  trackParamAtHit2.SetLocalChi2(localChi2AtHit2);
+  
+  // Flag first hit as being removable
+  trackParamAtHit2.SetRemovable(kTRUE);
+  
+  // Update the chi2 of the new track
+  track.SetFitFMin(track.GetFitFMin() + localChi2AtHit1 + localChi2AtHit2);
+  
+  // Update TrackParamAtHit
+  track.AddTrackParamAtHit(&trackParamAtHit1,trackParamAtHit1.GetHitForRecPtr());
+  track.AddTrackParamAtHit(&trackParamAtHit2,trackParamAtHit2.GetHitForRecPtr());
+  track.GetTrackParamAtHit()->Sort();
+  
+}
+
+  //__________________________________________________________________________
+Bool_t AliMUONTrackReconstructor::RecoverTrack(AliMUONTrack &trackCandidate, Int_t nextStation)
+{
+  /// Try to recover the track candidate in the next station
+  /// by removing the worst of the two hits attached in the current station
+  /// Return kTRUE if recovering succeeds
+  AliDebug(1,"Enter RecoverTrack");
+  
+  // Do not try to recover track until we have attached hit(s) on station(1..) 3
+  if (nextStation > 1) return kFALSE;
+  
+  Int_t worstHitNumber = -1;
+  Double_t localChi2, worstLocalChi2 = 0.;
+  
+  // Look for the hit to remove
+  for (Int_t hitNumber = 0; hitNumber < 2; hitNumber++) {
+    AliMUONTrackParam *trackParamAtHit = (AliMUONTrackParam*)trackCandidate.GetTrackParamAtHit()->UncheckedAt(hitNumber);
+    
+    // check if current hit is removable
+    if (!trackParamAtHit->IsRemovable()) return kFALSE;
+    
+    // Pick up hit with the worst chi2
+    localChi2 = trackParamAtHit->GetLocalChi2();
+    if (localChi2 > worstLocalChi2) {
+      worstLocalChi2 = localChi2;
+      worstHitNumber = hitNumber;
+    }
+  }
+  
+  // Reset best hit as being NOT removable
+  ((AliMUONTrackParam*)trackCandidate.GetTrackParamAtHit()->UncheckedAt((worstHitNumber+1)%2))->SetRemovable(kFALSE);
+  
+  // Remove the worst hit
+  trackCandidate.RemoveTrackParamAtHit((AliMUONTrackParam*)trackCandidate.GetTrackParamAtHit()->UncheckedAt(worstHitNumber));
+  
+  // Re-fit the track:
+  // Do not take into account the multiple scattering to speed up the fit
+  // Calculate the track parameter covariance matrix
+  trackCandidate.SetFitWithVertex(kFALSE); // To be sure
+  Fit(trackCandidate, kFALSE, kTRUE);
+  
+  // Look for new hit(s) in next station
+  return FollowTrackInStation(trackCandidate,nextStation);
+  
+}
+
+  //__________________________________________________________________________
+void AliMUONTrackReconstructor::SetVertexForFit(AliMUONTrack &trackCandidate)
 {
   /// Add the vertex as a measured hit to constrain the fit of the "trackCandidate"
   /// Compute the vertex resolution from natural vertex dispersion and
@@ -538,26 +703,26 @@ void AliMUONTrackReconstructor::SetVertexForFit(AliMUONTrack* trackCandidate)
   /// the "trackCandidate" to do not influence the result by changing track resolution at vertex
   AliDebug(1,"Enter SetVertexForFit");
   
-  Double_t nonBendingReso2 = fNonBendingVertexDispersion * fNonBendingVertexDispersion;
-  Double_t bendingReso2 = fBendingVertexDispersion * fBendingVertexDispersion;
+  Double_t nonBendingReso2 = fgkNonBendingVertexDispersion * fgkNonBendingVertexDispersion;
+  Double_t bendingReso2 = fgkBendingVertexDispersion * fgkBendingVertexDispersion;
   // add multiple scattering effets
-  AliMUONTrackParam paramAtVertex(*((AliMUONTrackParam*)(trackCandidate->GetTrackParamAtHit()->First())));
+  AliMUONTrackParam paramAtVertex(*((AliMUONTrackParam*)(trackCandidate.GetTrackParamAtHit()->First())));
   paramAtVertex.DeleteCovariances(); // to be sure to account only for multiple scattering
   AliMUONTrackExtrap::ExtrapToVertexUncorrected(&paramAtVertex,0.);
-  TMatrixD* paramCov = paramAtVertex.GetCovariances();
-  nonBendingReso2 += (*paramCov)(0,0);
-  bendingReso2 += (*paramCov)(2,2);
+  const TMatrixD& kParamCov = paramAtVertex.GetCovariances();
+  nonBendingReso2 += kParamCov(0,0);
+  bendingReso2 += kParamCov(2,2);
   // Set the vertex
   AliMUONHitForRec vertex; // Coordinates set to (0.,0.,0.) by default
   vertex.SetNonBendingReso2(nonBendingReso2);
   vertex.SetBendingReso2(bendingReso2);
-  trackCandidate->SetVertex(&vertex);
+  trackCandidate.SetVertex(&vertex);
 }
 
   //__________________________________________________________________________
-void AliMUONTrackReconstructor::Fit(AliMUONTrack *track, Bool_t includeMCS, Bool_t calcCov)
+void AliMUONTrackReconstructor::Fit(AliMUONTrack &track, Bool_t includeMCS, Bool_t calcCov)
 {
-  /// Fit the track "track" with or without multiple Coulomb scattering according to "includeMCS".
+  /// Fit the track "track" w/wo multiple Coulomb scattering according to "includeMCS".
   
   Double_t benC, errorParam, invBenP, nonBenC, x, y;
   AliMUONTrackParam *trackParam;
@@ -570,7 +735,7 @@ void AliMUONTrackReconstructor::Fit(AliMUONTrack *track, Bool_t includeMCS, Bool
   // Clear MINUIT parameters
   gMinuit->mncler();
   // Give the fitted track to MINUIT
-  gMinuit->SetObjectFit(track);
+  gMinuit->SetObjectFit(&track);
   if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructor") >= 2) || (AliLog::GetGlobalDebugLevel() >= 2)) {
     // Define print level
     arg[0] = 1;
@@ -587,12 +752,21 @@ void AliMUONTrackReconstructor::Fit(AliMUONTrack *track, Bool_t includeMCS, Bool
   //arg[0] = 2;
   //gMinuit->mnexcm("SET STR", arg, 1, status);
   
-  // Switch between available FCN according to "includeMCS"
-  if (includeMCS) gMinuit->SetFCN(TrackChi2MCS);
-  else gMinuit->SetFCN(TrackChi2);
+  // set flag w/wo multiple scattering according to "includeMCS"
+  track.SetFitWithMCS(includeMCS);
+  if (includeMCS) {
+    // compute hit weights only once
+    if (!track.ComputeHitWeights()) {
+      AliWarning("cannot take into account the multiple scattering effects");
+      track.SetFitWithMCS(kFALSE);
+    }
+  }
+  
+  // Set fitting function
+  gMinuit->SetFCN(TrackChi2);
   
   // Set fitted parameters (!! The order is very important for the covariance matrix !!)
-  trackParam = (AliMUONTrackParam*) (track->GetTrackParamAtHit()->First());
+  trackParam = (AliMUONTrackParam*) (track.GetTrackParamAtHit()->First());
   // could be tried with no limits for the search (min=max=0) ????
   // mandatory limits in non Bending to avoid NaN values of parameters
   gMinuit->mnparm(0, "X", trackParam->GetNonBendingCoor(), 0.03, -500.0, 500.0, status);
@@ -622,7 +796,7 @@ void AliMUONTrackReconstructor::Fit(AliMUONTrack *track, Bool_t includeMCS, Bool
   
   // global result of the fit
   gMinuit->mnstat(fitFMin, fedm, errdef, npari, nparx, covStatus);
-  track->SetFitFMin(fitFMin);
+  track.SetFitFMin(fitFMin);
   
   // Get the covariance matrix if required
   if (calcCov) {
@@ -632,39 +806,35 @@ void AliMUONTrackReconstructor::Fit(AliMUONTrack *track, Bool_t includeMCS, Bool
     gMinuit->mnemat(&matrix[0][0],5);
     if (covStatus == 3) trackParam->SetCovariances(matrix);
     else trackParam->SetVariances(matrix);
-  } else *(trackParam->GetCovariances()) = 0;
+  } else trackParam->DeleteCovariances();
   
 }
 
   //__________________________________________________________________________
-void TrackChi2(Int_t & /*NParam*/, Double_t * /*Gradient*/, Double_t &Chi2, Double_t *Param, Int_t /*Flag*/)
+void TrackChi2(Int_t & /*nParam*/, Double_t * /*gradient*/, Double_t &chi2, Double_t *param, Int_t /*flag*/)
 {
-  /// Return the "Chi2" to be minimized with Minuit for track fitting,
-  /// with "NParam" parameters
-  /// and their current values in array pointed to by "Param".
+  /// Return the "Chi2" to be minimized with Minuit for track fitting.
   /// Assumes that the track hits are sorted according to increasing Z.
   /// Track parameters at each TrackHit are updated accordingly.
-  /// Multiple Coulomb scattering is not taken into account
+  /// Vertex is used according to the flag "trackBeingFitted->GetFitWithVertex()".
+  /// Multiple Coulomb scattering is taken into account according to the flag "trackBeingFitted->GetFitWithMCS()".
   
   AliMUONTrack *trackBeingFitted = (AliMUONTrack*) gMinuit->GetObjectFit();
-//  AliMUONTrack *trackBeingFitted = (AliMUONTrack*) AliMUONTrackReconstructor::Fitter()->GetObjectFit();
-  AliMUONTrackParam param1;
-  AliMUONTrackParam* trackParamAtHit;
-  AliMUONHitForRec* hitForRec;
-  Chi2 = 0.0; // initialize Chi2
+  AliMUONTrackParam* trackParamAtHit = (AliMUONTrackParam*) trackBeingFitted->GetTrackParamAtHit()->First();
   Double_t dX, dY;
+  chi2 = 0.; // initialize chi2
   
-  // copy of track parameters to be fitted
-  param1 = *((AliMUONTrackParam*) (trackBeingFitted->GetTrackParamAtHit()->First()));
-  param1.SetNonBendingCoor(Param[0]);
-  param1.SetNonBendingSlope(Param[1]);
-  param1.SetBendingCoor(Param[2]);
-  param1.SetBendingSlope(Param[3]);
-  param1.SetInverseBendingMomentum(Param[4]);
+  // update track parameters
+  trackParamAtHit->SetNonBendingCoor(param[0]);
+  trackParamAtHit->SetNonBendingSlope(param[1]);
+  trackParamAtHit->SetBendingCoor(param[2]);
+  trackParamAtHit->SetBendingSlope(param[3]);
+  trackParamAtHit->SetInverseBendingMomentum(param[4]);
+  trackBeingFitted->UpdateTrackParamAtHit();
   
   // Take the vertex into account in the fit if required
   if (trackBeingFitted->GetFitWithVertex()) {
-    AliMUONTrackParam paramAtVertex(param1);
+    AliMUONTrackParam paramAtVertex(*trackParamAtHit);
     AliMUONTrackExtrap::ExtrapToZ(&paramAtVertex, 0.);
     AliMUONHitForRec *vertex = trackBeingFitted->GetVertex();
     if (!vertex) {
@@ -673,295 +843,127 @@ void TrackChi2(Int_t & /*NParam*/, Double_t * /*Gradient*/, Double_t &Chi2, Doub
     }
     dX = vertex->GetNonBendingCoor() - paramAtVertex.GetNonBendingCoor();
     dY = vertex->GetBendingCoor() - paramAtVertex.GetBendingCoor();
-    Chi2 += dX * dX / vertex->GetNonBendingReso2() + dY * dY / vertex->GetBendingReso2();
+    chi2 += dX * dX / vertex->GetNonBendingReso2() + dY * dY / vertex->GetBendingReso2();
   }
   
-  // Follow track through all planes of track hits
-  trackParamAtHit = (AliMUONTrackParam*) (trackBeingFitted->GetTrackParamAtHit()->First());
-  while (trackParamAtHit) {
-    hitForRec = trackParamAtHit->GetHitForRecPtr();
-    // extrapolation to the plane of the hitForRec attached to the current trackParamAtHit
-    AliMUONTrackExtrap::ExtrapToZ(&param1, hitForRec->GetZ());
-    // update track parameters of the current hit
-    trackParamAtHit->SetTrackParam(param1);
-    // Increment Chi2
-    // done hit per hit, with hit resolution,
-    // and not with point and angle like in "reco_muon.F" !!!!
-    dX = hitForRec->GetNonBendingCoor() - param1.GetNonBendingCoor();
-    dY = hitForRec->GetBendingCoor() - param1.GetBendingCoor();
-    Chi2 = Chi2 + dX * dX / hitForRec->GetNonBendingReso2() + dY * dY / hitForRec->GetBendingReso2();
-    trackParamAtHit = (AliMUONTrackParam*) (trackBeingFitted->GetTrackParamAtHit()->After(trackParamAtHit));
-  }
+  // compute chi2 w/wo multiple scattering
+  if (trackBeingFitted->GetFitWithMCS()) chi2 += trackBeingFitted->ComputeGlobalChi2(kTRUE);
+  else chi2 += trackBeingFitted->ComputeGlobalChi2(kFALSE);
+  
 }
 
   //__________________________________________________________________________
-void TrackChi2MCS(Int_t & /*NParam*/, Double_t * /*Gradient*/, Double_t &Chi2, Double_t *Param, Int_t /*Flag*/)
+void AliMUONTrackReconstructor::ImproveTracks()
 {
-  /// Return the "Chi2" to be minimized with Minuit for track fitting,
-  /// with "NParam" parameters
-  /// and their current values in array pointed to by "Param".
-  /// Assumes that the track hits are sorted according to increasing Z.
-  /// Track parameters at each TrackHit are updated accordingly.
-  /// Multiple Coulomb scattering is taken into account with covariance matrix.
+  /// Improve tracks by removing clusters with local chi2 highter than the defined cut
+  /// Recompute track parameters and covariances at the remaining clusters
+  AliDebug(1,"Enter ImproveTracks");
   
-  AliMUONTrack *trackBeingFitted = (AliMUONTrack*) gMinuit->GetObjectFit();
-//  AliMUONTrack *trackBeingFitted = (AliMUONTrack*) AliMUONTrackReconstructor::Fitter()->GetObjectFit();
-  AliMUONTrackParam param1;
-  AliMUONTrackParam* trackParamAtHit;
-  AliMUONHitForRec* hitForRec;
-  Chi2 = 0.0; // initialize Chi2
-  Int_t chCurrent, chPrev = 0, hitNumber, hitNumber1, hitNumber2, hitNumber3;
-  Double_t z1, z2, z3;
-  AliMUONTrackParam *trackParamAtHit1, *trackParamAtHit2, *trackParamAtHit3;
-  AliMUONHitForRec *hitForRec1, *hitForRec2;
-  Double_t hbc1, hbc2, pbc1, pbc2;
-  Double_t hnbc1, hnbc2, pnbc1, pnbc2;
-  Int_t numberOfHit = trackBeingFitted->GetNTrackHits();
-  TMatrixD *covBending = new TMatrixD(numberOfHit, numberOfHit);
-  TMatrixD *covNonBending = new TMatrixD(numberOfHit, numberOfHit);
-  Double_t *msa2 = new Double_t[numberOfHit];
-  
-  // copy of track parameters to be fitted
-  param1 = *((AliMUONTrackParam*) (trackBeingFitted->GetTrackParamAtHit()->First()));
-  param1.SetNonBendingCoor(Param[0]);
-  param1.SetNonBendingSlope(Param[1]);
-  param1.SetBendingCoor(Param[2]);
-  param1.SetBendingSlope(Param[3]);
-  param1.SetInverseBendingMomentum(Param[4]);
-
-  // Take the vertex into account in the fit if required
-  if (trackBeingFitted->GetFitWithVertex()) {
-    AliMUONTrackParam paramAtVertex(param1);
-    AliMUONTrackExtrap::ExtrapToZ(&paramAtVertex, 0.);
-    AliMUONHitForRec *vertex = trackBeingFitted->GetVertex();
-    if (!vertex) {
-      cout<<"Error in TrackChi2MCS: Want to use the vertex in tracking but it has not been created!!"<<endl;
-      exit(-1);
-    }
-    Double_t dX = vertex->GetNonBendingCoor() - paramAtVertex.GetNonBendingCoor();
-    Double_t dY = vertex->GetBendingCoor() - paramAtVertex.GetBendingCoor();
-    Chi2 += dX * dX / vertex->GetNonBendingReso2() + dY * dY / vertex->GetBendingReso2();
-  }
+  Double_t localChi2, worstLocalChi2;
+  Int_t worstChamber;
+  AliMUONTrackParam *trackParamAtHit, *worstTrackParamAtHit;
   
-  // Predicted coordinates and multiple scattering angles are first calculated
-  for (hitNumber = 0; hitNumber < numberOfHit; hitNumber++) {
-    trackParamAtHit = (AliMUONTrackParam*) (trackBeingFitted->GetTrackParamAtHit()->UncheckedAt(hitNumber));
-    hitForRec = trackParamAtHit->GetHitForRecPtr();
-    // extrapolation to the plane of the hitForRec attached to the current trackParamAtHit
-    AliMUONTrackExtrap::ExtrapToZ(&param1, hitForRec->GetZ());
-    // update track parameters of the current hit
-    trackParamAtHit->SetTrackParam(param1);
-    // square of multiple scattering angle at current hit, with one chamber
-    msa2[hitNumber] = MultipleScatteringAngle2(&param1);
-    // correction for eventual missing hits or multiple hits in a chamber,
-    // according to the number of chambers
-    // between the current hit and the previous one
-    chCurrent = hitForRec->GetChamberNumber();
-    if (hitNumber > 0) msa2[hitNumber] = msa2[hitNumber] * (chCurrent - chPrev);
-    chPrev = chCurrent;
-  }
-
-  // Calculates the covariance matrix
-  for (hitNumber1 = 0; hitNumber1 < numberOfHit; hitNumber1++) { 
-    trackParamAtHit1 = (AliMUONTrackParam*) (trackBeingFitted->GetTrackParamAtHit()->UncheckedAt(hitNumber1));
-    hitForRec1 = trackParamAtHit1->GetHitForRecPtr();
-    z1 = hitForRec1->GetZ();
-    for (hitNumber2 = hitNumber1; hitNumber2 < numberOfHit; hitNumber2++) {
-      trackParamAtHit2 = (AliMUONTrackParam*) (trackBeingFitted->GetTrackParamAtHit()->UncheckedAt(hitNumber2));
-      z2 = trackParamAtHit2->GetHitForRecPtr()->GetZ();
-      // initialization to 0 (diagonal plus upper triangular part)
-      (*covBending)(hitNumber2, hitNumber1) = 0.0;
-      // contribution from multiple scattering in bending plane:
-      // loop over upstream hits
-      for (hitNumber3 = 0; hitNumber3 < hitNumber1; hitNumber3++) {    
-        trackParamAtHit3 = (AliMUONTrackParam*) (trackBeingFitted->GetTrackParamAtHit()->UncheckedAt(hitNumber3));
-       z3 = trackParamAtHit3->GetHitForRecPtr()->GetZ();
-       (*covBending)(hitNumber2, hitNumber1) = (*covBending)(hitNumber2, hitNumber1) + ((z1 - z3) * (z2 - z3) * msa2[hitNumber3]); 
+  // Remove double track to improve only "good" tracks
+  RemoveDoubleTracks();
+  
+  AliMUONTrack *track = (AliMUONTrack*) fRecTracksPtr->First();
+  while (track) {
+    
+    while (!track->IsImproved()) {
+      
+      // Update track parameters and covariances
+      track->UpdateCovTrackParamAtHit();
+      
+      // Compute local chi2 of each hits
+      track->ComputeLocalChi2(kTRUE);
+      
+      // Look for the hit to remove
+      worstTrackParamAtHit = 0;
+      worstLocalChi2 = 0.;
+      trackParamAtHit = (AliMUONTrackParam*) track->GetTrackParamAtHit()->First();
+      while (trackParamAtHit) {
+        
+        // Pick up hit with the worst chi2
+        localChi2 = trackParamAtHit->GetLocalChi2();
+        if (localChi2 > worstLocalChi2) {
+          worstLocalChi2 = localChi2;
+          worstTrackParamAtHit = trackParamAtHit;
+        }
+        
+      trackParamAtHit = (AliMUONTrackParam*) track->GetTrackParamAtHit()->After(trackParamAtHit);
       }
-      // equal contribution from multiple scattering in non bending plane
-      (*covNonBending)(hitNumber2, hitNumber1) = (*covBending)(hitNumber2, hitNumber1);
-      if (hitNumber1 == hitNumber2) {
-       // Diagonal elements: add contribution from position measurements
-       // in bending plane
-       (*covBending)(hitNumber2, hitNumber1) = (*covBending)(hitNumber2, hitNumber1) + hitForRec1->GetBendingReso2();
-       // and in non bending plane
-       (*covNonBending)(hitNumber2, hitNumber1) = (*covNonBending)(hitNumber2, hitNumber1) + hitForRec1->GetNonBendingReso2();
-      } else {
-       // Non diagonal elements: symmetrization
-       // for bending plane
-       (*covBending)(hitNumber1, hitNumber2) = (*covBending)(hitNumber2, hitNumber1);
-       // and non bending plane
-       (*covNonBending)(hitNumber1, hitNumber2) = (*covNonBending)(hitNumber2, hitNumber1);
+      
+      // Check if bad hit found
+      if (!worstTrackParamAtHit) {
+        track->SetImproved(kTRUE);
+        break;
       }
-    } // for (hitNumber2 = hitNumber1;...
-  } // for (hitNumber1 = 0;...
-    
-  // Inversion of covariance matrices
-  Int_t ifailBending;
-  gMinuit->mnvert(&((*covBending)(0,0)), numberOfHit, numberOfHit, numberOfHit, ifailBending);
-  Int_t ifailNonBending;
-  gMinuit->mnvert(&((*covNonBending)(0,0)), numberOfHit, numberOfHit, numberOfHit, ifailNonBending);
-
-  // It would be worth trying to calculate the inverse of the covariance matrix
-  // only once per fit, since it cannot change much in principle,
-  // and it would save a lot of computing time !!!!
-  
-  // Calculates Chi2
-  if ((ifailBending == 0) && (ifailNonBending == 0)) {
-    // with Multiple Scattering if inversion correct
-    for (hitNumber1 = 0; hitNumber1 < numberOfHit ; hitNumber1++) { 
-      trackParamAtHit1 = (AliMUONTrackParam*) (trackBeingFitted->GetTrackParamAtHit()->UncheckedAt(hitNumber1));
-      hitForRec1 = trackParamAtHit1->GetHitForRecPtr();
-      hbc1 = hitForRec1->GetBendingCoor();
-      pbc1 = trackParamAtHit1->GetBendingCoor();
-      hnbc1 = hitForRec1->GetNonBendingCoor();
-      pnbc1 = trackParamAtHit1->GetNonBendingCoor();
-      for (hitNumber2 = 0; hitNumber2 < numberOfHit; hitNumber2++) {
-       trackParamAtHit2 = (AliMUONTrackParam*) (trackBeingFitted->GetTrackParamAtHit()->UncheckedAt(hitNumber2));
-        hitForRec2 = trackParamAtHit2->GetHitForRecPtr();
-       hbc2 = hitForRec2->GetBendingCoor();
-       pbc2 = trackParamAtHit2->GetBendingCoor();
-       hnbc2 = hitForRec2->GetNonBendingCoor();
-       pnbc2 = trackParamAtHit2->GetNonBendingCoor();
-       Chi2 += ((*covBending)(hitNumber2, hitNumber1) * (hbc1 - pbc1) * (hbc2 - pbc2)) +
-               ((*covNonBending)(hitNumber2, hitNumber1) * (hnbc1 - pnbc1) * (hnbc2 - pnbc2));
+      
+      // check whether the worst hit is removable or not
+      if (!worstTrackParamAtHit->IsRemovable()) {
+        track->SetImproved(kTRUE);
+        break;
       }
+      
+      // Check whether the worst chi2 is under requirement or not
+      if (worstLocalChi2 < 2. * fgkSigmaToCutForImprovement * fgkSigmaToCutForImprovement) { // 2 because 2 quantities in chi2
+        track->SetImproved(kTRUE);
+        break;
+      }
+      
+      // Reset the second hit in the same station as the bad one as being NOT removable
+      worstChamber = worstTrackParamAtHit->GetHitForRecPtr()->GetChamberNumber();
+      if (worstChamber%2 == 0) ((AliMUONTrackParam*)track->GetTrackParamAtHit()->After(worstTrackParamAtHit))->SetRemovable(kFALSE);
+      else ((AliMUONTrackParam*)track->GetTrackParamAtHit()->Before(worstTrackParamAtHit))->SetRemovable(kFALSE);
+      
+      // Remove the worst hit
+      track->RemoveTrackParamAtHit(worstTrackParamAtHit);
+      
+      // Re-fit the track:
+      // Take into account the multiple scattering
+      // Calculate the track parameter covariance matrix
+      track->SetFitWithVertex(kFALSE); // To be sure
+      Fit(*track, kTRUE, kTRUE);
+      
+      // Printout for debuging
+      if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructor") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
+        cout << "ImproveTracks: track " << fRecTracksPtr->IndexOf(track)+1 << " improved " << endl;
+      }
+      
     }
-  } else {
-    // without Multiple Scattering if inversion impossible
-    for (hitNumber1 = 0; hitNumber1 < numberOfHit ; hitNumber1++) { 
-      trackParamAtHit1 = (AliMUONTrackParam*) (trackBeingFitted->GetTrackParamAtHit()->UncheckedAt(hitNumber1));
-      hitForRec1 = trackParamAtHit1->GetHitForRecPtr();
-      hbc1 = hitForRec1->GetBendingCoor();
-      pbc1 = trackParamAtHit1->GetBendingCoor();
-      hnbc1 = hitForRec1->GetNonBendingCoor();
-      pnbc1 = trackParamAtHit1->GetNonBendingCoor();
-      Chi2 += ((hbc1 - pbc1) * (hbc1 - pbc1) / hitForRec1->GetBendingReso2()) +
-             ((hnbc1 - pnbc1) * (hnbc1 - pnbc1) / hitForRec1->GetNonBendingReso2());
-    }
+    
+    track = (AliMUONTrack*) fRecTracksPtr->After(track);
   }
   
-  delete covBending;
-  delete covNonBending;
-  delete [] msa2;
 }
 
   //__________________________________________________________________________
-Double_t MultipleScatteringAngle2(AliMUONTrackParam *param)
-{
-  /// Returns square of multiple Coulomb scattering angle
-  /// from TrackParamAtHit pointed to by "param"
-  Double_t slopeBending, slopeNonBending, radiationLength, inverseBendingMomentum2, inverseTotalMomentum2;
-  Double_t varMultipleScatteringAngle;
-  slopeBending = param->GetBendingSlope();
-  slopeNonBending = param->GetNonBendingSlope();
-  // thickness in radiation length for the current track,
-  // taking local angle into account
-  radiationLength = AliMUONConstants::ChamberThicknessInX0() *
-                   TMath::Sqrt(1.0 + slopeBending*slopeBending + slopeNonBending*slopeNonBending);
-  inverseBendingMomentum2 =  param->GetInverseBendingMomentum() * param->GetInverseBendingMomentum();
-  inverseTotalMomentum2 = inverseBendingMomentum2 * (1.0 + slopeBending * slopeBending) /
-                         (1.0 + slopeBending *slopeBending + slopeNonBending * slopeNonBending); 
-  varMultipleScatteringAngle = 0.0136 * (1.0 + 0.038 * TMath::Log(radiationLength));
-  // The velocity is assumed to be 1 !!!!
-  varMultipleScatteringAngle = inverseTotalMomentum2 * radiationLength * varMultipleScatteringAngle * varMultipleScatteringAngle;
-  return varMultipleScatteringAngle;
-}
-
-  //__________________________________________________________________________
-void AliMUONTrackReconstructor::FillMUONTrack(void)
+void AliMUONTrackReconstructor::Finalize()
 {
   /// Fill AliMUONTrack's fHitForRecAtHit array
   /// Recompute track parameters and covariances at each attached cluster from those at the first one
   AliMUONTrack *track;
-  AliMUONTrackParam trackParam;
   AliMUONTrackParam *trackParamAtHit;
-  AliMUONHitForRec *hitForRecAtHit;
   
   track = (AliMUONTrack*) fRecTracksPtr->First();
   while (track) {
+    
+    // update track parameters if not already done
+    if (!track->IsImproved()) track->UpdateCovTrackParamAtHit();
+    
     trackParamAtHit = (AliMUONTrackParam*) (track->GetTrackParamAtHit()->First());
-    trackParam = *trackParamAtHit;
     while (trackParamAtHit) {
-      hitForRecAtHit = trackParamAtHit->GetHitForRecPtr();
-      // extrapolation to the plane of the hitForRec attached to the current trackParamAtHit
-      AliMUONTrackExtrap::ExtrapToZCov(&trackParam, hitForRecAtHit->GetZ());
-      // update track parameters of the current hit
-      trackParamAtHit->SetTrackParam(trackParam);
-      // update covariance matrix of track parameters of the current hit
-      trackParamAtHit->SetCovariances(trackParam.GetCovariances());
+      
       // update array of track hit
-      track->AddHitForRecAtHit(hitForRecAtHit);
-      // prepare next step, add MCS effects in parameter covariances
-      AliMUONTrackExtrap::AddMCSEffect(&trackParam,AliMUONConstants::ChamberThicknessInX0(),1.);
-      trackParamAtHit = (AliMUONTrackParam*) (track->GetTrackParamAtHit()->After(trackParamAtHit)); 
+      track->AddHitForRecAtHit(trackParamAtHit->GetHitForRecPtr());
+      
+      trackParamAtHit = (AliMUONTrackParam*) (track->GetTrackParamAtHit()->After(trackParamAtHit));
     }
+    
     track = (AliMUONTrack*) fRecTracksPtr->After(track);
+    
   }
-  return;
-}
-
-  //__________________________________________________________________________
-void AliMUONTrackReconstructor::EventDump(void)
-{
-  /// Dump reconstructed event (track parameters at vertex and at first hit),
-  /// and the particle parameters
-  AliMUONTrack *track;
-  AliMUONTrackParam trackParam, *trackParam1;
-  Double_t bendingSlope, nonBendingSlope, pYZ;
-  Double_t pX, pY, pZ, x, y, z, c;
-  Int_t trackIndex, nTrackHits;
-  AliDebug(1,"****** enter EventDump ******");
-  AliDebug(1, Form("Number of Reconstructed tracks : %d", fNRecTracks)); 
-  
-  fRecTracksPtr->Compress(); // for simple loop without "Next" since no hole
-  // Loop over reconstructed tracks
-  for (trackIndex = 0; trackIndex < fNRecTracks; trackIndex++) {
-    AliDebug(1, Form("track number: %d", trackIndex));
-    // function for each track for modularity ????
-    track = (AliMUONTrack*) ((*fRecTracksPtr)[trackIndex]);
-    nTrackHits = track->GetNTrackHits();
-    AliDebug(1, Form("Number of track hits: %d ", nTrackHits));
-    // track parameters at Vertex
-    trackParam = (*((AliMUONTrackParam*) track->GetTrackParamAtHit()->First()));
-    AliMUONTrackExtrap::ExtrapToVertex(&trackParam,0.,0.,0.);
-    x = trackParam.GetNonBendingCoor();
-    y = trackParam.GetBendingCoor();
-    z = trackParam.GetZ();
-    bendingSlope = trackParam.GetBendingSlope();
-    nonBendingSlope = trackParam.GetNonBendingSlope();
-    pYZ = 1/TMath::Abs(trackParam.GetInverseBendingMomentum());
-    pZ = pYZ/TMath::Sqrt(1+bendingSlope*bendingSlope);
-    pX = pZ * nonBendingSlope;
-    pY = pZ * bendingSlope;
-    c = TMath::Sign(1.0, trackParam.GetInverseBendingMomentum());
-    AliDebug(1, Form("Track parameters at Vertex z= %f: X= %f Y= %f pX= %f pY= %f pZ= %f c= %f\n",
-                    z, x, y, pX, pY, pZ, c));
-
-    // track parameters at first hit
-    trackParam1 = (AliMUONTrackParam*) track->GetTrackParamAtHit()->First();
-    x = trackParam1->GetNonBendingCoor();
-    y = trackParam1->GetBendingCoor();
-    z = trackParam1->GetZ();
-    bendingSlope = trackParam1->GetBendingSlope();
-    nonBendingSlope = trackParam1->GetNonBendingSlope();
-    pYZ = 1/TMath::Abs(trackParam1->GetInverseBendingMomentum());
-    pZ = pYZ/TMath::Sqrt(1.0 + bendingSlope * bendingSlope);
-    pX = pZ * nonBendingSlope;
-    pY = pZ * bendingSlope;
-    c = TMath::Sign(1.0, trackParam1->GetInverseBendingMomentum());
-    AliDebug(1, Form("track parameters at z= %f: X= %f Y= %f pX= %f pY= %f pZ= %f c= %f\n",
-                    z, x, y, pX, pY, pZ, c));
-  }
-  // informations about generated particles NO !!!!!!!!
-  
-//    for (Int_t iPart = 0; iPart < np; iPart++) {
-//      p = gAlice->Particle(iPart);
-//      printf(" particle %d: type= %d px= %f py= %f pz= %f pdg= %d\n",
-//        iPart, p->GetPdgCode(), p->Px(), p->Py(), p->Pz(), p->GetPdgCode());    
-//    }
-  return;
+    
 }
 
 
index e7954b7e822014b09928d1cf3c30c9b7f0d58aa4..e6331748bc19b41bfa3a4ce3b89cc0ceb1e74245 100644 (file)
 
 #include "AliMUONVTrackReconstructor.h"
 
+class AliMUONHitForRec;
+class AliMUONTrackParam;
 class AliMUONTrack;
 
 class AliMUONTrackReconstructor : public AliMUONVTrackReconstructor 
 {
  public:
+  
   AliMUONTrackReconstructor(); // default Constructor
   virtual ~AliMUONTrackReconstructor(); // Destructor
 
-  virtual void EventDump(void);  // dump reconstructed event
-
 
  protected:
 
-  virtual void MakeTracks(void);
-  virtual void MakeTrackCandidates(void);
-  virtual void FollowTracks(void);
-  virtual void RemoveDoubleTracks(void);
-  virtual void FillMUONTrack(void);
+  // Functions
+  virtual void MakeTrackCandidates();
+  virtual void FollowTracks();
+  virtual void ImproveTracks();
+  virtual void Finalize();
   
 
  private:
   
-  // Parameters for reconstruction
-  static const Double_t fgkMaxNormChi2; ///< maximum Chi2 per degree of freedom for reconstruction
-  static const Bool_t fgkTrackAllTracks; ///< kTRUE to track all the possible candidates; kFALSE to track only the best ones
-
+  // Parameters for track reconstruction
+  static const Double_t fgkBendingVertexDispersion; ///< Vertex dispersion (cm) in bending plane for reconstruction
+  static const Double_t fgkNonBendingVertexDispersion; ///< Vertex dispersion (cm) in non bending plane for reconstruction
+  
+  
   // Functions
   /// Not implemented copy constructor
   AliMUONTrackReconstructor (const AliMUONTrackReconstructor& rhs); 
   /// Not implemented copy assignment operator
   AliMUONTrackReconstructor& operator=(const AliMUONTrackReconstructor& rhs);
   
-  void RemoveIdenticalTracks(void);
-  void FollowTrackInStation(AliMUONTrack* trackCandidate, Int_t nextStation);
-  void SetVertexForFit(AliMUONTrack* trackCandidate);
-  void Fit(AliMUONTrack *track, Bool_t includeMCS, Bool_t calcCov);
+  Bool_t FollowTrackInStation(AliMUONTrack &trackCandidate, Int_t nextStation);
+  
+  Double_t TryTwoHitForRec(const AliMUONTrackParam &trackParamAtHit1, AliMUONHitForRec* hitForRec2, AliMUONTrackParam &trackParamAtHit2);
+
+  void UpdateTrack(AliMUONTrack &track, AliMUONTrackParam &trackParamAtHit);
+  void UpdateTrack(AliMUONTrack &track, AliMUONTrackParam &trackParamAtHit1, AliMUONTrackParam &trackParamAtHit2);
+  
+  Bool_t RecoverTrack(AliMUONTrack &track, Int_t nextStation);
+  
+  void SetVertexForFit(AliMUONTrack &trackCandidate);
+  
+  void Fit(AliMUONTrack &track, Bool_t includeMCS, Bool_t calcCov);
 
 
   ClassDef(AliMUONTrackReconstructor, 0) // MUON track reconstructor in ALICE
index f2367ad7bbfe350ccbf03cee0a866cb597585cc8..5cf67eb3e342c03000845df6550980de65e44257 100644 (file)
 #include "AliMUONTrackReconstructorK.h"
 #include "AliMUONConstants.h"
 #include "AliMUONHitForRec.h"
-#include "AliMUONObjectPair.h"
-#include "AliMUONRawCluster.h"
-#include "AliMUONTrackK.h" 
+#include "AliMUONTrack.h"
+#include "AliMUONTrackParam.h"
+#include "AliMUONTrackExtrap.h"
 
 #include "AliLog.h"
 
 #include <Riostream.h>
+#include <TMath.h>
+#include <TMatrixD.h>
 
 /// \cond CLASSIMP
 ClassImp(AliMUONTrackReconstructorK) // Class implementation in ROOT context
-ClassImp(AliMUONConstants)
 /// \endcond
 
-//__________________________________________________________________________
-AliMUONTrackReconstructorK::AliMUONTrackReconstructorK(const Option_t* TrackMethod)
-  : AliMUONVTrackReconstructor(),
-    fTrackMethod(2) //tracking method (2-Kalman 3-Combination-Kalman/Clustering)
-{
-  /// Constructor for class AliMUONTrackReconstructorK
+//************* Defaults parameters for reconstruction
+const Bool_t AliMUONTrackReconstructorK::fgkRunSmoother = kTRUE;
 
-  if (strstr(TrackMethod,"Kalman")) {
-    AliInfo(" *** Tracking with the Kalman filter *** ");
-    fTrackMethod = 2;
-  } else if (strstr(TrackMethod,"Combi")) {
-    AliInfo(" *** Combined cluster / track finder ***");
-    fTrackMethod = 3;
-  } else AliFatal(Form("Tracking method %s not available",TrackMethod));
-  
-  // Memory allocation for the TClonesArray of reconstructed tracks
-  fRecTracksPtr = new TClonesArray("AliMUONTrackK", 10);
-}
 
 //__________________________________________________________________________
-AliMUONTrackReconstructorK::~AliMUONTrackReconstructorK(void)
+AliMUONTrackReconstructorK::AliMUONTrackReconstructorK()
+  : AliMUONVTrackReconstructor()
 {
-  /// Destructor for class AliMUONTrackReconstructorK
-  delete fRecTracksPtr;
+  /// Constructor for class AliMUONTrackReconstructorK
+  AliInfo("*** Tracking with Kalman Filter ***");
 }
 
 //__________________________________________________________________________
-void AliMUONTrackReconstructorK::MakeTracks(void)
+AliMUONTrackReconstructorK::~AliMUONTrackReconstructorK()
 {
-  /// To make the tracks from the list of segments and points in all stations
-  AliDebug(1,"Enter MakeTracks");
-  // The order may be important for the following Reset's
-  //AZ ResetTracks();
-  MakeTrackCandidates();
-  if (fRecTracksPtr->GetEntriesFast() == 0) return;
-  // Follow tracks in stations(1..) 3, 2 and 1
-  FollowTracks();
-  // Remove double tracks
-  RemoveDoubleTracks();
-  // Print out some track info (if necessary)
-  EventDump();
-  // Fill AliMUONTrack data members
-  FillMUONTrack();
-}
+/// Destructor
+} 
 
   //__________________________________________________________________________
-void AliMUONTrackReconstructorK::MakeTrackCandidates(void)
+void AliMUONTrackReconstructorK::MakeTrackCandidates()
 {
-  /// To make initial tracks for Kalman filter from segments in stations(1..)  4 and 5
-  Int_t istat, iseg;
+  /// To make track candidates:
+  /// Start with segments station(1..) 4 or 5 then follow track in station 5 or 4.
+  /// Good candidates are made of at least three hitForRec's.
+  /// Keep only best candidates or all of them according to the flag fgkTrackAllTracks.
   TClonesArray *segments;
-  AliMUONObjectPair *segment;
-  AliMUONTrackK *trackK;
+  AliMUONTrack *track;
+  Int_t iCandidate = 0;
 
-  AliDebug(1,"Enter MakeTrackCandidatesK");
+  AliDebug(1,"Enter MakeTrackCandidates");
 
-  AliMUONTrackK a(this, fHitsForRecPtr);
-  // Loop over stations(1...) 5 and 4
-  for (istat=4; istat>=3; istat--) 
-  {
+  // Loop over stations(1..) 5 and 4 and make track candidates
+  for (Int_t istat=4; istat>=3; istat--) {
+    
     // Make segments in the station
     segments = MakeSegmentsInStation(istat);
-    // Loop over segments in the station
-    for (iseg=0; iseg<segments->GetEntriesFast(); iseg++) 
-    {
-      // Transform segments to tracks
-      segment = (AliMUONObjectPair*) ((*segments)[iseg]);
-      trackK = new ((*fRecTracksPtr)[fNRecTracks++]) AliMUONTrackK(*segment);
-    } // for (iseg=0;...)
+    
+    // Loop over segments
+    for (Int_t iseg=0; iseg<segments->GetEntriesFast(); iseg++) {
+      AliDebug(1,Form("Making primary candidate(1..) %d",++iCandidate));
+      
+      // Transform segments to tracks and put them at the end of fRecTracksPtr
+      track = new ((*fRecTracksPtr)[fRecTracksPtr->GetLast()+1]) AliMUONTrack((AliMUONObjectPair*)((*segments)[iseg]));
+      fNRecTracks++;
+      
+      // Recompute track parameters and covariances on station(1..) 5 using Kalman filter
+      // (to make sure all tracks are treated in the same way)
+      if (istat == 4) RetraceTrack(*track,kFALSE);
+      
+      // Printout for debuging
+      if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 2) || (AliLog::GetGlobalDebugLevel() >= 2)) {
+        cout<<endl<<"Track parameter covariances at first hit:"<<endl;
+        ((AliMUONTrackParam*) (track->GetTrackParamAtHit()->First()))->GetCovariances().Print();
+      }
+      
+      // Look for compatible hitForRec(s) in the other station
+      // Remove track if no hit found
+      if (!FollowTrackInStation(*track,7-istat)) {
+        fRecTracksPtr->Remove(track);
+       fNRecTracks--;
+      }
+      
+    }
+    // delete the array of segments
     delete segments;
-  } // for (istat=4;...)
+  }
+  
+  fRecTracksPtr->Compress(); // this is essential before checking tracks
+  
+  // Remove bad tracks
+  Int_t currentNRecTracks = fNRecTracks;
+  for (Int_t iRecTrack = 0; iRecTrack < currentNRecTracks; iRecTrack++) {
+    
+    track = (AliMUONTrack*) fRecTracksPtr->UncheckedAt(iRecTrack);
+    
+    // Remove the track if the normalized chi2 is too high
+    if (track->GetNormalizedChi2() > fgkSigmaToCutForTracking * fgkSigmaToCutForTracking) {
+      fRecTracksPtr->Remove(track);
+      fNRecTracks--;
+    }
+    
+  }
+  
+  fRecTracksPtr->Compress(); // this is essential before checking tracks
+  
+  // Keep all different tracks or only the best ones as required
+  if (fgkTrackAllTracks) RemoveIdenticalTracks();
+  else RemoveDoubleTracks();
+  
+  AliDebug(1,Form("Number of good candidates = %d",fNRecTracks));
+  
 }
 
-//__________________________________________________________________________
-void AliMUONTrackReconstructorK::FollowTracks(void)
+  //__________________________________________________________________________
+void AliMUONTrackReconstructorK::RetraceTrack(AliMUONTrack &trackCandidate, Bool_t resetSeed)
 {
-  /// Follow tracks using Kalman filter
-  Bool_t ok;
-  Int_t icand, ichamBeg = 0, ichamEnd, chamBits;
-  AliMUONTrackK *trackK;
-  AliMUONHitForRec *hit;
-  AliMUONRawCluster *clus;
-  TClonesArray *rawclusters;
-  clus = 0; rawclusters = 0;
-
-  Double_t simpleBPosition = 0.5 * (AliMUONConstants::CoilZ() + AliMUONConstants::YokeZ());
-  Double_t simpleBLength = 0.5 * (AliMUONConstants::CoilL() + AliMUONConstants::YokeL());
-  Double_t zDipole1 = simpleBPosition + 0.5 * simpleBLength;
-  Double_t zDipole2 = zDipole1 - simpleBLength;
-
-  // Print hits
-  trackK = (AliMUONTrackK*) ((*fRecTracksPtr)[0]);
+  /// Re-run the kalman filter from the most downstream hit to the most uptream one
+  AliDebug(1,"Enter RetraceTrack");
+  
+  AliMUONTrackParam* startingTrackParam = (AliMUONTrackParam*) trackCandidate.GetTrackParamAtHit()->Last();
+  
+  // Reset the "seed" (= track parameters and their covariances at last hit) if required
+  if (resetSeed) {
+    // => Shift track parameters at the position of the last hit
+    AliMUONHitForRec* hitForRecAtHit = startingTrackParam->GetHitForRecPtr();
+    startingTrackParam->SetNonBendingCoor(hitForRecAtHit->GetNonBendingCoor());
+    startingTrackParam->SetBendingCoor(hitForRecAtHit->GetBendingCoor());
+    
+    // => Re-compute and reset track parameters covariances at last hit (as if the other hits did not exist)
+    const TMatrixD& kParamCov = startingTrackParam->GetCovariances();
+    TMatrixD newParamCov(5,5);
+    newParamCov.Zero();
+    // Non bending plane
+    newParamCov(0,0) = hitForRecAtHit->GetNonBendingReso2();
+    newParamCov(1,1) = 100.*kParamCov(1,1);
+    // Bending plane
+    newParamCov(2,2) = hitForRecAtHit->GetBendingReso2();
+    newParamCov(3,3) = 100.*kParamCov(3,3);
+    // Inverse bending momentum
+    newParamCov(4,4) = 0.5*startingTrackParam->GetInverseBendingMomentum() * 0.5*startingTrackParam->GetInverseBendingMomentum();
+    startingTrackParam->SetCovariances(newParamCov);
+    
+    // Reset the track chi2
+    startingTrackParam->SetTrackChi2(0.);
+  
+  }
+  
+  // Redo the tracking
+  RetracePartialTrack(trackCandidate, startingTrackParam);
+  
+}
 
-  icand = -1;
-  Int_t nSeeds;
-  nSeeds = fNRecTracks; // starting number of seeds
-  // Loop over track candidates
-  while (icand < fNRecTracks-1) {
-    icand ++;
-    if (trackK->DebugLevel()>0) cout << " *** Kalman track candidate No. " << icand << endl;
-    trackK = (AliMUONTrackK*) ((*fRecTracksPtr)[icand]);
-    if (trackK->GetRecover() < 0) continue; // failed track
+  //__________________________________________________________________________
+void AliMUONTrackReconstructorK::RetracePartialTrack(AliMUONTrack &trackCandidate, const AliMUONTrackParam* startingTrackParam)
+{
+  /// Re-run the kalman filter from the hit attached to startingTrackParam to the most uptream hit
+  AliDebug(1,"Enter RetracePartialTrack");
+  
+  // Printout for debuging
+  if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
+    cout << "RetracePartialTrack: track chi2 before re-tracking: " << trackCandidate.GetFitFMin() << endl;
+  }
+  
+  // Reset the track chi2
+  trackCandidate.SetFitFMin(startingTrackParam->GetTrackChi2());
+  
+  // loop over attached hits until the first one and recompute track parameters and covariances using kalman filter
+  Int_t expectedChamber = startingTrackParam->GetHitForRecPtr()->GetChamberNumber() - 1;
+  Int_t currentChamber;
+  Double_t addChi2TrackAtHit;
+  AliMUONTrackParam* trackParamAtHit = (AliMUONTrackParam*) trackCandidate.GetTrackParamAtHit()->Before(startingTrackParam); 
+  while (trackParamAtHit) {
+    
+    // reset track parameters and their covariances
+    trackParamAtHit->SetParameters(startingTrackParam->GetParameters());
+    trackParamAtHit->SetZ(startingTrackParam->GetZ());
+    trackParamAtHit->SetCovariances(startingTrackParam->GetCovariances());
+    
+    // add MCS effect
+    AliMUONTrackExtrap::AddMCSEffect(trackParamAtHit,AliMUONConstants::ChamberThicknessInX0(),1.);
+    
+    // reset propagator for smoother
+    if (fgkRunSmoother) trackParamAtHit->ResetPropagator();
+    
+    // add MCS in missing chambers if any (at most 2 chambers can be missing according to tracking criteria)
+    currentChamber = trackParamAtHit->GetHitForRecPtr()->GetChamberNumber();
+    while (currentChamber < expectedChamber) {
+      // extrapolation to the missing chamber (update the propagator)
+      AliMUONTrackExtrap::ExtrapToZCov(trackParamAtHit, AliMUONConstants::DefaultChamberZ(expectedChamber), fgkRunSmoother);
+      // add MCS effect
+      AliMUONTrackExtrap::AddMCSEffect(trackParamAtHit,AliMUONConstants::ChamberThicknessInX0(),1.);
+      expectedChamber--;
+    }
+    
+    // extrapolation to the plane of the hitForRec attached to the current trackParamAtHit (update the propagator)
+    AliMUONTrackExtrap::ExtrapToZCov(trackParamAtHit, trackParamAtHit->GetHitForRecPtr()->GetZ(), fgkRunSmoother);
+    
+    if (fgkRunSmoother) {
+      // save extrapolated parameters for smoother
+      trackParamAtHit->SetExtrapParameters(trackParamAtHit->GetParameters());
+      
+      // save extrapolated covariance matrix for smoother
+      trackParamAtHit->SetExtrapCovariances(trackParamAtHit->GetCovariances());
+    }
+    
+    // Compute new track parameters including "hitForRecCh2" using kalman filter
+    addChi2TrackAtHit = RunKalmanFilter(*trackParamAtHit);
+    
+    // Update the track chi2
+    trackCandidate.SetFitFMin(trackCandidate.GetFitFMin() + addChi2TrackAtHit);
+    trackParamAtHit->SetTrackChi2(trackCandidate.GetFitFMin());
+    
+    // prepare next step, add MCS effects in parameter covariances
+    expectedChamber--;
+    startingTrackParam = trackParamAtHit;
+    trackParamAtHit = (AliMUONTrackParam*) (trackCandidate.GetTrackParamAtHit()->Before(startingTrackParam)); 
+  }
+  
+  // Printout for debuging
+  if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
+    cout << "RetracePartialTrack: track chi2 after re-tracking: " << trackCandidate.GetFitFMin() << endl;
+  }
+  
+}
 
-    // Discard candidate which will produce the double track
-    /*
-    if (icand > 0) {
-      ok = CheckCandidate(icand,nSeeds);
-      if (!ok) {
-        trackK->SetRecover(-1); // mark candidate to be removed
-        continue;
+  //__________________________________________________________________________
+void AliMUONTrackReconstructorK::FollowTracks()
+{
+  /// Follow tracks in stations(1..) 3, 2 and 1
+  AliDebug(1,"Enter FollowTracks");
+  
+  AliMUONTrack *track;
+  Int_t currentNRecTracks;
+  Bool_t hitFound;
+  
+  for (Int_t station = 2; station >= 0; station--) {
+    
+    // Save the actual number of reconstructed track in case of
+    // tracks are added or suppressed during the tracking procedure
+    // !! Do not compress fRecTracksPtr until the end of the loop over tracks !!
+    currentNRecTracks = fNRecTracks;
+    
+    for (Int_t iRecTrack = 0; iRecTrack <currentNRecTracks; iRecTrack++) {
+      AliDebug(1,Form("FollowTracks: track candidate(1..) %d", iRecTrack+1));
+      
+      track = (AliMUONTrack*) fRecTracksPtr->UncheckedAt(iRecTrack);
+      
+      // Printout for debuging
+      if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 2) || (AliLog::GetGlobalDebugLevel() >= 2)) {
+        cout<<endl<<"Track parameter covariances at first hit:"<<endl;
+        ((AliMUONTrackParam*) (track->GetTrackParamAtHit()->First()))->GetCovariances().Print();
+      }
+      
+      // Look for compatible hitForRec in station(0..) "station"
+      hitFound = FollowTrackInStation(*track,station);
+      
+      // Try to recover track if required
+      if (!hitFound && fgkRecoverTracks) hitFound = RecoverTrack(*track,station);
+      
+      // remove track if no hit found
+      if (!hitFound) {
+       fRecTracksPtr->Remove(track);
+       fNRecTracks--;
       }
+      
     }
-    */
-
-    ok = kTRUE;
-    if (trackK->GetRecover() == 0) 
-      hit = (AliMUONHitForRec*) trackK->GetTrackHits()->Last(); // last hit
-    else 
-      hit = trackK->GetHitLastOk(); // hit where track stopped
-
-    if (hit) ichamBeg = hit->GetChamberNumber();
-    if (ichamBeg == 8 && trackK->GetStation0() == 4) ichamBeg = 10;
+    
+    fRecTracksPtr->Compress(); // this is essential before checking tracks
+    
+    // Remove bad tracks
+    Int_t currentNRecTracks = fNRecTracks;
+    for (Int_t iRecTrack = 0; iRecTrack < currentNRecTracks; iRecTrack++) {
+      track = (AliMUONTrack*) fRecTracksPtr->UncheckedAt(iRecTrack);
+      
+      // Remove the track if the normalized chi2 is too high
+      if (track->GetNormalizedChi2() > fgkSigmaToCutForTracking * fgkSigmaToCutForTracking) {
+       fRecTracksPtr->Remove(track);
+       fNRecTracks--;
+      }
+      
+    }
+    
+    fRecTracksPtr->Compress(); // this is essential before checking tracks
+    
+    // Keep only the best tracks if required
+    if (!fgkTrackAllTracks) RemoveDoubleTracks();
+    
+  }
+  
+}
 
-    ichamEnd = 0;
-    // Check propagation direction
-    if (!hit) { ichamBeg = ichamEnd; AliFatal(" ??? "); }
-    else if (trackK->GetTrackDir() < 0) {
-      ichamEnd = 9; // forward propagation
-      ok = trackK->KalmanFilter(ichamBeg,ichamEnd,kFALSE,zDipole1,zDipole2);
-      if (ok) {
-        ichamBeg = ichamEnd + 1;
-        ichamEnd = 6; // backward propagation
-       // Change weight matrix and zero fChi2 for backpropagation
-        trackK->StartBack();
-       trackK->SetTrackDir(1);
-        ok = trackK->KalmanFilter(ichamBeg,ichamEnd,kTRUE,zDipole1,zDipole2);
-        ichamBeg = ichamEnd;
-        ichamEnd = 0;
+  //__________________________________________________________________________
+Bool_t AliMUONTrackReconstructorK::FollowTrackInStation(AliMUONTrack &trackCandidate, Int_t nextStation)
+{
+  /// Follow trackCandidate in station(0..) nextStation and search for compatible HitForRec(s)
+  /// Keep all possibilities or only the best one(s) according to the flag fgkTrackAllTracks:
+  /// kTRUE:  duplicate "trackCandidate" if there are several possibilities and add the new tracks at the end of
+  ///         fRecTracksPtr to avoid conficts with other track candidates at this current stage of the tracking procedure.
+  ///         Remove the obsolete "trackCandidate" at the end.
+  /// kFALSE: add only the best hit(s) to the "trackCandidate". Try to add a couple of hits in priority.
+  /// return kTRUE if new hits have been found (otherwise return kFALSE)
+  AliDebug(1,Form("Enter FollowTrackInStation(1..) %d", nextStation+1));
+  
+  // Order the chamber according to the propagation direction (tracking starts with chamber 2):
+  // - nextStation == station(1...) 5 => forward propagation
+  // - nextStation < station(1...) 5 => backward propagation
+  Int_t ch1, ch2;
+  if (nextStation==4) {
+    ch1 = 2*nextStation+1;
+    ch2 = 2*nextStation;
+  } else {
+    ch1 = 2*nextStation;
+    ch2 = 2*nextStation+1;
+  }
+  
+  Double_t zCh2 = AliMUONConstants::DefaultChamberZ(ch2);
+  Double_t chi2OfHitForRec;
+  Double_t maxChi2OfHitForRec = 2. * fgkSigmaToCutForTracking * fgkSigmaToCutForTracking; // 2 because 2 quantities in chi2
+  Double_t addChi2TrackAtHit1;
+  Double_t addChi2TrackAtHit2;
+  Double_t bestAddChi2TrackAtHit1 = 1.e10;
+  Double_t bestAddChi2TrackAtHit2 = 1.e10;
+  Bool_t foundOneHit = kFALSE;
+  Bool_t foundTwoHits = kFALSE;
+  AliMUONTrack *newTrack = 0x0;
+  AliMUONHitForRec *hitForRecCh1, *hitForRecCh2;
+  AliMUONTrackParam extrapTrackParam;
+  AliMUONTrackParam extrapTrackParamAtHit1;
+  AliMUONTrackParam extrapTrackParamAtHit2;
+  AliMUONTrackParam bestTrackParamAtHit1;
+  AliMUONTrackParam bestTrackParamAtHit2;
+  Bool_t *hitForRecCh1Used = new Bool_t[fNHitsForRecPerChamber[ch1]];
+  for (Int_t hit1 = 0; hit1 < fNHitsForRecPerChamber[ch1]; hit1++) hitForRecCh1Used[hit1] = kFALSE;
+  
+  // Get track parameters and extrapolate them to chamber "ch2" to save computing time in the next steps
+  AliMUONTrackParam extrapTrackParamAtCh2(*(AliMUONTrackParam*)trackCandidate.GetTrackParamAtHit()->First());
+  
+  // Add MCS effect
+  AliMUONTrackExtrap::AddMCSEffect(&extrapTrackParamAtCh2,AliMUONConstants::ChamberThicknessInX0(),1.);
+  
+  // reset propagator for smoother
+  if (fgkRunSmoother) extrapTrackParamAtCh2.ResetPropagator();
+  
+  // Add MCS in the missing chamber if any (only 1 chamber can be missing according to tracking criteria)
+  if (ch1 < ch2 && extrapTrackParamAtCh2.GetHitForRecPtr()->GetChamberNumber() > ch2 + 1) {
+    // extrapolation to the missing chamber
+    AliMUONTrackExtrap::ExtrapToZCov(&extrapTrackParamAtCh2, AliMUONConstants::DefaultChamberZ(ch2 + 1), fgkRunSmoother);
+    // add MCS effect
+    AliMUONTrackExtrap::AddMCSEffect(&extrapTrackParamAtCh2,AliMUONConstants::ChamberThicknessInX0(),1.);
+  }
+  
+  //Extrapolate trackCandidate to chamber "ch2"
+  AliMUONTrackExtrap::ExtrapToZCov(&extrapTrackParamAtCh2, zCh2, fgkRunSmoother);
+  
+  // Printout for debuging
+  if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 2) || (AliLog::GetGlobalDebugLevel() >= 2)) {
+    cout<<endl<<"Track parameter covariances at first hit extrapolated to z = "<<zCh2<<":"<<endl;
+    extrapTrackParamAtCh2.GetCovariances().Print();
+  }
+  
+  // Printout for debuging
+  if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
+    cout << "FollowTrackInStation: look for hits in chamber(1..): " << ch2+1 << endl;
+  }
+  
+  // look for candidates in chamber 2 
+  for (Int_t hit2 = 0; hit2 < fNHitsForRecPerChamber[ch2]; hit2++) {
+    
+    hitForRecCh2 = (AliMUONHitForRec*) fHitsForRecPtr->UncheckedAt(fIndexOfFirstHitForRecPerChamber[ch2]+hit2);
+    
+    // try to add the current hit
+    chi2OfHitForRec = TryOneHitForRec(extrapTrackParamAtCh2, hitForRecCh2, extrapTrackParamAtHit2, fgkRunSmoother);
+    
+    // if good chi2 then try to attach a hitForRec in the other chamber too
+    if (chi2OfHitForRec < maxChi2OfHitForRec) {
+      Bool_t foundSecondHit = kFALSE;
+      
+      // Printout for debuging
+      if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
+        cout << "FollowTrackInStation: found one hit in chamber(1..): " << ch2+1
+            << " (Chi2 = " << chi2OfHitForRec << ")" << endl;
+        cout << "                      look for second hits in chamber(1..): " << ch1+1 << " ..." << endl;
       }
-    } else {
-      if (trackK->GetBPFlag()) {
-       // backpropagation
-        if (ichamBeg == 10) ichamEnd = 8;
-        else {
-          if (ichamBeg == 9) ichamBeg++;
-         ichamEnd = 6; 
-         // Change weight matrix and zero fChi2 for backpropagation
-         trackK->StartBack();
+      
+      if (fgkRunSmoother) {
+        // save extrapolated parameters for smoother
+        extrapTrackParamAtHit2.SetExtrapParameters(extrapTrackParamAtHit2.GetParameters());
+        
+        // save extrapolated covariance matrix for smoother
+        extrapTrackParamAtHit2.SetExtrapCovariances(extrapTrackParamAtHit2.GetCovariances());
+      }
+      
+      // Compute new track parameters including "hitForRecCh2" using kalman filter
+      addChi2TrackAtHit2 = RunKalmanFilter(extrapTrackParamAtHit2);
+      
+      // copy new track parameters for next step
+      extrapTrackParam = extrapTrackParamAtHit2;
+      
+      // add MCS effect
+      AliMUONTrackExtrap::AddMCSEffect(&extrapTrackParam,AliMUONConstants::ChamberThicknessInX0(),1.);
+      
+      // reset propagator for smoother
+      if (fgkRunSmoother) extrapTrackParam.ResetPropagator();
+      
+      for (Int_t hit1 = 0; hit1 < fNHitsForRecPerChamber[ch1]; hit1++) {
+        
+       hitForRecCh1 = (AliMUONHitForRec*) fHitsForRecPtr->UncheckedAt(fIndexOfFirstHitForRecPerChamber[ch1]+hit1);
+       
+        // try to add the current hit
+       chi2OfHitForRec = TryOneHitForRec(extrapTrackParam, hitForRecCh1, extrapTrackParamAtHit1, fgkRunSmoother);
+        
+       // if good chi2 then consider to add the 2 hitForRec to the "trackCandidate"
+       if (chi2OfHitForRec < maxChi2OfHitForRec) {
+         foundSecondHit = kTRUE;
+         foundTwoHits = kTRUE;
+          
+         // Printout for debuging
+         if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
+           cout << "FollowTrackInStation: found one hit in chamber(1..): " << ch1+1
+                << " (Chi2 = " << chi2OfHitForRec << ")" << endl;
+         }
+         
+          if (fgkRunSmoother) {
+            // save extrapolated parameters for smoother
+            extrapTrackParamAtHit1.SetExtrapParameters(extrapTrackParamAtHit1.GetParameters());
+            
+            // save extrapolated covariance matrix for smoother
+            extrapTrackParamAtHit1.SetExtrapCovariances(extrapTrackParamAtHit1.GetCovariances());
+          }
+          
+          // Compute new track parameters including "hitForRecCh1" using kalman filter
+          addChi2TrackAtHit1 = RunKalmanFilter(extrapTrackParamAtHit1);
+          
+         if (fgkTrackAllTracks) {
+           // copy trackCandidate into a new track put at the end of fRecTracksPtr and add the new hitForRec's
+            newTrack = new ((*fRecTracksPtr)[fRecTracksPtr->GetLast()+1]) AliMUONTrack(trackCandidate);
+           UpdateTrack(*newTrack,extrapTrackParamAtHit1,extrapTrackParamAtHit2,addChi2TrackAtHit1,addChi2TrackAtHit2);
+           fNRecTracks++;
+           
+           // if we are arrived on station(1..) 5, recompute track parameters and covariances starting from this station
+           // (going in the right direction)
+           if (nextStation == 4) RetraceTrack(*newTrack,kTRUE);
+           
+           // Tag hitForRecCh1 as used
+           hitForRecCh1Used[hit1] = kTRUE;
+           
+           // Printout for debuging
+           if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
+             cout << "FollowTrackInStation: added two hits in station(1..): " << nextStation+1 << endl;
+             if (AliLog::GetGlobalDebugLevel() >= 3) newTrack->RecursiveDump();
+           }
+           
+          } else if (addChi2TrackAtHit1+addChi2TrackAtHit2 < bestAddChi2TrackAtHit1+bestAddChi2TrackAtHit2) {
+           // keep track of the best couple of hits
+           bestAddChi2TrackAtHit1 = addChi2TrackAtHit1;
+           bestAddChi2TrackAtHit2 = addChi2TrackAtHit2;
+           bestTrackParamAtHit1 = extrapTrackParamAtHit1;
+           bestTrackParamAtHit2 = extrapTrackParamAtHit2;
+          }
+         
        }
-        ok = trackK->KalmanFilter(ichamBeg,ichamEnd,kTRUE,zDipole1,zDipole2);
-        ichamBeg = ichamEnd;
-        ichamEnd = 0;
+       
       }
+      
+      // if no hitForRecCh1 found then consider to add hitForRecCh2 only
+      if (!foundSecondHit) {
+       foundOneHit = kTRUE;
+        
+       if (fgkTrackAllTracks) {
+         // copy trackCandidate into a new track put at the end of fRecTracksPtr and add the new hitForRec's
+          newTrack = new ((*fRecTracksPtr)[fRecTracksPtr->GetLast()+1]) AliMUONTrack(trackCandidate);
+         UpdateTrack(*newTrack,extrapTrackParamAtHit2,addChi2TrackAtHit2);
+         fNRecTracks++;
+         
+         // if we are arrived on station(1..) 5, recompute track parameters and covariances starting from this station
+         // (going in the right direction)
+         if (nextStation == 4) RetraceTrack(*newTrack,kTRUE);
+         
+         // Printout for debuging
+         if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
+           cout << "FollowTrackInStation: added one hit in chamber(1..): " << ch2+1 << endl;
+           if (AliLog::GetGlobalDebugLevel() >= 3) newTrack->RecursiveDump();
+         }
+         
+       } else if (!foundTwoHits && addChi2TrackAtHit2 < bestAddChi2TrackAtHit1) {
+         // keep track of the best single hitForRec except if a couple
+          // of hits has already been found (i.e. bestHitForRec2!=0x0)
+         bestAddChi2TrackAtHit1 = addChi2TrackAtHit2;
+         bestTrackParamAtHit1 = extrapTrackParamAtHit2;
+        }
+       
+      }
+      
     }
-
-    if (ok) {
-      trackK->SetTrackDir(1);
-      trackK->SetBPFlag(kFALSE);
-      ok = trackK->KalmanFilter(ichamBeg,ichamEnd,kFALSE,zDipole1,zDipole2);
+    
+  }
+  
+  // look for candidates in chamber 1 not already attached to a track
+  // if we want to keep all possible tracks or if no good couple of hitForRec has been found
+  if (fgkTrackAllTracks || !foundTwoHits) {
+    
+    // Printout for debuging
+    if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
+      cout << "FollowTrackInStation: look for single hits in chamber(1..): " << ch1+1 << endl;
     }
-    if (!ok) { trackK->SetRecover(-1); continue; } // mark candidate to be removed
-
-    // Apply smoother
-    if (trackK->GetRecover() >= 0) {
-      ok = trackK->Smooth();
-      if (!ok) trackK->SetRecover(-1); // mark candidate to be removed
+    
+    // add MCS effect for next step
+    AliMUONTrackExtrap::AddMCSEffect(&extrapTrackParamAtCh2,AliMUONConstants::ChamberThicknessInX0(),1.);
+      
+    for (Int_t hit1 = 0; hit1 < fNHitsForRecPerChamber[ch1]; hit1++) {
+      
+      hitForRecCh1 = (AliMUONHitForRec*) fHitsForRecPtr->UncheckedAt(fIndexOfFirstHitForRecPerChamber[ch1]+hit1);
+      
+      if (hitForRecCh1Used[hit1]) continue; // Skip hitForRec already used
+      
+      // try to add the current hit
+      chi2OfHitForRec = TryOneHitForRec(extrapTrackParamAtCh2, hitForRecCh1, extrapTrackParamAtHit1, fgkRunSmoother);
+    
+      // if good chi2 then consider to add hitForRecCh1
+      // We do not try to attach a hitForRec in the other chamber too since it has already been done above
+      if (chi2OfHitForRec < maxChi2OfHitForRec) {
+       foundOneHit = kTRUE;
+       
+       // Printout for debuging
+       if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
+         cout << "FollowTrackInStation: found one hit in chamber(1..): " << ch1+1
+              << " (Chi2 = " << chi2OfHitForRec << ")" << endl;
+       }
+       
+       if (fgkRunSmoother) {
+          // save extrapolated parameters for smoother
+          extrapTrackParamAtHit1.SetExtrapParameters(extrapTrackParamAtHit1.GetParameters());
+          
+          // save extrapolated covariance matrix for smoother
+          extrapTrackParamAtHit1.SetExtrapCovariances(extrapTrackParamAtHit1.GetCovariances());
+        }
+        
+        // Compute new track parameters including "hitForRecCh1" using kalman filter
+        addChi2TrackAtHit1 = RunKalmanFilter(extrapTrackParamAtHit1);
+        
+       if (fgkTrackAllTracks) {
+         // copy trackCandidate into a new track put at the end of fRecTracksPtr and add the new hitForRec's
+         newTrack = new ((*fRecTracksPtr)[fRecTracksPtr->GetLast()+1]) AliMUONTrack(trackCandidate);
+         UpdateTrack(*newTrack,extrapTrackParamAtHit1,addChi2TrackAtHit1);
+         fNRecTracks++;
+         
+         // if we are arrived on station(1..) 5, recompute track parameters and covariances starting from this station
+         // (going in the right direction)
+         if (nextStation == 4) RetraceTrack(*newTrack,kTRUE);
+         
+         // Printout for debuging
+         if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
+           cout << "FollowTrackInStation: added one hit in chamber(1..): " << ch1+1 << endl;
+           if (AliLog::GetGlobalDebugLevel() >= 3) newTrack->RecursiveDump();
+         }
+         
+       } else if (addChi2TrackAtHit1 < bestAddChi2TrackAtHit1) {
+         // keep track of the best single hitForRec except if a couple
+         // of hits has already been found (i.e. bestHitForRec1!=0x0)
+         bestAddChi2TrackAtHit1 = addChi2TrackAtHit1;
+         bestTrackParamAtHit1 = extrapTrackParamAtHit1;
+       }
+       
+      }
+      
     }
+    
+  }
+  
+  // fill out the best track if required else clean up the fRecTracksPtr array
+  if (!fgkTrackAllTracks) {
+    if (foundTwoHits) {
+      UpdateTrack(trackCandidate,bestTrackParamAtHit1,bestTrackParamAtHit2,bestAddChi2TrackAtHit1,bestAddChi2TrackAtHit2);
+      
+      // if we are arrived on station(1..) 5, recompute track parameters and covariances starting from this station
+      // (going in the right direction)
+      if (nextStation == 4) RetraceTrack(trackCandidate,kTRUE);
 
-    // Majority 3 of 4 in first 2 stations
-    if (!ok) continue;
-    chamBits = 0;
-    Double_t chi2max = 0;
-    for (Int_t i=0; i<trackK->GetNTrackHits(); i++) {
-      hit = (AliMUONHitForRec*) (*trackK->GetTrackHits())[i];
-      chamBits |= BIT(hit->GetChamberNumber());
-      if (trackK->GetChi2PerPoint(i) > chi2max) chi2max = trackK->GetChi2PerPoint(i);
-    }
-    if (!((chamBits&3)==3 || (chamBits>>2&3)==3) && chi2max > 25) {
-      //trackK->Recover();
-      trackK->SetRecover(-1); //mark candidate to be removed
-      continue;
-    }
-    if (ok) trackK->SetTrackQuality(0); // compute "track quality"
-  } // while
+      // Printout for debuging
+      if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
+        cout << "FollowTrackInStation: added the two best hits in station(1..): " << nextStation+1 << endl;
+        if (AliLog::GetGlobalDebugLevel() >= 3) newTrack->RecursiveDump();
+      }
+      
+    } else if (foundOneHit) {
+      UpdateTrack(trackCandidate,bestTrackParamAtHit1,bestAddChi2TrackAtHit1);
+      
+      // if we are arrived on station(1..) 5, recompute track parameters and covariances starting from this station
+      // (going in the right direction)
+      if (nextStation == 4) RetraceTrack(trackCandidate,kTRUE);
+
+      // Printout for debuging
+      if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
+        cout << "FollowTrackInStation: added the best hit in chamber(1..): " << bestTrackParamAtHit1.GetHitForRecPtr()->GetChamberNumber()+1 << endl;
+        if (AliLog::GetGlobalDebugLevel() >= 3) newTrack->RecursiveDump();
+      }
+      
+    } else return kFALSE;
+    
+  } else if (foundOneHit || foundTwoHits) {
+    
+    // remove obsolete track
+    fRecTracksPtr->Remove(&trackCandidate);
+    fNRecTracks--;
+    
+  } else return kFALSE;
+  
+  return kTRUE;
+  
+}
 
-  for (Int_t i=0; i<fNRecTracks; i++) {
-    trackK = (AliMUONTrackK*) ((*fRecTracksPtr)[i]);
-    if (trackK->GetRecover() < 0) fRecTracksPtr->RemoveAt(i);
+  //__________________________________________________________________________
+Double_t AliMUONTrackReconstructorK::RunKalmanFilter(AliMUONTrackParam &trackParamAtHit)
+{
+  /// Compute new track parameters and their covariances including new hit using kalman filter
+  /// return the additional track chi2
+  AliDebug(1,"Enter RunKalmanFilter");
+  
+  // Get actual track parameters (p)
+  TMatrixD param(trackParamAtHit.GetParameters());
+  
+  // Get new hit parameters (m)
+  AliMUONHitForRec *hitForRecAtHit = trackParamAtHit.GetHitForRecPtr();
+  TMatrixD hit(5,1);
+  hit.Zero();
+  hit(0,0) = hitForRecAtHit->GetNonBendingCoor();
+  hit(2,0) = hitForRecAtHit->GetBendingCoor();
+  
+  // Compute the actual parameter weight (W)
+  TMatrixD paramWeight(trackParamAtHit.GetCovariances());
+  if (paramWeight.Determinant() != 0) {
+    paramWeight.Invert();
+  } else {
+    AliWarning(" Determinant = 0");
+    return 1.e10;
   }
+  
+  // Compute the new hit weight (U)
+  TMatrixD hitWeight(5,5);
+  hitWeight.Zero();
+  hitWeight(0,0) = 1. / hitForRecAtHit->GetNonBendingReso2();
+  hitWeight(2,2) = 1. / hitForRecAtHit->GetBendingReso2();
 
-  // Compress TClonesArray
-  fRecTracksPtr->Compress();
-  fNRecTracks = fRecTracksPtr->GetEntriesFast();
-  return;
+  // Compute the new parameters covariance matrix ( (W+U)^-1 )
+  TMatrixD newParamCov(paramWeight,TMatrixD::kPlus,hitWeight);
+  if (newParamCov.Determinant() != 0) {
+    newParamCov.Invert();
+  } else {
+    AliWarning(" Determinant = 0");
+    return 1.e10;
+  }
+  
+  // Save the new parameters covariance matrix
+  trackParamAtHit.SetCovariances(newParamCov);
+  
+  // Compute the new parameters (p' = ((W+U)^-1)U(m-p) + p)
+  TMatrixD tmp(hit,TMatrixD::kMinus,param);
+  TMatrixD tmp2(hitWeight,TMatrixD::kMult,tmp); // U(m-p)
+  TMatrixD newParam(newParamCov,TMatrixD::kMult,tmp2); // ((W+U)^-1)U(m-p)
+  newParam += param; // ((W+U)^-1)U(m-p) + p
+  
+  // Save the new parameters
+  trackParamAtHit.SetParameters(newParam);
+  
+  // Compute the additional chi2 (= ((p'-p)^-1)W(p'-p) + ((p'-m)^-1)U(p'-m))
+  tmp = newParam; // p'
+  tmp -= param; // (p'-p)
+  TMatrixD tmp3(paramWeight,TMatrixD::kMult,tmp); // W(p'-p)
+  TMatrixD addChi2Track(tmp,TMatrixD::kTransposeMult,tmp3); // ((p'-p)^-1)W(p'-p)
+  tmp = newParam; // p'
+  tmp -= hit; // (p'-m)
+  TMatrixD tmp4(hitWeight,TMatrixD::kMult,tmp); // U(p'-m)
+  addChi2Track += TMatrixD(tmp,TMatrixD::kTransposeMult,tmp4); // ((p'-p)^-1)W(p'-p) + ((p'-m)^-1)U(p'-m)
+  
+  return addChi2Track(0,0);
+  
 }
 
-//__________________________________________________________________________
-Bool_t AliMUONTrackReconstructorK::CheckCandidate(Int_t icand, Int_t nSeeds) const
+  //__________________________________________________________________________
+void AliMUONTrackReconstructorK::UpdateTrack(AliMUONTrack &track, AliMUONTrackParam &trackParamAtHit, Double_t addChi2)
 {
-  /// Discards track candidate if it will produce the double track (having
-  /// the same seed segment hits as hits of a good track found before)
-  AliMUONTrackK *track1, *track2;
-  AliMUONHitForRec *hit1, *hit2, *hit;
-  AliMUONObjectPair *segment1, *segment2;
+  /// Add 1 hit to the track candidate
+  /// Update chi2 of the track 
+  
+  // Update the track chi2 into TrackParamAtHit
+  trackParamAtHit.SetTrackChi2(track.GetFitFMin() + addChi2);
+  
+  // Update the chi2 of the new track
+  track.SetFitFMin(trackParamAtHit.GetTrackChi2());
+  
+  // Update array of TrackParamAtHit
+  track.AddTrackParamAtHit(&trackParamAtHit,trackParamAtHit.GetHitForRecPtr());
+  track.GetTrackParamAtHit()->Sort();
+  
+}
 
-  track1 = (AliMUONTrackK*) ((*fRecTracksPtr)[icand]);
-  hit1 = (AliMUONHitForRec*) (*track1->GetTrackHits())[0]; // 1'st hit
-  hit2 = (AliMUONHitForRec*) (*track1->GetTrackHits())[1]; // 2'nd hit
+  //__________________________________________________________________________
+void AliMUONTrackReconstructorK::UpdateTrack(AliMUONTrack &track, AliMUONTrackParam &trackParamAtHit1, AliMUONTrackParam &trackParamAtHit2,
+                                            Double_t addChi2AtHit1, Double_t addChi2AtHit2)
+{
+  /// Add 2 hits to the track candidate
+  /// Update track and local chi2
+  
+  // Update local chi2 at first hit
+  AliMUONHitForRec* hit1 = trackParamAtHit1.GetHitForRecPtr();
+  Double_t deltaX = trackParamAtHit1.GetNonBendingCoor() - hit1->GetNonBendingCoor();
+  Double_t deltaY = trackParamAtHit1.GetBendingCoor() - hit1->GetBendingCoor();
+  Double_t localChi2AtHit1 = deltaX*deltaX / hit1->GetNonBendingReso2() +
+                            deltaY*deltaY / hit1->GetBendingReso2();
+  trackParamAtHit1.SetLocalChi2(localChi2AtHit1);
+  
+  // Flag first hit as being removable
+  trackParamAtHit1.SetRemovable(kTRUE);
+  
+  // Update local chi2 at second hit
+  AliMUONHitForRec* hit2 = trackParamAtHit2.GetHitForRecPtr();
+  AliMUONTrackParam extrapTrackParamAtHit2(trackParamAtHit1);
+  AliMUONTrackExtrap::ExtrapToZ(&extrapTrackParamAtHit2, trackParamAtHit2.GetZ());
+  deltaX = extrapTrackParamAtHit2.GetNonBendingCoor() - hit2->GetNonBendingCoor();
+  deltaY = extrapTrackParamAtHit2.GetBendingCoor() - hit2->GetBendingCoor();
+  Double_t localChi2AtHit2 = deltaX*deltaX / hit2->GetNonBendingReso2() +
+                            deltaY*deltaY / hit2->GetBendingReso2();
+  trackParamAtHit2.SetLocalChi2(localChi2AtHit2);
+  
+  // Flag second hit as being removable
+  trackParamAtHit2.SetRemovable(kTRUE);
+  
+  // Update the track chi2 into TrackParamAtHit1
+  trackParamAtHit1.SetTrackChi2(track.GetFitFMin() + addChi2AtHit1);
+  
+  // Update the track chi2 into TrackParamAtHit2
+  trackParamAtHit2.SetTrackChi2(trackParamAtHit1.GetTrackChi2() + addChi2AtHit2);
+  
+  // Update the chi2 of the new track
+  track.SetFitFMin(trackParamAtHit2.GetTrackChi2());
+  
+  // Update array of TrackParamAtHit
+  track.AddTrackParamAtHit(&trackParamAtHit1,trackParamAtHit1.GetHitForRecPtr());
+  track.AddTrackParamAtHit(&trackParamAtHit2,trackParamAtHit2.GetHitForRecPtr());
+  track.GetTrackParamAtHit()->Sort();
+  
+}
 
-  for (Int_t i=0; i<icand; i++) {
-    track2 = (AliMUONTrackK*) ((*fRecTracksPtr)[i]);
-    //if (track2->GetRecover() < 0) continue;
-    if (track2->GetRecover() < 0 && icand >= nSeeds) continue;
-    segment1 = track1->GetStartSegment();
-    segment2 = track2->GetStartSegment();
-    if (segment1->First()  == segment2->First() &&
-        segment1->Second() == segment2->Second()) {
-      return kFALSE;
-    } else {
-      Int_t nSame = 0;
-      for (Int_t j=0; j<track2->GetNTrackHits(); j++) {
-        hit = (AliMUONHitForRec*) (*track2->GetTrackHits())[j];
-        if (hit == hit1 || hit == hit2) {
-          nSame++;
-          if (nSame == 2) return kFALSE;
-        }
-      } // for (Int_t j=0;
+  //__________________________________________________________________________
+Bool_t AliMUONTrackReconstructorK::RecoverTrack(AliMUONTrack &trackCandidate, Int_t nextStation)
+{
+  /// Try to recover the track candidate in the next station
+  /// by removing the worst of the two hits attached in the current station
+  /// Return kTRUE if recovering succeeds
+  AliDebug(1,"Enter RecoverTrack");
+  
+  // Do not try to recover track until we have attached hit(s) on station(1..) 3
+  if (nextStation > 1) return kFALSE;
+  
+  Int_t worstHitNumber = -1;
+  Double_t localChi2, worstChi2 = 0.;
+  
+  // Look for the hit to remove
+  for (Int_t hitNumber = 0; hitNumber < 2; hitNumber++) {
+    AliMUONTrackParam *trackParamAtHit = (AliMUONTrackParam*)trackCandidate.GetTrackParamAtHit()->UncheckedAt(hitNumber);
+    
+    // check if current hit is removable
+    if (!trackParamAtHit->IsRemovable()) return kFALSE;
+    
+    // Pick up hit with the worst chi2
+    localChi2 = trackParamAtHit->GetLocalChi2();
+    if (localChi2 > worstChi2) {
+      worstChi2 = localChi2;
+      worstHitNumber = hitNumber;
     }
-  } // for (Int_t i=0;
-  return kTRUE;
+  }
+  
+  // Reset best hit as being NOT removable
+  ((AliMUONTrackParam*)trackCandidate.GetTrackParamAtHit()->UncheckedAt((worstHitNumber+1)%2))->SetRemovable(kFALSE);
+  
+  // Remove the worst hit
+  trackCandidate.RemoveTrackParamAtHit((AliMUONTrackParam*)trackCandidate.GetTrackParamAtHit()->UncheckedAt(worstHitNumber));
+  
+  // Re-calculate track parameters at the (new) first hit
+  RetracePartialTrack(trackCandidate,(AliMUONTrackParam*)trackCandidate.GetTrackParamAtHit()->UncheckedAt(1));
+  
+  // Look for new hit(s) in next station
+  return FollowTrackInStation(trackCandidate,nextStation);
+  
 }
 
   //__________________________________________________________________________
-void AliMUONTrackReconstructorK::RemoveDoubleTracks(void)
+Bool_t AliMUONTrackReconstructorK::RunSmoother(AliMUONTrack &track)
 {
-  /// Removes double tracks (sharing more than half of their hits).
-  /// Keeps the track with higher quality
-  AliMUONTrackK *track1, *track2, *trackToKill;
-
-  // Sort tracks according to their quality
-  fRecTracksPtr->Sort();
-
-  // Loop over first track of the pair
-  track1 = (AliMUONTrackK*) fRecTracksPtr->First();
-  Int_t debug = track1->DebugLevel();
-  while (track1) {
-    // Loop over second track of the pair
-    track2 = (AliMUONTrackK*) fRecTracksPtr->After(track1);
-    while (track2) {
-      // Check whether or not to keep track2
-      if (!track2->KeepTrack(track1)) {
-        if (debug >= 0) cout << " Killed track: " << 1/(*track2->GetTrackParameters())(4,0) <<
-         " " << track2->GetTrackQuality() << endl;
-        trackToKill = track2;
-        track2 = (AliMUONTrackK*) fRecTracksPtr->After(track2);
-        trackToKill->Kill();
-        fRecTracksPtr->Compress();
-      } else track2 = (AliMUONTrackK*) fRecTracksPtr->After(track2);
-    } // track2
-    track1 = (AliMUONTrackK*) fRecTracksPtr->After(track1);
-  } // track1
-
-  fNRecTracks = fRecTracksPtr->GetEntriesFast();
-  if (debug >= 0) cout << " Number of Kalman tracks: " << fNRecTracks << endl;
+  /// Compute new track parameters and their covariances using smoother
+  AliDebug(1,"Enter RunSmoother");
+  
+  AliMUONTrackParam *previousTrackParam = (AliMUONTrackParam*) track.GetTrackParamAtHit()->First();
+  
+  // Smoothed parameters and covariances at first hit = filtered parameters and covariances
+  previousTrackParam->SetSmoothParameters(previousTrackParam->GetParameters());
+  previousTrackParam->SetSmoothCovariances(previousTrackParam->GetCovariances());
+  
+  // Compute local chi2 at first hit
+  AliMUONHitForRec *hitForRecAtHit = previousTrackParam->GetHitForRecPtr();
+  Double_t dX = hitForRecAtHit->GetNonBendingCoor() - previousTrackParam->GetNonBendingCoor();
+  Double_t dY = hitForRecAtHit->GetBendingCoor() - previousTrackParam->GetBendingCoor();
+  Double_t localChi2 = dX * dX / hitForRecAtHit->GetNonBendingReso2() + dY * dY / hitForRecAtHit->GetBendingReso2();
+  
+  // Save local chi2 at first hit
+  previousTrackParam->SetLocalChi2(localChi2);
+  
+  AliMUONTrackParam *currentTrackParam = (AliMUONTrackParam*) track.GetTrackParamAtHit()->After(previousTrackParam);
+  while (currentTrackParam) {
+    
+    // Get variables
+    const TMatrixD &extrapParameters          = previousTrackParam->GetExtrapParameters();  // X(k+1 k)
+    const TMatrixD &filteredParameters        = currentTrackParam->GetParameters();         // X(k k)
+    const TMatrixD &previousSmoothParameters  = previousTrackParam->GetSmoothParameters();  // X(k+1 n)
+    const TMatrixD &propagator                = previousTrackParam->GetPropagator();        // F(k)
+    const TMatrixD &extrapCovariances         = previousTrackParam->GetExtrapCovariances(); // C(k+1 k)
+    const TMatrixD &filteredCovariances       = currentTrackParam->GetCovariances();        // C(k k)
+    const TMatrixD &previousSmoothCovariances = previousTrackParam->GetSmoothCovariances(); // C(k+1 n)
+    
+    // Compute smoother gain: A(k) = C(kk) * F(f)^t * (C(k+1 k))^-1
+    TMatrixD extrapWeight(extrapCovariances);
+    if (extrapWeight.Determinant() != 0) {
+      extrapWeight.Invert(); // (C(k+1 k))^-1
+    } else {
+      AliWarning(" Determinant = 0");
+      return kFALSE;
+    }
+    TMatrixD smootherGain(filteredCovariances,TMatrixD::kMultTranspose,propagator); // C(kk) * F(f)^t
+    smootherGain *= extrapWeight; // C(kk) * F(f)^t * (C(k+1 k))^-1
+    
+    // Compute smoothed parameters: X(k n) = X(k k) + A(k) * (X(k+1 n) - X(k+1 k))
+    TMatrixD tmpParam(previousSmoothParameters,TMatrixD::kMinus,extrapParameters); // X(k+1 n) - X(k+1 k)
+    TMatrixD smoothParameters(smootherGain,TMatrixD::kMult,tmpParam); // A(k) * (X(k+1 n) - X(k+1 k))
+    smoothParameters += filteredParameters; // X(k k) + A(k) * (X(k+1 n) - X(k+1 k))
+    
+    // Save smoothed parameters
+    currentTrackParam->SetSmoothParameters(smoothParameters);
+    
+    // Compute smoothed covariances: C(k n) = C(k k) + A(k) * (C(k+1 n) - C(k+1 k)) * (A(k))^t
+    TMatrixD tmpCov(previousSmoothCovariances,TMatrixD::kMinus,extrapCovariances); // C(k+1 n) - C(k+1 k)
+    TMatrixD tmpCov2(tmpCov,TMatrixD::kMultTranspose,smootherGain); // (C(k+1 n) - C(k+1 k)) * (A(k))^t
+    TMatrixD smoothCovariances(smootherGain,TMatrixD::kMult,tmpCov2); // A(k) * (C(k+1 n) - C(k+1 k)) * (A(k))^t
+    smoothCovariances += filteredCovariances; // C(k k) + A(k) * (C(k+1 n) - C(k+1 k)) * (A(k))^t
+    
+    // Save smoothed covariances
+    currentTrackParam->SetSmoothCovariances(smoothCovariances);
+    
+    // Compute smoothed residual: r(k n) = hit - X(k n)
+    hitForRecAtHit = currentTrackParam->GetHitForRecPtr();
+    TMatrixD smoothResidual(2,1);
+    smoothResidual.Zero();
+    smoothResidual(0,0) = hitForRecAtHit->GetNonBendingCoor() - smoothParameters(0,0);
+    smoothResidual(1,0) = hitForRecAtHit->GetBendingCoor() - smoothParameters(2,0);
+    
+    // Compute weight of smoothed residual: W(k n) = (hitCov - C(k n))^-1
+    TMatrixD smoothResidualWeight(2,2);
+    smoothResidualWeight(0,0) = hitForRecAtHit->GetNonBendingReso2() - smoothCovariances(0,0);
+    smoothResidualWeight(0,1) = - smoothCovariances(0,2);
+    smoothResidualWeight(1,0) = - smoothCovariances(2,0);
+    smoothResidualWeight(1,1) = hitForRecAtHit->GetBendingReso2() - smoothCovariances(2,2);
+    if (smoothResidualWeight.Determinant() != 0) {
+      smoothResidualWeight.Invert();
+    } else {
+      AliWarning(" Determinant = 0");
+      return kFALSE;
+    }
+    
+    // Compute local chi2 = (r(k n))^t * W(k n) * r(k n)
+    TMatrixD tmpChi2(smoothResidual,TMatrixD::kTransposeMult,smoothResidualWeight); // (r(k n))^t * W(k n)
+    TMatrixD localChi2(tmpChi2,TMatrixD::kMult,smoothResidual); // (r(k n))^t * W(k n) * r(k n)
+    
+    // Save local chi2
+    currentTrackParam->SetLocalChi2(localChi2(0,0));
+    
+    previousTrackParam = currentTrackParam;
+    currentTrackParam = (AliMUONTrackParam*) track.GetTrackParamAtHit()->After(previousTrackParam);
+  }
+  
+  return kTRUE;
+  
 }
 
   //__________________________________________________________________________
-void AliMUONTrackReconstructorK::FillMUONTrack()
+void AliMUONTrackReconstructorK::ImproveTracks()
 {
-  // Set track parameters at hits for Kalman track. Fill fTrackParamAtHit of AliMUONTrack's
-  AliMUONTrackK *track;
-  track = (AliMUONTrackK*) fRecTracksPtr->First();
+  /// Improve tracks by removing clusters with local chi2 highter than the defined cut
+  /// Recompute track parameters and covariances at the remaining clusters
+  AliDebug(1,"Enter ImproveTracks");
+  
+  Double_t localChi2, worstLocalChi2;
+  Int_t worstChamber;
+  AliMUONTrackParam *trackParamAtHit, *worstTrackParamAtHit;
+  Bool_t smoothed;
+  
+  // Remove double track to improve only "good" tracks
+  RemoveDoubleTracks();
+  
+  AliMUONTrack *track = (AliMUONTrack*) fRecTracksPtr->First();
   while (track) {
-    track->FillMUONTrack();
-    track = (AliMUONTrackK*) fRecTracksPtr->After(track);
-  } 
-  return;
+    
+    while (!track->IsImproved()) {
+      
+      // Run smoother if required
+      smoothed = kFALSE;
+      if (fgkRunSmoother) smoothed = RunSmoother(*track);
+      
+      // Use standard procedure to compute local chi2 if smoother not required or not working
+      if (!smoothed) {
+        
+        // Update track parameters and covariances
+        track->UpdateCovTrackParamAtHit();
+        
+        // Compute local chi2 of each hits
+        track->ComputeLocalChi2(kTRUE);
+      }
+      
+      // Look for the hit to remove
+      worstTrackParamAtHit = NULL;
+      worstLocalChi2 = 0.;
+      trackParamAtHit = (AliMUONTrackParam*)track->GetTrackParamAtHit()->First();
+      while (trackParamAtHit) {
+        
+        // Pick up hit with the worst chi2
+        localChi2 = trackParamAtHit->GetLocalChi2();
+        if (localChi2 > worstLocalChi2) {
+          worstLocalChi2 = localChi2;
+          worstTrackParamAtHit = trackParamAtHit;
+        }
+        
+      trackParamAtHit = (AliMUONTrackParam*)track->GetTrackParamAtHit()->After(trackParamAtHit);
+      }
+      
+      // Check if bad removable hit found
+      if (!worstTrackParamAtHit) {
+        track->SetImproved(kTRUE);
+        break;
+      }
+      
+      // check whether the worst hit is removable or not
+      if (!worstTrackParamAtHit->IsRemovable()) {
+        track->SetImproved(kTRUE);
+        break;
+      }
+      
+      // Check whether the worst chi2 is under requirement or not
+      if (worstLocalChi2 < 2. * fgkSigmaToCutForImprovement * fgkSigmaToCutForImprovement) { // 2 because 2 quantities in chi2
+        track->SetImproved(kTRUE);
+        break;
+      }
+      
+      // Reset the second hit in the same station as the bad one as being NOT removable
+      worstChamber = worstTrackParamAtHit->GetHitForRecPtr()->GetChamberNumber();
+      if (worstChamber%2 == 0) ((AliMUONTrackParam*)track->GetTrackParamAtHit()->After(worstTrackParamAtHit))->SetRemovable(kFALSE);
+      else ((AliMUONTrackParam*)track->GetTrackParamAtHit()->Before(worstTrackParamAtHit))->SetRemovable(kFALSE);
+      
+      // Save pointer to the trackParamAtHit next to the one to be removed
+      trackParamAtHit = (AliMUONTrackParam*)track->GetTrackParamAtHit()->After(worstTrackParamAtHit);
+      
+      // Remove the worst hit
+      track->RemoveTrackParamAtHit(worstTrackParamAtHit);
+      
+      // Re-calculate track parameters
+      // - from the hit immediately downstream the one suppressed
+      // - or from the begining - if parameters have been re-computed using the standard method (kalman parameters have been lost)
+      //                       - or if the removed hit was the last one
+      if (smoothed && trackParamAtHit) RetracePartialTrack(*track,trackParamAtHit);
+      else RetraceTrack(*track,kTRUE);
+      
+      // Printout for debuging
+      if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
+        cout << "ImproveTracks: track " << fRecTracksPtr->IndexOf(track)+1 << " improved " << endl;
+      }
+      
+    }
+    
+    track = (AliMUONTrack*) fRecTracksPtr->After(track);
+  }
+  
 }
 
-
   //__________________________________________________________________________
-void AliMUONTrackReconstructorK::EventDump(void)
+void AliMUONTrackReconstructorK::Finalize()
 {
-  /// Dump reconstructed event (track parameters at vertex and at first hit),
-  /// and the particle parameters
-  AliDebug(1,"****** enter EventDump ******");
-  AliDebug(1, Form("Number of Reconstructed tracks : %d", fNRecTracks));
-                                                                                
-  Int_t debug =   ((AliMUONTrackK*) fRecTracksPtr->First())->DebugLevel();
-  if (debug < 0) return;
-                                                                                
-  for (Int_t i = 0; i < fNRecTracks; ++i) {
-    AliMUONTrackK *track = (AliMUONTrackK*) fRecTracksPtr->UncheckedAt(i);
-    track->Print("");
+  /// Fill AliMUONTrack's fHitForRecAtHit array
+  AliMUONTrack *track;
+  AliMUONTrackParam *trackParamAtHit;
+  Bool_t smoothed = kFALSE;
+  
+  track = (AliMUONTrack*) fRecTracksPtr->First();
+  while (track) {
+    
+    // update track parameters (using smoother if required) if not already done
+    if (!track->IsImproved()) {
+      smoothed = kFALSE;
+      if (fgkRunSmoother) smoothed = RunSmoother(*track);
+      if (!smoothed) track->UpdateCovTrackParamAtHit();
+    }
+    
+    trackParamAtHit = (AliMUONTrackParam*) (track->GetTrackParamAtHit()->First());
+    while (trackParamAtHit) {
+      
+      // copy smoothed parameters and covariances if any
+      if (smoothed) {
+        trackParamAtHit->SetParameters(trackParamAtHit->GetSmoothParameters());
+        trackParamAtHit->SetCovariances(trackParamAtHit->GetSmoothCovariances());
+      }
+      
+      // update array of track hits
+      track->AddHitForRecAtHit(trackParamAtHit->GetHitForRecPtr());
+      
+      trackParamAtHit = (AliMUONTrackParam*) (track->GetTrackParamAtHit()->After(trackParamAtHit));
+    }
+    
+    track = (AliMUONTrack*) fRecTracksPtr->After(track);
+    
   }
+    
 }
+
index e3b6a7f3d1655bc87dbc5e6050cc26b9f4bf4344..4f6b3555dc58ff9de9e03e0fce73dc54a640e9d7 100644 (file)
 
 #include "AliMUONVTrackReconstructor.h"
 
+class AliMUONTrack;
+class AliMUONTrackParam;
+
 class AliMUONTrackReconstructorK : public AliMUONVTrackReconstructor 
 {
 
  public:
-  AliMUONTrackReconstructorK(const Option_t* TrackMethod); // default Constructor
+  
+  AliMUONTrackReconstructorK(); // default Constructor
   virtual ~AliMUONTrackReconstructorK(); // Destructor
 
-          /// Return track method
-  Int_t GetTrackMethod(void) const {return fTrackMethod;} 
-  virtual void EventDump(void);  // dump reconstructed event
-  
+
  protected:
-  
-  virtual void MakeTracks(void);
-  virtual void MakeTrackCandidates(void);
-  virtual void FollowTracks(void);
-  virtual void RemoveDoubleTracks(void);
-  virtual void FillMUONTrack(void);
+
+  // Functions
+  virtual void MakeTrackCandidates();
+  virtual void FollowTracks();
+  virtual void ImproveTracks();
+  virtual void Finalize();
   
 
  private:
-
-  Int_t fTrackMethod; ///< AZ - tracking method
-
+  
+  // Parameters for track reconstruction
+  static const Bool_t fgkRunSmoother; ///< kTRUE to run the smoother
+  
+  
   // Functions
-  AliMUONTrackReconstructorK (const AliMUONTrackReconstructorK& rhs); ///< copy constructor
-  AliMUONTrackReconstructorK& operator=(const AliMUONTrackReconstructorK& rhs); ///< assignment operator
+  /// Not implemented copy constructor
+  AliMUONTrackReconstructorK (const AliMUONTrackReconstructorK& rhs); 
+  /// Not implemented copy assignment operator
+  AliMUONTrackReconstructorK& operator=(const AliMUONTrackReconstructorK& rhs);
+  
+  void RetraceTrack(AliMUONTrack &trackCandidate, Bool_t resetSeed);
+  void RetracePartialTrack(AliMUONTrack &trackCandidate, const AliMUONTrackParam* startingTrackParam);
+  
+  Bool_t FollowTrackInStation(AliMUONTrack &trackCandidate, Int_t nextStation);
+  
+  Double_t RunKalmanFilter(AliMUONTrackParam &trackParamAtHit);
+
+  void UpdateTrack(AliMUONTrack &track, AliMUONTrackParam &trackParamAtHit, Double_t addChi2);
+  void UpdateTrack(AliMUONTrack &track, AliMUONTrackParam &trackParamAtHit1, AliMUONTrackParam &trackParamAtHit2,
+                  Double_t addChi2AtHit1, Double_t addChi2AtHit2);
+  
+  Bool_t RecoverTrack(AliMUONTrack &track, Int_t nextStation);
   
-  Bool_t CheckCandidate(Int_t icand, Int_t nSeeds) const;
+  Bool_t RunSmoother(AliMUONTrack &track);
 
 
   ClassDef(AliMUONTrackReconstructorK, 0) // MUON track reconstructor in ALICE
-    };
+};
        
 #endif
index 09dae3aa760156834de71ab1783fc994e2c350ac..53438051cab8d4b7e9d40e20bf3e150a9fa5d4b2 100644 (file)
@@ -13,6 +13,8 @@
  * provided "as is" without express or implied warranty.                  *
  **************************************************************************/
 
+/* $Id$ */
+
 /// \class AliMUONTracker
 ///
 /// Steering class for use in global tracking framework;
 
 #include "AliMUONTracker.h"
 
-#include "AliESD.h"
-#include "AliESDMuonTrack.h"
-#include "AliESDVertex.h"
-#include "AliLoader.h"
 #include "AliMUONTrack.h"
 #include "AliMUONTrackExtrap.h"
 #include "AliMUONTrackHitPattern.h"
 #include "AliMUONTriggerTrackStoreV1.h"
 #include "AliMUONVClusterStore.h"
 #include "AliMUONVTriggerStore.h"
+
+#include "AliESD.h"
+#include "AliESDMuonTrack.h"
+#include "AliESDVertex.h"
+#include "AliLoader.h"
+#include "AliLog.h"
+
 #include <Riostream.h>
 #include <TTree.h>
-#include "AliLog.h"
 
 //_____________________________________________________________________________
 AliMUONTracker::AliMUONTracker(AliLoader* loader,
@@ -259,13 +263,9 @@ void AliMUONTracker::SetOption(Option_t* option)
   {
     fTrackReco = new AliMUONTrackReconstructor;
   }
-  else if (strstr(option,"Combi")) 
-  {
-    fTrackReco = new AliMUONTrackReconstructorK("Combi");
-  }
   else 
   {
-    fTrackReco = new AliMUONTrackReconstructorK("Kalman");
+    fTrackReco = new AliMUONTrackReconstructorK();
   }
 }
 
index f6829574acb680f1429f9a598b983ad2d4ff9def..293c70726bbee1093d48154c3541520cbaea27a5 100644 (file)
@@ -35,8 +35,8 @@
 
 #include "AliMUONVTrackReconstructor.h"
 
-#include "AliMpDEManager.h"
 #include "AliMUONConstants.h"
+#include "AliMUONRawCluster.h"
 #include "AliMUONHitForRec.h"
 #include "AliMUONObjectPair.h"
 #include "AliMUONTriggerTrack.h"
 #include "AliMUONVTrackStore.h"
 #include "AliMUONVClusterStore.h"
 #include "AliMUONRawCluster.h"
-#include "AliLog.h"
-#include "AliTracker.h"
 #include "AliMUONVTriggerStore.h"
 #include "AliMUONVTriggerTrackStore.h"
+#include "AliMpDEManager.h"
+
+#include "AliLog.h"
+#include "AliTracker.h"
 
-#include <Riostream.h>
 #include <TClonesArray.h>
 #include <TMath.h>
+#include <TMatrixD.h>
+
+#include <Riostream.h>
 
 /// \cond CLASSIMP
 ClassImp(AliMUONVTrackReconstructor) // Class implementation in ROOT context
@@ -66,21 +70,22 @@ ClassImp(AliMUONVTrackReconstructor) // Class implementation in ROOT context
 //************* Defaults parameters for reconstruction
 const Double_t AliMUONVTrackReconstructor::fgkDefaultMinBendingMomentum = 3.0;
 const Double_t AliMUONVTrackReconstructor::fgkDefaultMaxBendingMomentum = 3000.0;
-const Double_t AliMUONVTrackReconstructor::fgkDefaultBendingResolution = 0.01;
-const Double_t AliMUONVTrackReconstructor::fgkDefaultNonBendingResolution = 0.144;
-const Double_t AliMUONVTrackReconstructor::fgkDefaultBendingVertexDispersion = 10.;
-const Double_t AliMUONVTrackReconstructor::fgkDefaultNonBendingVertexDispersion = 10.;
 const Double_t AliMUONVTrackReconstructor::fgkDefaultMaxNormChi2MatchTrigger = 16.0;
 
-//__________________________________________________________________________
+const Double_t AliMUONVTrackReconstructor::fgkSigmaToCutForTracking = 6.0;
+const Double_t AliMUONVTrackReconstructor::fgkSigmaToCutForImprovement = 4.0;
+const Bool_t   AliMUONVTrackReconstructor::fgkTrackAllTracks = kTRUE;
+const Double_t AliMUONVTrackReconstructor::fgkMaxTrackingDistanceBending    = 2.;
+const Double_t AliMUONVTrackReconstructor::fgkMaxTrackingDistanceNonBending = 2.;
+const Bool_t   AliMUONVTrackReconstructor::fgkRecoverTracks = kTRUE;
+const Bool_t   AliMUONVTrackReconstructor::fgkImproveTracks = kTRUE;
+
+
+  //__________________________________________________________________________
 AliMUONVTrackReconstructor::AliMUONVTrackReconstructor()
   : TObject(),
     fMinBendingMomentum(fgkDefaultMinBendingMomentum),
     fMaxBendingMomentum(fgkDefaultMaxBendingMomentum),
-    fBendingResolution(fgkDefaultBendingResolution),
-    fNonBendingResolution(fgkDefaultNonBendingResolution),
-    fBendingVertexDispersion(fgkDefaultBendingVertexDispersion),
-    fNonBendingVertexDispersion(fgkDefaultNonBendingVertexDispersion),
     fMaxNormChi2MatchTrigger(fgkDefaultMaxNormChi2MatchTrigger),
     fHitsForRecPtr(0x0),
     fNHitsForRec(0),
@@ -96,7 +101,9 @@ AliMUONVTrackReconstructor::AliMUONVTrackReconstructor()
   // Memory allocation for the TClonesArray of hits for reconstruction
   // Is 10000 the right size ????
   fHitsForRecPtr = new TClonesArray("AliMUONHitForRec", 10000);
-  fHitsForRecPtr->SetOwner(kTRUE);
+  
+  // Memory allocation for the TClonesArray of reconstructed tracks
+  fRecTracksPtr = new TClonesArray("AliMUONTrack", 10);
   
   // set the magnetic field for track extrapolations
   const AliMagF* kField = AliTracker::GetFieldMap();
@@ -105,17 +112,58 @@ AliMUONVTrackReconstructor::AliMUONVTrackReconstructor()
 }
 
   //__________________________________________________________________________
-AliMUONVTrackReconstructor::~AliMUONVTrackReconstructor(void)
+AliMUONVTrackReconstructor::~AliMUONVTrackReconstructor()
 {
   /// Destructor for class AliMUONVTrackReconstructor
   delete [] fNHitsForRecPerChamber;
   delete [] fIndexOfFirstHitForRecPerChamber;
   delete fHitsForRecPtr;
+  delete fRecTracksPtr;
 }
 
-//__________________________________________________________________________
-void 
-AliMUONVTrackReconstructor::AddHitsForRecFromRawClusters(const AliMUONVClusterStore& clusterStore)
+  //__________________________________________________________________________
+void AliMUONVTrackReconstructor::ResetHitsForRec()
+{
+  /// To reset the TClonesArray of HitsForRec,
+  /// and the number of HitForRec and the index of the first HitForRec per chamber
+  if (fHitsForRecPtr) fHitsForRecPtr->Clear("C");
+  fNHitsForRec = 0;
+  for (Int_t ch = 0; ch < AliMUONConstants::NTrackingCh(); ch++) {
+    fNHitsForRecPerChamber[ch] = 0;
+    fIndexOfFirstHitForRecPerChamber[ch] = 0;
+  }
+}
+
+  //__________________________________________________________________________
+void AliMUONVTrackReconstructor::ResetTracks()
+{
+  /// To reset the TClonesArray of reconstructed tracks
+  if (fRecTracksPtr) fRecTracksPtr->Clear("C");
+  fNRecTracks = 0;
+  return;
+}
+
+  //__________________________________________________________________________
+void AliMUONVTrackReconstructor::EventReconstruct(const AliMUONVClusterStore& clusterStore, AliMUONVTrackStore& trackStore)
+{
+  /// To reconstruct one event
+  AliDebug(1,"");
+  
+  ResetTracks();
+  ResetHitsForRec();
+  AddHitsForRecFromRawClusters(clusterStore);
+  MakeTracks();
+
+  // Add tracks to MUON data container 
+  for (Int_t i=0; i<fNRecTracks; ++i) 
+  {
+    AliMUONTrack * track = (AliMUONTrack*) fRecTracksPtr->At(i);
+    trackStore.Add(*track);
+  }
+}
+
+  //__________________________________________________________________________
+void AliMUONVTrackReconstructor::AddHitsForRecFromRawClusters(const AliMUONVClusterStore& clusterStore)
 {
   /// Build internal array of hit for rec from clusterStore
   
@@ -169,50 +217,6 @@ AliMUONVTrackReconstructor::AddHitsForRecFromRawClusters(const AliMUONVClusterSt
   }
 }
 
-//__________________________________________________________________________
-void AliMUONVTrackReconstructor::EventReconstruct(const AliMUONVClusterStore& clusterStore,
-                                                  AliMUONVTrackStore& trackStore)
-{
-  /// To reconstruct one event
-  AliDebug(1,"");
-  
-  ResetTracks(); //AZ
-  ResetHitsForRec(); //AZ
-  AddHitsForRecFromRawClusters(clusterStore);
-  MakeTracks();
-
-  // Add tracks to MUON data container 
-  for (Int_t i=0; i<fNRecTracks; ++i) 
-  {
-    AliMUONTrack * track = (AliMUONTrack*) fRecTracksPtr->At(i);
-    trackStore.Add(*track);
-  }
-}
-
-//__________________________________________________________________________
-void AliMUONVTrackReconstructor::ResetTracks(void)
-{
-  /// To reset the TClonesArray of reconstructed tracks
-  if (fRecTracksPtr) fRecTracksPtr->Clear("C");
-  // Delete in order that the Track destructors are called,
-  // hence the space for the TClonesArray of pointers to TrackHit's is freed
-  fNRecTracks = 0;
-  return;
-}
-
-  //__________________________________________________________________________
-void AliMUONVTrackReconstructor::ResetHitsForRec(void)
-{
-  /// To reset the array and the number of HitsForRec,
-  /// and also the number of HitsForRec
-  /// and the index of the first HitForRec per chamber
-  if (fHitsForRecPtr) fHitsForRecPtr->Clear("C");
-  fNHitsForRec = 0;
-  for (Int_t ch = 0; ch < AliMUONConstants::NTrackingCh(); ch++)
-    fNHitsForRecPerChamber[ch] = fIndexOfFirstHitForRecPerChamber[ch] = 0;
-  return;
-}
-
   //__________________________________________________________________________
 void AliMUONVTrackReconstructor::SortHitsForRecWithIncreasingChamber()
 {
@@ -243,6 +247,24 @@ void AliMUONVTrackReconstructor::SortHitsForRecWithIncreasingChamber()
   return;
 }
 
+  //__________________________________________________________________________
+void AliMUONVTrackReconstructor::MakeTracks()
+{
+  /// To make the tracks from the list of segments and points in all stations
+  AliDebug(1,"Enter MakeTracks");
+  // Look for candidates from at least 3 aligned points in stations(1..) 4 and 5
+  MakeTrackCandidates();
+  if (fRecTracksPtr->GetEntriesFast() == 0) return;
+  // Follow tracks in stations(1..) 3, 2 and 1
+  FollowTracks();
+  // Improve the reconstructed tracks
+  if (fgkImproveTracks) ImproveTracks();
+  // Remove double tracks
+  RemoveDoubleTracks();
+  // Fill AliMUONTrack data members
+  Finalize();
+}
+
   //__________________________________________________________________________
 TClonesArray* AliMUONVTrackReconstructor::MakeSegmentsInStation(Int_t station)
 {
@@ -309,7 +331,157 @@ TClonesArray* AliMUONVTrackReconstructor::MakeSegmentsInStation(Int_t station)
   return segments;
 }
 
-//__________________________________________________________________________
+  //__________________________________________________________________________
+void AliMUONVTrackReconstructor::RemoveIdenticalTracks()
+{
+  /// To remove identical tracks:
+  /// Tracks are considered identical if they have all their hits in common.
+  /// One keeps the track with the larger number of hits if need be
+  AliMUONTrack *track1, *track2, *trackToRemove;
+  Int_t hitsInCommon, nHits1, nHits2;
+  Bool_t removedTrack1;
+  // Loop over first track of the pair
+  track1 = (AliMUONTrack*) fRecTracksPtr->First();
+  while (track1) {
+    removedTrack1 = kFALSE;
+    nHits1 = track1->GetNTrackHits();
+    // Loop over second track of the pair
+    track2 = (AliMUONTrack*) fRecTracksPtr->After(track1);
+    while (track2) {
+      nHits2 = track2->GetNTrackHits();
+      // number of hits in common between two tracks
+      hitsInCommon = track1->HitsInCommon(track2);
+      // check for identical tracks
+      if ((hitsInCommon == nHits1) || (hitsInCommon == nHits2)) {
+        // decide which track to remove
+        if (nHits2 > nHits1) {
+         // remove track1 and continue the first loop with the track next to track1
+         trackToRemove = track1;
+         track1 = (AliMUONTrack*) fRecTracksPtr->After(track1);
+          fRecTracksPtr->Remove(trackToRemove);
+         fRecTracksPtr->Compress(); // this is essential to retrieve the TClonesArray afterwards
+         fNRecTracks--;
+         removedTrack1 = kTRUE;
+         break;
+       } else {
+         // remove track2 and continue the second loop with the track next to track2
+         trackToRemove = track2;
+         track2 = (AliMUONTrack*) fRecTracksPtr->After(track2);
+         fRecTracksPtr->Remove(trackToRemove);
+         fRecTracksPtr->Compress(); // this is essential to retrieve the TClonesArray afterwards
+         fNRecTracks--;
+        }
+      } else track2 = (AliMUONTrack*) fRecTracksPtr->After(track2);
+    } // track2
+    if (removedTrack1) continue;
+    track1 = (AliMUONTrack*) fRecTracksPtr->After(track1);
+  } // track1
+  return;
+}
+
+  //__________________________________________________________________________
+void AliMUONVTrackReconstructor::RemoveDoubleTracks()
+{
+  /// To remove double tracks:
+  /// Tracks are considered identical if more than half of the hits of the track
+  /// which has the smaller number of hits are in common with the other track.
+  /// Among two identical tracks, one keeps the track with the larger number of hits
+  /// or, if these numbers are equal, the track with the minimum chi2.
+  AliMUONTrack *track1, *track2, *trackToRemove;
+  Int_t hitsInCommon, nHits1, nHits2;
+  Bool_t removedTrack1;
+  // Loop over first track of the pair
+  track1 = (AliMUONTrack*) fRecTracksPtr->First();
+  while (track1) {
+    removedTrack1 = kFALSE;
+    nHits1 = track1->GetNTrackHits();
+    // Loop over second track of the pair
+    track2 = (AliMUONTrack*) fRecTracksPtr->After(track1);
+    while (track2) {
+      nHits2 = track2->GetNTrackHits();
+      // number of hits in common between two tracks
+      hitsInCommon = track1->HitsInCommon(track2);
+      // check for identical tracks
+      if (((nHits1 < nHits2) && (2 * hitsInCommon > nHits1)) || (2 * hitsInCommon > nHits2)) {
+        // decide which track to remove
+        if ((nHits1 > nHits2) || ((nHits1 == nHits2) && (track1->GetFitFMin() <= track2->GetFitFMin()))) {
+         // remove track2 and continue the second loop with the track next to track2
+         trackToRemove = track2;
+         track2 = (AliMUONTrack*) fRecTracksPtr->After(track2);
+         fRecTracksPtr->Remove(trackToRemove);
+         fRecTracksPtr->Compress(); // this is essential to retrieve the TClonesArray afterwards
+         fNRecTracks--;
+        } else {
+         // else remove track1 and continue the first loop with the track next to track1
+         trackToRemove = track1;
+         track1 = (AliMUONTrack*) fRecTracksPtr->After(track1);
+          fRecTracksPtr->Remove(trackToRemove);
+         fRecTracksPtr->Compress(); // this is essential to retrieve the TClonesArray afterwards
+         fNRecTracks--;
+         removedTrack1 = kTRUE;
+         break;
+        }
+      } else track2 = (AliMUONTrack*) fRecTracksPtr->After(track2);
+    } // track2
+    if (removedTrack1) continue;
+    track1 = (AliMUONTrack*) fRecTracksPtr->After(track1);
+  } // track1
+  return;
+}
+
+  //__________________________________________________________________________
+Double_t AliMUONVTrackReconstructor::TryOneHitForRec(const AliMUONTrackParam &trackParam, AliMUONHitForRec* hitForRec,
+                                                    AliMUONTrackParam &trackParamAtHit, Bool_t updatePropagator)
+{
+/// Test the compatibility between the track and the hitForRec (using trackParam's covariance matrix):
+/// return the corresponding Chi2
+/// return trackParamAtHit
+  
+  if (!trackParam.CovariancesExist()) AliWarning(" track parameter covariance matrix does not exist");
+  
+  // extrapolate track parameters and covariances at the z position of the tested hit
+  if (&trackParam != &trackParamAtHit) {
+    trackParamAtHit = trackParam;
+    AliMUONTrackExtrap::ExtrapToZCov(&trackParamAtHit, hitForRec->GetZ(), updatePropagator);
+  }
+  
+  // set pointer to hit into trackParamAtHit
+  trackParamAtHit.SetHitForRecPtr(hitForRec);
+  
+  // Set differences between trackParam and hitForRec in the bending and non bending directions
+  TMatrixD dPos(2,1);
+  dPos(0,0) = hitForRec->GetNonBendingCoor() - trackParamAtHit.GetNonBendingCoor();
+  dPos(1,0) = hitForRec->GetBendingCoor() - trackParamAtHit.GetBendingCoor();
+  
+  // quick test of hitForRec compatibility within a wide road of x*y = 10*1 cm2 to save computing time
+  if (TMath::Abs(dPos(0,0)) > fgkMaxTrackingDistanceNonBending ||
+      TMath::Abs(dPos(1,0)) > fgkMaxTrackingDistanceBending) return 1.e10;
+  
+  // Set the error matrix from trackParam covariances and hitForRec resolution
+  const TMatrixD& kParamCov = trackParamAtHit.GetCovariances();
+  TMatrixD error(2,2);
+  error(0,0) = kParamCov(0,0) + hitForRec->GetNonBendingReso2();
+  error(0,1) = kParamCov(0,2);
+  error(1,0) = kParamCov(2,0);
+  error(1,1) = kParamCov(2,2) + hitForRec->GetBendingReso2();
+  
+  // Invert the error matrix for Chi2 calculation
+  if (error.Determinant() != 0) {
+    error.Invert();
+  } else {
+    AliWarning(" Determinant error=0");
+    return 1.e10;
+  }
+  
+  // Compute the Chi2 value
+  TMatrixD tmp(dPos,TMatrixD::kTransposeMult,error);
+  TMatrixD result(tmp,TMatrixD::kMult,dPos);
+  
+  return result(0,0);
+  
+}
+
+  //__________________________________________________________________________
 void AliMUONVTrackReconstructor::ValidateTracksWithTrigger(AliMUONVTrackStore& trackStore,
                                                            const AliMUONVTriggerTrackStore& triggerTrackStore,
                                                            const AliMUONVTriggerStore& triggerStore,
@@ -410,11 +582,10 @@ void AliMUONVTrackReconstructor::ValidateTracksWithTrigger(AliMUONVTrackStore& t
   trackHitPattern.GetHitPattern(trackStore,triggerStore);
 }
 
-//__________________________________________________________________________
-void 
-AliMUONVTrackReconstructor::EventReconstructTrigger(const AliMUONTriggerCircuit& circuit,
-                                                    const AliMUONVTriggerStore& triggerStore,
-                                                    AliMUONVTriggerTrackStore& triggerTrackStore)
+  //__________________________________________________________________________
+void AliMUONVTrackReconstructor::EventReconstructTrigger(const AliMUONTriggerCircuit& circuit,
+                                                         const AliMUONVTriggerStore& triggerStore,
+                                                         AliMUONVTriggerTrackStore& triggerTrackStore)
 {
   /// To make the trigger tracks from Local Trigger
   AliDebug(1, "");
@@ -483,3 +654,4 @@ AliMUONVTrackReconstructor::EventReconstructTrigger(const AliMUONTriggerCircuit&
     } // board is fired 
   } // end of loop on Local Trigger
 }
+
index 509d2c7ee6454b9c8827a8181b49627c8d16718d..6be172033f8b7f779ff27c39268859244c0084fd 100644 (file)
@@ -14,6 +14,8 @@
 #include <TObject.h>
 
 class TClonesArray;
+class AliMUONTrackParam;
+class AliMUONHitForRec;
 class AliMUONTriggerTrack;
 class AliMUONTrackHitPattern;
 class AliMUONVClusterStore;
@@ -33,11 +35,7 @@ class AliMUONVTrackReconstructor : public TObject {
   // Parameters for track reconstruction: public methods
   // Get and Set, Set to defaults
            /// Return minimum value (GeV/c) of momentum in bending plane
-  Double_t GetMinBendingMomentum(void) const {return fMinBendingMomentum;}
-           /// Return chamber resolution (cm) in bending plane
-  Double_t GetBendingResolution(void) const {return fBendingResolution;}
-           /// Return chamber resolution (cm) in non-bending plane
-  Double_t GetNonBendingResolution(void) const {return fNonBendingResolution;}
+  Double_t GetMinBendingMomentum() const {return fMinBendingMomentum;}
 
   // Reconstructed tracks
            /// Return number of reconstructed tracks
@@ -45,7 +43,7 @@ class AliMUONVTrackReconstructor : public TObject {
            /// Set number of reconstructed tracks
   void SetNRecTracks(Int_t NRecTracks) {fNRecTracks = NRecTracks;}
            /// Return array of reconstructed tracks
-  TClonesArray* GetRecTracksPtr(void) const {return fRecTracksPtr;} // Array
+  TClonesArray* GetRecTracksPtr() const {return fRecTracksPtr;} // Array
  
   // Functions
   void EventReconstruct(const AliMUONVClusterStore& clusterStore,
@@ -59,25 +57,27 @@ class AliMUONVTrackReconstructor : public TObject {
                                  const AliMUONVTriggerTrackStore& triggerTrackStore,
                                  const AliMUONVTriggerStore& triggerStore,
                                  const AliMUONTrackHitPattern& trackHitPattern);
-    
+  
+  
  protected:
 
   // Defaults parameters for reconstruction
   static const Double_t fgkDefaultMinBendingMomentum; ///< default min. bending momentum for reconstruction
   static const Double_t fgkDefaultMaxBendingMomentum; ///< default max. bending momentum for reconstruction
-  static const Double_t fgkDefaultBendingResolution; ///< default bending coordinate resolution for reconstruction 
-  static const Double_t fgkDefaultNonBendingResolution; ///< default non bending coordinate resolution for reconstruction
-  static const Double_t fgkDefaultBendingVertexDispersion; ///< default vertex dispersion in bending plane for reconstruction
-  static const Double_t fgkDefaultNonBendingVertexDispersion; ///< default vertex dispersion in non bending plane for reconstruction
   static const Double_t fgkDefaultMaxNormChi2MatchTrigger; ///< default maximum normalized chi2 of tracking/trigger track matching
   
+  // Parameters for track reconstruction
+  static const Double_t fgkSigmaToCutForTracking; ///< cut in sigma to apply on cluster local chi2 and track global chi2 during tracking
+  static const Double_t fgkSigmaToCutForImprovement; ///< cut in sigma to apply on cluster local chi2 during track improvement
+  static const Bool_t   fgkTrackAllTracks; ///< kTRUE to track all the possible candidates; kFALSE to track only the best ones
+  static const Double_t fgkMaxTrackingDistanceBending;    ///< Maximum distance to the track to search for compatible hitForRec(s) in bending direction
+  static const Double_t fgkMaxTrackingDistanceNonBending; ///< Maximum distance to the track to search for compatible hitForRec(s) in non bending direction
+  static const Bool_t   fgkRecoverTracks; ///< kTRUE to try to recover the tracks being lost during reconstruction
+  static const Bool_t   fgkImproveTracks; ///< kTRUE to try to improve the reconstructed tracks
+  
   // Parameters for track reconstruction
   Double_t fMinBendingMomentum; ///< minimum value (GeV/c) of momentum in bending plane
   Double_t fMaxBendingMomentum; ///< maximum value (GeV/c) of momentum in bending plane
-  Double_t fBendingResolution; ///< chamber resolution (cm) in bending plane
-  Double_t fNonBendingResolution; ///< chamber resolution (cm) in non bending plane
-  Double_t fBendingVertexDispersion; ///< vextex dispersion (cm) in bending plane
-  Double_t fNonBendingVertexDispersion; ///< vextex dispersion (cm) in non bending plane
   Double_t fMaxNormChi2MatchTrigger; ///< maximum normalized chi2 of tracking/trigger track matching
   
   TClonesArray* fHitsForRecPtr; ///< pointer to the array of hits for reconstruction
@@ -89,31 +89,40 @@ class AliMUONVTrackReconstructor : public TObject {
   TClonesArray *fRecTracksPtr; ///< pointer to array of reconstructed tracks
   Int_t fNRecTracks; ///< number of reconstructed tracks
 
+
   // Functions
   AliMUONVTrackReconstructor (const AliMUONVTrackReconstructor& rhs); ///< copy constructor
   AliMUONVTrackReconstructor& operator=(const AliMUONVTrackReconstructor& rhs); ///< assignment operator
   
-  void SortHitsForRecWithIncreasingChamber();
-  TClonesArray *MakeSegmentsInStation(Int_t station);
+  /// Make track candidats from clusters in stations(1..) 4 and 5
+  virtual void MakeTrackCandidates() = 0;
+  /// Follow tracks in stations(1..) 3, 2 and 1
+  virtual void FollowTracks() = 0;
+  /// Improve the reconstructed tracks
+  virtual void ImproveTracks() = 0;
+  /// Finalize the tracking results
+  virtual void Finalize() = 0;
+  
+  TClonesArray* MakeSegmentsInStation(Int_t station);
 
-               /// \todo add comment
-  virtual void AddHitsForRecFromRawClusters(const AliMUONVClusterStore& clusterStore);
-               /// \todo add comment
-  virtual void MakeTracks(void) = 0;
-               /// \todo add comment
-  virtual void MakeTrackCandidates(void) = 0;
-               /// \todo add comment
-  virtual void FollowTracks(void) = 0;
-               /// \todo add comment
-  virtual void RemoveDoubleTracks(void) = 0;
-               /// \todo add comment
-  virtual void FillMUONTrack(void) = 0;
+  void RemoveIdenticalTracks();
+  void RemoveDoubleTracks();
+
+  Double_t TryOneHitForRec(const AliMUONTrackParam &trackParam, AliMUONHitForRec* hitForRec,
+                          AliMUONTrackParam &trackParamAtHit, Bool_t updatePropagator = kFALSE);
+  
 
  private:
   
   // Functions
-  void ResetTracks(void);
-  void ResetHitsForRec(void);
+  void ResetTracks();
+  void ResetHitsForRec();
+  
+  void AddHitsForRecFromRawClusters(const AliMUONVClusterStore& clusterStore);
+  void SortHitsForRecWithIncreasingChamber();
+  
+  void MakeTracks();
+  
   
   ClassDef(AliMUONVTrackReconstructor, 0) // MUON track reconstructor in ALICE
 };