]> git.uio.no Git - u/mrichter/AliRoot.git/blob - MUON/AliMUONTrackReconstructorK.cxx
Define default values of cluster resolution per chamber in the
[u/mrichter/AliRoot.git] / MUON / AliMUONTrackReconstructorK.cxx
1 /**************************************************************************
2  * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
3  *                                                                        *
4  * Author: The ALICE Off-line Project.                                    *
5  * Contributors are mentioned in the code where appropriate.              *
6  *                                                                        *
7  * Permission to use, copy, modify and distribute this software and its   *
8  * documentation strictly for non-commercial purposes is hereby granted   *
9  * without fee, provided that the above copyright notice appears in all   *
10  * copies and that both the copyright notice and this permission notice   *
11  * appear in the supporting documentation. The authors make no claims     *
12  * about the suitability of this software for any purpose. It is          *
13  * provided "as is" without express or implied warranty.                  *
14  **************************************************************************/
15
16 /* $Id$ */
17
18 //-----------------------------------------------------------------------------
19 /// \class AliMUONTrackReconstructorK
20 ///
21 /// MUON track reconstructor using the kalman method
22 ///
23 /// This class contains as data:
24 /// - the parameters for the track reconstruction
25 ///
26 /// It contains as methods, among others:
27 /// - MakeTracks to build the tracks
28 ///
29 //-----------------------------------------------------------------------------
30
31 #include "AliMUONTrackReconstructorK.h"
32
33 #include "AliMUONConstants.h"
34 #include "AliMUONVCluster.h"
35 #include "AliMUONVClusterServer.h"
36 #include "AliMUONVClusterStore.h"
37 #include "AliMUONTrack.h"
38 #include "AliMUONTrackParam.h"
39 #include "AliMUONTrackExtrap.h"
40
41 #include "AliMpArea.h"
42
43 #include "AliLog.h"
44
45 #include <Riostream.h>
46 #include <TMath.h>
47 #include <TMatrixD.h>
48
49 /// \cond CLASSIMP
50 ClassImp(AliMUONTrackReconstructorK) // Class implementation in ROOT context
51 /// \endcond
52
53   //__________________________________________________________________________
54 AliMUONTrackReconstructorK::AliMUONTrackReconstructorK(const AliMUONRecoParam* recoParam, AliMUONVClusterServer* clusterServer)
55   : AliMUONVTrackReconstructor(recoParam, clusterServer)
56 {
57   /// Constructor
58 }
59
60   //__________________________________________________________________________
61 AliMUONTrackReconstructorK::~AliMUONTrackReconstructorK()
62 {
63 /// Destructor
64
65
66   //__________________________________________________________________________
67 void AliMUONTrackReconstructorK::MakeTrackCandidates(AliMUONVClusterStore& clusterStore)
68 {
69   /// To make track candidates (assuming linear propagation if the flag fgkMakeTrackCandidatesFast is set to kTRUE):
70   /// Start with segments station(1..) 4 or 5 then follow track in station 5 or 4.
71   /// Good candidates are made of at least three clusters if both station are requested (two otherwise).
72   /// Keep only best candidates or all of them according to the flag fgkTrackAllTracks.
73   
74   TClonesArray *segments;
75   AliMUONTrack *track;
76   Int_t iCandidate = 0;
77   Bool_t clusterFound;
78
79   AliDebug(1,"Enter MakeTrackCandidates");
80
81   // Unless we're doing combined tracking, we'll clusterize all stations at once
82   Int_t firstChamber(0);
83   Int_t lastChamber(9);
84   
85   if (GetRecoParam()->CombineClusterTrackReco()) {
86     // ... Here's the exception : ask the clustering to reconstruct
87     // clusters *only* in station 4 and 5 for combined tracking
88     firstChamber = 6;
89   }
90   
91   for (Int_t i = firstChamber; i <= lastChamber; ++i ) 
92   {
93     if (fClusterServer && GetRecoParam()->UseChamber(i)) fClusterServer->Clusterize(i, clusterStore, AliMpArea(), GetRecoParam());
94   }
95   
96   // Loop over stations(1..) 5 and 4 and make track candidates
97   for (Int_t istat=4; istat>=3; istat--) {
98     
99     // Make segments in the station
100     segments = MakeSegmentsBetweenChambers(clusterStore, 2*istat, 2*istat+1);
101     
102     // Loop over segments
103     for (Int_t iseg=0; iseg<segments->GetEntriesFast(); iseg++) {
104       AliDebug(1,Form("Making primary candidate(1..) %d",++iCandidate));
105       
106       // Transform segments to tracks and put them at the end of fRecTracksPtr
107       track = new ((*fRecTracksPtr)[fRecTracksPtr->GetLast()+1]) AliMUONTrack((AliMUONObjectPair*)((*segments)[iseg]),GetRecoParam()->GetBendingVertexDispersion());
108       fNRecTracks++;
109       
110       // Look for compatible cluster(s) in the other station
111       if (GetRecoParam()->MakeTrackCandidatesFast())
112         clusterFound = FollowLinearTrackInStation(*track, clusterStore, 7-istat);
113       else {
114         // First recompute track parameters and covariances on station(1..) 5 using Kalman filter
115         // (to make sure all tracks are treated in the same way)
116         if (istat == 4) RetraceTrack(*track, kTRUE);
117         clusterFound = FollowTrackInStation(*track, clusterStore, 7-istat);
118       }
119       
120       // Remove track if no cluster found on a requested station
121       if (!clusterFound) {
122         if (GetRecoParam()->RequestStation(7-istat)) {
123           fRecTracksPtr->Remove(track);
124           fNRecTracks--;
125         } else if (istat == 3 && !GetRecoParam()->MakeTrackCandidatesFast()) {
126           // update track parameters and covariances using Kalman filter
127           RetraceTrack(*track, kTRUE);
128         }
129       }
130       
131     }
132     // delete the array of segments
133     delete segments;
134   }
135   
136   
137   // Retrace tracks using Kalman filter and remove bad ones
138   if (GetRecoParam()->MakeTrackCandidatesFast()) {
139     fRecTracksPtr->Compress(); // this is essential before checking tracks
140     
141     Int_t currentNRecTracks = fNRecTracks;
142     for (Int_t iRecTrack = 0; iRecTrack < currentNRecTracks; iRecTrack++) {
143       track = (AliMUONTrack*) fRecTracksPtr->UncheckedAt(iRecTrack);
144       
145       // Recompute track parameters and covariances using Kalman filter
146       RetraceTrack(*track,kTRUE);
147       
148       // Remove the track if the normalized chi2 is too high
149       if (track->GetNormalizedChi2() > GetRecoParam()->GetSigmaCutForTracking() *
150                                        GetRecoParam()->GetSigmaCutForTracking()) {
151         fRecTracksPtr->Remove(track);
152         fNRecTracks--;
153       }
154       
155     }
156     
157   }
158   
159   fRecTracksPtr->Compress(); // this is essential before checking tracks
160   
161   // Keep all different tracks or only the best ones as required
162   if (GetRecoParam()->TrackAllTracks()) RemoveIdenticalTracks();
163   else RemoveDoubleTracks();
164   
165   AliDebug(1,Form("Number of good candidates = %d",fNRecTracks));
166   
167 }
168
169   //__________________________________________________________________________
170 void AliMUONTrackReconstructorK::MakeMoreTrackCandidates(AliMUONVClusterStore& clusterStore)
171 {
172   /// To make extra track candidates (assuming linear propagation if the flag fgkMakeTrackCandidatesFast is set to kTRUE):
173   /// clustering is supposed to be already done
174   /// Start with segments made of 1 cluster in each of the stations 4 and 5 then follow track in remaining chambers.
175   /// Good candidates are made of at least three clusters if both station are requested (two otherwise).
176   /// Keep only best candidates or all of them according to the flag fgkTrackAllTracks.
177   
178   TClonesArray *segments;
179   AliMUONTrack *track;
180   Int_t iCandidate = 0, iCurrentTrack, nCurrentTracks;
181   Int_t initialNRecTracks = fNRecTracks;
182   Bool_t clusterFound;
183   
184   AliDebug(1,"Enter MakeMoreTrackCandidates");
185   
186   // Double loop over chambers in stations(1..) 4 and 5 to make track candidates
187   for (Int_t ich1 = 6; ich1 <= 7; ich1++) {
188     for (Int_t ich2 = 8; ich2 <= 9; ich2++) {
189       
190       // Make segments between ch1 and ch2
191       segments = MakeSegmentsBetweenChambers(clusterStore, ich1, ich2);
192       
193       // Loop over segments
194       for (Int_t iseg=0; iseg<segments->GetEntriesFast(); iseg++) {
195         AliDebug(1,Form("Making primary candidate(1..) %d",++iCandidate));
196         
197         // Transform segments to tracks and put them at the end of fRecTracksPtr
198         iCurrentTrack = fRecTracksPtr->GetLast()+1;
199         track = new ((*fRecTracksPtr)[iCurrentTrack]) AliMUONTrack((AliMUONObjectPair*)((*segments)[iseg]),GetRecoParam()->GetBendingVertexDispersion());
200         fNRecTracks++;
201         
202         // Look for compatible cluster(s) in the second chamber of station 5
203         if (GetRecoParam()->MakeTrackCandidatesFast())
204           clusterFound = FollowLinearTrackInChamber(*track, clusterStore, 17-ich2);
205         else clusterFound = FollowTrackInChamber(*track, clusterStore, 17-ich2);
206         
207         // skip the original track in case it has been removed
208         if (GetRecoParam()->TrackAllTracks() && clusterFound) iCurrentTrack++;
209         
210         // loop over every new tracks
211         nCurrentTracks = fRecTracksPtr->GetLast()+1;
212         while (iCurrentTrack < nCurrentTracks) {
213           track = (AliMUONTrack*) fRecTracksPtr->UncheckedAt(iCurrentTrack);
214           
215           // Look for compatible cluster(s) in the second chamber of station 4
216           if (GetRecoParam()->MakeTrackCandidatesFast())
217             FollowLinearTrackInChamber(*track, clusterStore, 13-ich1);
218           else FollowTrackInChamber(*track, clusterStore, 13-ich1);
219           
220           iCurrentTrack++;
221         }
222         
223       }
224       
225       // delete the array of segments
226       delete segments;
227     }
228   }
229   
230   fRecTracksPtr->Compress(); // this is essential before checking tracks
231   
232   // Retrace tracks using Kalman filter
233   for (Int_t iRecTrack = initialNRecTracks; iRecTrack < fNRecTracks; iRecTrack++) {
234     track = (AliMUONTrack*) fRecTracksPtr->UncheckedAt(iRecTrack);
235     
236     // Recompute track parameters and covariances using Kalman filter
237     RetraceTrack(*track,kTRUE);
238     
239     // Remove the track if the normalized chi2 is too high
240     // (only if the tracking has been done without magnetic field)
241     if (GetRecoParam()->MakeTrackCandidatesFast() &&
242         track->GetNormalizedChi2() > GetRecoParam()->GetSigmaCutForTracking() *
243                                      GetRecoParam()->GetSigmaCutForTracking()) {
244       fRecTracksPtr->Remove(track);
245       fNRecTracks--;
246     }
247     
248   }
249   
250   // this is essential before checking tracks
251   if (GetRecoParam()->MakeTrackCandidatesFast()) fRecTracksPtr->Compress();
252   
253   // Keep all different tracks or only the best ones as required
254   if (GetRecoParam()->TrackAllTracks()) RemoveIdenticalTracks();
255   else RemoveDoubleTracks();
256   
257   AliDebug(1,Form("Number of good candidates = %d",fNRecTracks));
258   
259 }
260
261   //__________________________________________________________________________
262 void AliMUONTrackReconstructorK::RetraceTrack(AliMUONTrack &trackCandidate, Bool_t resetSeed)
263 {
264   /// Re-run the kalman filter from the most downstream cluster to the most uptream one
265   AliDebug(1,"Enter RetraceTrack");
266   
267   AliMUONTrackParam* lastTrackParam = (AliMUONTrackParam*) trackCandidate.GetTrackParamAtCluster()->Last();
268   
269   // Reset the "seed" (= track parameters and their covariances at last cluster) if required
270   if (resetSeed) {
271     
272     // parameters at last cluster
273     AliMUONVCluster* cluster2 = lastTrackParam->GetClusterPtr();
274     Double_t x2 = cluster2->GetX();
275     Double_t y2 = cluster2->GetY();
276     Double_t z2 = cluster2->GetZ();
277     
278     // parameters at last but one cluster
279     AliMUONTrackParam* previousTrackParam = (AliMUONTrackParam*) trackCandidate.GetTrackParamAtCluster()->Before(lastTrackParam);
280     AliMUONVCluster* cluster1 = previousTrackParam->GetClusterPtr();
281     // make sure it is on the previous chamber (can have 2 clusters in the same chamber after "ComplementTrack")
282     if (cluster2->GetChamberId() == cluster1->GetChamberId()) {
283       previousTrackParam = (AliMUONTrackParam*) trackCandidate.GetTrackParamAtCluster()->Before(previousTrackParam);
284       cluster1 = previousTrackParam->GetClusterPtr();
285     }
286     Double_t x1 = cluster1->GetX();
287     Double_t y1 = cluster1->GetY();
288     Double_t z1 = cluster1->GetZ();
289     
290     // reset track parameters
291     Double_t dZ = z1 - z2;
292     lastTrackParam->SetNonBendingCoor(x2);
293     lastTrackParam->SetBendingCoor(y2);
294     lastTrackParam->SetZ(z2);
295     lastTrackParam->SetNonBendingSlope((x1 - x2) / dZ);
296     lastTrackParam->SetBendingSlope((y1 - y2) / dZ);
297     Double_t bendingImpact = y2 - z2 * lastTrackParam->GetBendingSlope();
298     Double_t inverseBendingMomentum = 1. / AliMUONTrackExtrap::GetBendingMomentumFromImpactParam(bendingImpact);
299     lastTrackParam->SetInverseBendingMomentum(inverseBendingMomentum);
300     
301     // => Reset track parameter covariances at last cluster (as if the other clusters did not exist)
302     TMatrixD lastParamCov(5,5);
303     lastParamCov.Zero();
304     // Non bending plane
305     lastParamCov(0,0) = cluster2->GetErrX2();
306     lastParamCov(1,1) = 100. * ( cluster1->GetErrX2() + cluster2->GetErrX2() ) / dZ / dZ;
307     // Bending plane
308     lastParamCov(2,2) = cluster2->GetErrY2();
309     lastParamCov(3,3) = 100. * ( cluster1->GetErrY2() + cluster2->GetErrY2() ) / dZ / dZ;
310     // Inverse bending momentum (vertex resolution + bending slope resolution + 10% error on dipole parameters+field)
311     lastParamCov(4,4) = ((GetRecoParam()->GetBendingVertexDispersion() *
312                           GetRecoParam()->GetBendingVertexDispersion() +
313                           (z1 * z1 * cluster2->GetErrY2() + z2 * z2 * cluster1->GetErrY2()) / dZ / dZ) /
314                          bendingImpact / bendingImpact + 0.1 * 0.1) * inverseBendingMomentum * inverseBendingMomentum;
315     lastTrackParam->SetCovariances(lastParamCov);
316     
317     // Reset the track chi2
318     lastTrackParam->SetTrackChi2(0.);
319   
320   }
321   
322   // Redo the tracking
323   RetracePartialTrack(trackCandidate, lastTrackParam);
324   
325 }
326
327   //__________________________________________________________________________
328 void AliMUONTrackReconstructorK::RetracePartialTrack(AliMUONTrack &trackCandidate, const AliMUONTrackParam* startingTrackParam)
329 {
330   /// Re-run the kalman filter from the cluster attached to startingTrackParam to the most uptream cluster
331   AliDebug(1,"Enter RetracePartialTrack");
332   
333   // Printout for debuging
334   if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
335     cout << "RetracePartialTrack: track chi2 before re-tracking: " << trackCandidate.GetGlobalChi2() << endl;
336   }
337   
338   // Reset the track chi2
339   trackCandidate.SetGlobalChi2(startingTrackParam->GetTrackChi2());
340   
341   // loop over attached clusters until the first one and recompute track parameters and covariances using kalman filter
342   Int_t expectedChamber = startingTrackParam->GetClusterPtr()->GetChamberId() - 1;
343   Int_t currentChamber;
344   Double_t addChi2TrackAtCluster;
345   AliMUONTrackParam* trackParamAtCluster = (AliMUONTrackParam*) trackCandidate.GetTrackParamAtCluster()->Before(startingTrackParam); 
346   while (trackParamAtCluster) {
347     
348     // reset track parameters and their covariances
349     trackParamAtCluster->SetParameters(startingTrackParam->GetParameters());
350     trackParamAtCluster->SetZ(startingTrackParam->GetZ());
351     trackParamAtCluster->SetCovariances(startingTrackParam->GetCovariances());
352     
353     // add MCS effect
354     AliMUONTrackExtrap::AddMCSEffect(trackParamAtCluster,AliMUONConstants::ChamberThicknessInX0(),1.);
355     
356     // reset propagator for smoother
357     if (GetRecoParam()->UseSmoother()) trackParamAtCluster->ResetPropagator();
358     
359     // add MCS in missing chambers if any
360     currentChamber = trackParamAtCluster->GetClusterPtr()->GetChamberId();
361     while (currentChamber < expectedChamber) {
362       // extrapolation to the missing chamber (update the propagator)
363       AliMUONTrackExtrap::ExtrapToZCov(trackParamAtCluster, AliMUONConstants::DefaultChamberZ(expectedChamber),
364                                        GetRecoParam()->UseSmoother());
365       // add MCS effect
366       AliMUONTrackExtrap::AddMCSEffect(trackParamAtCluster,AliMUONConstants::ChamberThicknessInX0(),1.);
367       expectedChamber--;
368     }
369     
370     // extrapolation to the plane of the cluster attached to the current trackParamAtCluster (update the propagator)
371     AliMUONTrackExtrap::ExtrapToZCov(trackParamAtCluster, trackParamAtCluster->GetClusterPtr()->GetZ(),
372                                      GetRecoParam()->UseSmoother());
373     
374     if (GetRecoParam()->UseSmoother()) {
375       // save extrapolated parameters for smoother
376       trackParamAtCluster->SetExtrapParameters(trackParamAtCluster->GetParameters());
377       
378       // save extrapolated covariance matrix for smoother
379       trackParamAtCluster->SetExtrapCovariances(trackParamAtCluster->GetCovariances());
380     }
381     
382     // Compute new track parameters using kalman filter
383     addChi2TrackAtCluster = RunKalmanFilter(*trackParamAtCluster);
384     
385     // Update the track chi2
386     trackCandidate.SetGlobalChi2(trackCandidate.GetGlobalChi2() + addChi2TrackAtCluster);
387     trackParamAtCluster->SetTrackChi2(trackCandidate.GetGlobalChi2());
388     
389     // prepare next step
390     expectedChamber = currentChamber - 1;
391     startingTrackParam = trackParamAtCluster;
392     trackParamAtCluster = (AliMUONTrackParam*) (trackCandidate.GetTrackParamAtCluster()->Before(startingTrackParam)); 
393   }
394   
395   // Printout for debuging
396   if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
397     cout << "RetracePartialTrack: track chi2 after re-tracking: " << trackCandidate.GetGlobalChi2() << endl;
398   }
399   
400 }
401
402   //__________________________________________________________________________
403 void AliMUONTrackReconstructorK::FollowTracks(AliMUONVClusterStore& clusterStore)
404 {
405   /// Follow tracks in stations(1..) 3, 2 and 1
406   AliDebug(1,"Enter FollowTracks");
407   
408   AliMUONTrack *track;
409   Int_t currentNRecTracks;
410   
411   for (Int_t station = 2; station >= 0; station--) {
412     
413     // Save the actual number of reconstructed track in case of
414     // tracks are added or suppressed during the tracking procedure
415     // !! Do not compress fRecTracksPtr until the end of the loop over tracks !!
416     currentNRecTracks = fNRecTracks;
417     
418     for (Int_t iRecTrack = 0; iRecTrack <currentNRecTracks; iRecTrack++) {
419       AliDebug(1,Form("FollowTracks: track candidate(1..) %d", iRecTrack+1));
420       
421       track = (AliMUONTrack*) fRecTracksPtr->UncheckedAt(iRecTrack);
422       
423       // Look for compatible cluster(s) in station(0..) "station"
424       if (!FollowTrackInStation(*track, clusterStore, station)) {
425         
426         // Try to recover track if required
427         if (GetRecoParam()->RecoverTracks()) {
428           
429           // work on a copy of the track if this station is not required
430           // to keep the case where no cluster is reconstructed as a possible candidate
431           if (!GetRecoParam()->RequestStation(station)) {
432             track = new ((*fRecTracksPtr)[fRecTracksPtr->GetLast()+1]) AliMUONTrack(*track);
433             fNRecTracks++;
434           }
435           
436           // try to recover
437           if (!RecoverTrack(*track, clusterStore, station)) {
438             // remove track if no cluster found
439             fRecTracksPtr->Remove(track);
440             fNRecTracks--;
441           }
442           
443         } else if (GetRecoParam()->RequestStation(station)) {
444           // remove track if no cluster found
445           fRecTracksPtr->Remove(track);
446           fNRecTracks--;
447         } 
448         
449       }
450       
451     }
452     
453     fRecTracksPtr->Compress(); // this is essential before checking tracks
454     
455     // Keep only the best tracks if required
456     if (!GetRecoParam()->TrackAllTracks()) RemoveDoubleTracks();
457     
458   }
459   
460 }
461
462   //__________________________________________________________________________
463 Bool_t AliMUONTrackReconstructorK::FollowTrackInChamber(AliMUONTrack &trackCandidate, AliMUONVClusterStore& clusterStore, Int_t nextChamber)
464 {
465   /// Follow trackCandidate in chamber(0..) nextChamber and search for compatible cluster(s)
466   /// Keep all possibilities or only the best one(s) according to the flag fgkTrackAllTracks:
467   /// kTRUE:  duplicate "trackCandidate" if there are several possibilities and add the new tracks at the end of
468   ///         fRecTracksPtr to avoid conficts with other track candidates at this current stage of the tracking procedure.
469   ///         Remove the obsolete "trackCandidate" at the end.
470   /// kFALSE: add only the best cluster(s) to the "trackCandidate". Try to add a couple of clusters in priority.
471   /// return kTRUE if new cluster(s) have been found (otherwise return kFALSE)
472   AliDebug(1,Form("Enter FollowTrackInChamber(1..) %d", nextChamber+1));
473   
474   Double_t bendingMomentum;
475   Double_t chi2OfCluster;
476   Double_t maxChi2OfCluster = 2. * GetRecoParam()->GetSigmaCutForTracking() *
477                                    GetRecoParam()->GetSigmaCutForTracking(); // 2 because 2 quantities in chi2
478   Double_t addChi2TrackAtCluster;
479   Double_t bestAddChi2TrackAtCluster = 1.e10;
480   Bool_t foundOneCluster = kFALSE;
481   AliMUONTrack *newTrack = 0x0;
482   AliMUONVCluster *cluster;
483   AliMUONTrackParam extrapTrackParamAtCh;
484   AliMUONTrackParam extrapTrackParamAtCluster;
485   AliMUONTrackParam bestTrackParamAtCluster;
486   
487   // Get track parameters according to the propagation direction
488   if (nextChamber > 7) extrapTrackParamAtCh = *(AliMUONTrackParam*)trackCandidate.GetTrackParamAtCluster()->Last();
489   else extrapTrackParamAtCh = *(AliMUONTrackParam*)trackCandidate.GetTrackParamAtCluster()->First();
490   
491   // Printout for debuging
492   if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 2) || (AliLog::GetGlobalDebugLevel() >= 2)) {
493     cout<<endl<<"Track parameters and covariances at first cluster:"<<endl;
494     extrapTrackParamAtCh.GetParameters().Print();
495     extrapTrackParamAtCh.GetCovariances().Print();
496   }
497   
498   // Add MCS effect
499   AliMUONTrackExtrap::AddMCSEffect(&extrapTrackParamAtCh,AliMUONConstants::ChamberThicknessInX0(),1.);
500   
501   // reset propagator for smoother
502   if (GetRecoParam()->UseSmoother()) extrapTrackParamAtCh.ResetPropagator();
503   
504   // Add MCS in the missing chamber(s) if any
505   Int_t currentChamber = extrapTrackParamAtCh.GetClusterPtr()->GetChamberId();
506   while (currentChamber > nextChamber + 1) {
507     // extrapolation to the missing chamber
508     currentChamber--;
509     AliMUONTrackExtrap::ExtrapToZCov(&extrapTrackParamAtCh, AliMUONConstants::DefaultChamberZ(currentChamber),
510                                      GetRecoParam()->UseSmoother());
511     // add MCS effect
512     AliMUONTrackExtrap::AddMCSEffect(&extrapTrackParamAtCh,AliMUONConstants::ChamberThicknessInX0(),1.);
513   }
514   
515   //Extrapolate trackCandidate to chamber
516   AliMUONTrackExtrap::ExtrapToZCov(&extrapTrackParamAtCh, AliMUONConstants::DefaultChamberZ(nextChamber),
517                                    GetRecoParam()->UseSmoother());
518   
519   // Printout for debuging
520   if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 2) || (AliLog::GetGlobalDebugLevel() >= 2)) {
521     cout<<endl<<"Track parameters and covariances at first cluster extrapolated to z = "<<AliMUONConstants::DefaultChamberZ(nextChamber)<<":"<<endl;
522     extrapTrackParamAtCh.GetParameters().Print();
523     extrapTrackParamAtCh.GetCovariances().Print();
524   }
525   
526   // Printout for debuging
527   if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
528     cout << "FollowTrackInChamber: look for clusters in chamber(1..): " << nextChamber+1 << endl;
529   }
530   
531   // Ask the clustering to reconstruct new clusters around the track position in the current chamber
532   // except for station 4 and 5 that are already entirely clusterized
533   if (GetRecoParam()->CombineClusterTrackReco()) {
534     if (nextChamber < 6) AskForNewClustersInChamber(extrapTrackParamAtCh, clusterStore, nextChamber);
535   }
536   
537   // Create iterators to loop over clusters in both chambers
538   TIter next(clusterStore.CreateChamberIterator(nextChamber,nextChamber));
539   
540   // look for candidates in chamber
541   while ( ( cluster = static_cast<AliMUONVCluster*>(next()) ) ) {
542     
543     // try to add the current cluster fast
544     if (!TryOneClusterFast(extrapTrackParamAtCh, cluster)) continue;
545     
546     // try to add the current cluster accuratly
547     chi2OfCluster = TryOneCluster(extrapTrackParamAtCh, cluster, extrapTrackParamAtCluster,
548                                   GetRecoParam()->UseSmoother());
549     
550     // if good chi2 then consider to add cluster
551     if (chi2OfCluster < maxChi2OfCluster) {
552       foundOneCluster = kTRUE;
553       
554       // Printout for debuging
555       if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
556         cout << "FollowTrackInChamber: found one cluster in chamber(1..): " << nextChamber+1
557         << " (Chi2 = " << chi2OfCluster << ")" << endl;
558         cluster->Print();
559       }
560       
561       if (GetRecoParam()->UseSmoother()) {
562         // save extrapolated parameters for smoother
563         extrapTrackParamAtCluster.SetExtrapParameters(extrapTrackParamAtCluster.GetParameters());
564         
565         // save extrapolated covariance matrix for smoother
566         extrapTrackParamAtCluster.SetExtrapCovariances(extrapTrackParamAtCluster.GetCovariances());
567       }
568       
569       // Compute new track parameters including new cluster using kalman filter
570       addChi2TrackAtCluster = RunKalmanFilter(extrapTrackParamAtCluster);
571       
572       // skip track with absolute bending momentum out of limits
573       bendingMomentum = TMath::Abs(1. / extrapTrackParamAtCluster.GetInverseBendingMomentum());
574       if (bendingMomentum < GetRecoParam()->GetMinBendingMomentum() ||
575           bendingMomentum > GetRecoParam()->GetMaxBendingMomentum()) continue;
576       
577       if (GetRecoParam()->TrackAllTracks()) {
578         // copy trackCandidate into a new track put at the end of fRecTracksPtr and add the new cluster
579         newTrack = new ((*fRecTracksPtr)[fRecTracksPtr->GetLast()+1]) AliMUONTrack(trackCandidate);
580         UpdateTrack(*newTrack,extrapTrackParamAtCluster,addChi2TrackAtCluster);
581         fNRecTracks++;
582         
583         // Printout for debuging
584         if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
585           cout << "FollowTrackInChamber: added one cluster in chamber(1..): " << nextChamber+1 << endl;
586           if (AliLog::GetGlobalDebugLevel() >= 3) newTrack->RecursiveDump();
587         }
588         
589       } else if (addChi2TrackAtCluster < bestAddChi2TrackAtCluster) {
590         // keep track of the best cluster
591         bestAddChi2TrackAtCluster = addChi2TrackAtCluster;
592         bestTrackParamAtCluster = extrapTrackParamAtCluster;
593       }
594       
595     }
596     
597   }
598   
599   // fill out the best track if required else clean up the fRecTracksPtr array
600   if (!GetRecoParam()->TrackAllTracks()) {
601     if (foundOneCluster) {
602       UpdateTrack(trackCandidate,bestTrackParamAtCluster,bestAddChi2TrackAtCluster);
603       
604       // Printout for debuging
605       if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
606         cout << "FollowTrackInChamber: added the best cluster in chamber(1..): " << bestTrackParamAtCluster.GetClusterPtr()->GetChamberId()+1 << endl;
607         if (AliLog::GetGlobalDebugLevel() >= 3) newTrack->RecursiveDump();
608       }
609       
610     } else return kFALSE;
611     
612   } else if (foundOneCluster) {
613     
614     // remove obsolete track
615     fRecTracksPtr->Remove(&trackCandidate);
616     fNRecTracks--;
617     
618   } else return kFALSE;
619   
620   return kTRUE;
621   
622 }
623
624   //__________________________________________________________________________
625 Bool_t AliMUONTrackReconstructorK::FollowTrackInStation(AliMUONTrack &trackCandidate, AliMUONVClusterStore& clusterStore, Int_t nextStation)
626 {
627   /// Follow trackCandidate in station(0..) nextStation and search for compatible cluster(s)
628   /// Keep all possibilities or only the best one(s) according to the flag fgkTrackAllTracks:
629   /// kTRUE:  duplicate "trackCandidate" if there are several possibilities and add the new tracks at the end of
630   ///         fRecTracksPtr to avoid conficts with other track candidates at this current stage of the tracking procedure.
631   ///         Remove the obsolete "trackCandidate" at the end.
632   /// kFALSE: add only the best cluster(s) to the "trackCandidate". Try to add a couple of clusters in priority.
633   /// return kTRUE if new cluster(s) have been found (otherwise return kFALSE)
634   AliDebug(1,Form("Enter FollowTrackInStation(1..) %d", nextStation+1));
635   
636   // Order the chamber according to the propagation direction (tracking starts with chamber 2):
637   // - nextStation == station(1...) 5 => forward propagation
638   // - nextStation < station(1...) 5 => backward propagation
639   Int_t ch1, ch2;
640   if (nextStation==4) {
641     ch1 = 2*nextStation+1;
642     ch2 = 2*nextStation;
643   } else {
644     ch1 = 2*nextStation;
645     ch2 = 2*nextStation+1;
646   }
647   
648   Double_t bendingMomentum;
649   Double_t chi2OfCluster;
650   Double_t maxChi2OfCluster = 2. * GetRecoParam()->GetSigmaCutForTracking() *
651                                    GetRecoParam()->GetSigmaCutForTracking(); // 2 because 2 quantities in chi2
652   Double_t addChi2TrackAtCluster1;
653   Double_t addChi2TrackAtCluster2;
654   Double_t bestAddChi2TrackAtCluster1 = 1.e10;
655   Double_t bestAddChi2TrackAtCluster2 = 1.e10;
656   Bool_t foundOneCluster = kFALSE;
657   Bool_t foundTwoClusters = kFALSE;
658   AliMUONTrack *newTrack = 0x0;
659   AliMUONVCluster *clusterCh1, *clusterCh2;
660   AliMUONTrackParam extrapTrackParam;
661   AliMUONTrackParam extrapTrackParamAtCh;
662   AliMUONTrackParam extrapTrackParamAtCluster1;
663   AliMUONTrackParam extrapTrackParamAtCluster2;
664   AliMUONTrackParam bestTrackParamAtCluster1;
665   AliMUONTrackParam bestTrackParamAtCluster2;
666   
667   Int_t nClusters = clusterStore.GetSize();
668   Bool_t *clusterCh1Used = new Bool_t[nClusters];
669   for (Int_t i = 0; i < nClusters; i++) clusterCh1Used[i] = kFALSE;
670   Int_t iCluster1;
671   
672   // Get track parameters according to the propagation direction
673   
674   if (nextStation==4) extrapTrackParamAtCh = *(AliMUONTrackParam*)trackCandidate.GetTrackParamAtCluster()->Last();
675   else extrapTrackParamAtCh = *(AliMUONTrackParam*)trackCandidate.GetTrackParamAtCluster()->First();
676   
677   // Printout for debuging
678   if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 2) || (AliLog::GetGlobalDebugLevel() >= 2)) {
679     cout<<endl<<"Track parameters and covariances at first cluster:"<<endl;
680     extrapTrackParamAtCh.GetParameters().Print();
681     extrapTrackParamAtCh.GetCovariances().Print();
682   }
683   
684   // Add MCS effect
685   AliMUONTrackExtrap::AddMCSEffect(&extrapTrackParamAtCh,AliMUONConstants::ChamberThicknessInX0(),1.);
686   
687   // reset propagator for smoother
688   if (GetRecoParam()->UseSmoother()) extrapTrackParamAtCh.ResetPropagator();
689   
690   // Add MCS in the missing chamber(s) if any
691   Int_t currentChamber = extrapTrackParamAtCh.GetClusterPtr()->GetChamberId();
692   while (ch1 < ch2 && currentChamber > ch2 + 1) {
693     // extrapolation to the missing chamber
694     currentChamber--;
695     AliMUONTrackExtrap::ExtrapToZCov(&extrapTrackParamAtCh, AliMUONConstants::DefaultChamberZ(currentChamber),
696                                      GetRecoParam()->UseSmoother());
697     // add MCS effect
698     AliMUONTrackExtrap::AddMCSEffect(&extrapTrackParamAtCh,AliMUONConstants::ChamberThicknessInX0(),1.);
699   }
700   
701   //Extrapolate trackCandidate to chamber "ch2"
702   AliMUONTrackExtrap::ExtrapToZCov(&extrapTrackParamAtCh, AliMUONConstants::DefaultChamberZ(ch2),
703                                    GetRecoParam()->UseSmoother());
704   
705   // Printout for debuging
706   if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 2) || (AliLog::GetGlobalDebugLevel() >= 2)) {
707     cout<<endl<<"Track parameters and covariances at first cluster extrapolated to z = "<<AliMUONConstants::DefaultChamberZ(ch2)<<":"<<endl;
708     extrapTrackParamAtCh.GetParameters().Print();
709     extrapTrackParamAtCh.GetCovariances().Print();
710   }
711   
712   // Printout for debuging
713   if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
714     cout << "FollowTrackInStation: look for clusters in chamber(1..): " << ch2+1 << endl;
715   }
716   
717   // Ask the clustering to reconstruct new clusters around the track position in the current station
718   // except for station 4 and 5 that are already entirely clusterized
719   if (GetRecoParam()->CombineClusterTrackReco()) {
720     if (nextStation < 3) AskForNewClustersInStation(extrapTrackParamAtCh, clusterStore, nextStation);
721   }
722   
723   // Create iterators to loop over clusters in both chambers
724   TIter nextInCh1(clusterStore.CreateChamberIterator(ch1,ch1));
725   TIter nextInCh2(clusterStore.CreateChamberIterator(ch2,ch2));
726   
727   // look for candidates in chamber 2
728   while ( ( clusterCh2 = static_cast<AliMUONVCluster*>(nextInCh2()) ) ) {
729     
730     // try to add the current cluster fast
731     if (!TryOneClusterFast(extrapTrackParamAtCh, clusterCh2)) continue;
732     
733     // try to add the current cluster accuratly
734     chi2OfCluster = TryOneCluster(extrapTrackParamAtCh, clusterCh2, extrapTrackParamAtCluster2,
735                                   GetRecoParam()->UseSmoother());
736     
737     // if good chi2 then try to attach a cluster in the other chamber too
738     if (chi2OfCluster < maxChi2OfCluster) {
739       Bool_t foundSecondCluster = kFALSE;
740       
741       // Printout for debuging
742       if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
743         cout << "FollowTrackInStation: found one cluster in chamber(1..): " << ch2+1
744              << " (Chi2 = " << chi2OfCluster << ")" << endl;
745         clusterCh2->Print();
746         cout << "                      look for second clusters in chamber(1..): " << ch1+1 << " ..." << endl;
747       }
748       
749       if (GetRecoParam()->UseSmoother()) {
750         // save extrapolated parameters for smoother
751         extrapTrackParamAtCluster2.SetExtrapParameters(extrapTrackParamAtCluster2.GetParameters());
752         
753         // save extrapolated covariance matrix for smoother
754         extrapTrackParamAtCluster2.SetExtrapCovariances(extrapTrackParamAtCluster2.GetCovariances());
755       }
756       
757       // Compute new track parameters including "clusterCh2" using kalman filter
758       addChi2TrackAtCluster2 = RunKalmanFilter(extrapTrackParamAtCluster2);
759       
760       // skip track with absolute bending momentum out of limits
761       bendingMomentum = TMath::Abs(1. / extrapTrackParamAtCluster2.GetInverseBendingMomentum());
762       if (bendingMomentum < GetRecoParam()->GetMinBendingMomentum() ||
763           bendingMomentum > GetRecoParam()->GetMaxBendingMomentum()) continue;
764         
765       // copy new track parameters for next step
766       extrapTrackParam = extrapTrackParamAtCluster2;
767       
768       // add MCS effect
769       AliMUONTrackExtrap::AddMCSEffect(&extrapTrackParam,AliMUONConstants::ChamberThicknessInX0(),1.);
770       
771       // reset propagator for smoother
772       if (GetRecoParam()->UseSmoother()) extrapTrackParam.ResetPropagator();
773       
774       //Extrapolate track parameters to chamber "ch1"
775       AliMUONTrackExtrap::ExtrapToZCov(&extrapTrackParam, AliMUONConstants::DefaultChamberZ(ch1),
776                                        GetRecoParam()->UseSmoother());
777       
778       // reset cluster iterator of chamber 1
779       nextInCh1.Reset();
780       iCluster1 = -1;
781       
782       // look for second candidates in chamber 1
783       while ( ( clusterCh1 = static_cast<AliMUONVCluster*>(nextInCh1()) ) ) {
784         iCluster1++;
785         
786         // try to add the current cluster fast
787         if (!TryOneClusterFast(extrapTrackParam, clusterCh1)) continue;
788         
789         // try to add the current cluster accuratly
790         chi2OfCluster = TryOneCluster(extrapTrackParam, clusterCh1, extrapTrackParamAtCluster1,
791                                       GetRecoParam()->UseSmoother());
792         
793         // if good chi2 then consider to add the 2 clusters to the "trackCandidate"
794         if (chi2OfCluster < maxChi2OfCluster) {
795           foundSecondCluster = kTRUE;
796           foundTwoClusters = kTRUE;
797           
798           // Printout for debuging
799           if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
800             cout << "FollowTrackInStation: found one cluster in chamber(1..): " << ch1+1
801                  << " (Chi2 = " << chi2OfCluster << ")" << endl;
802             clusterCh1->Print();
803           }
804           
805           if (GetRecoParam()->UseSmoother()) {
806             // save extrapolated parameters for smoother
807             extrapTrackParamAtCluster1.SetExtrapParameters(extrapTrackParamAtCluster1.GetParameters());
808             
809             // save extrapolated covariance matrix for smoother
810             extrapTrackParamAtCluster1.SetExtrapCovariances(extrapTrackParamAtCluster1.GetCovariances());
811           }
812           
813           // Compute new track parameters including "clusterCh1" using kalman filter
814           addChi2TrackAtCluster1 = RunKalmanFilter(extrapTrackParamAtCluster1);
815           
816           // skip track with absolute bending momentum out of limits
817           bendingMomentum = TMath::Abs(1. / extrapTrackParamAtCluster1.GetInverseBendingMomentum());
818           if (bendingMomentum < GetRecoParam()->GetMinBendingMomentum() ||
819               bendingMomentum > GetRecoParam()->GetMaxBendingMomentum()) continue;
820           
821           if (GetRecoParam()->TrackAllTracks()) {
822             // copy trackCandidate into a new track put at the end of fRecTracksPtr and add the new clusters
823             newTrack = new ((*fRecTracksPtr)[fRecTracksPtr->GetLast()+1]) AliMUONTrack(trackCandidate);
824             UpdateTrack(*newTrack,extrapTrackParamAtCluster1,extrapTrackParamAtCluster2,addChi2TrackAtCluster1,addChi2TrackAtCluster2);
825             fNRecTracks++;
826             
827             // if we are arrived on station(1..) 5, recompute track parameters and covariances starting from this station
828             // (going in the right direction)
829             if (nextStation == 4) RetraceTrack(*newTrack,kTRUE);
830             
831             // Tag clusterCh1 as used
832             clusterCh1Used[iCluster1] = kTRUE;
833             
834             // Printout for debuging
835             if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
836               cout << "FollowTrackInStation: added two clusters in station(1..): " << nextStation+1 << endl;
837               if (AliLog::GetGlobalDebugLevel() >= 3) newTrack->RecursiveDump();
838             }
839             
840           } else if (addChi2TrackAtCluster1+addChi2TrackAtCluster2 < bestAddChi2TrackAtCluster1+bestAddChi2TrackAtCluster2) {
841             // keep track of the best couple of clusters
842             bestAddChi2TrackAtCluster1 = addChi2TrackAtCluster1;
843             bestAddChi2TrackAtCluster2 = addChi2TrackAtCluster2;
844             bestTrackParamAtCluster1 = extrapTrackParamAtCluster1;
845             bestTrackParamAtCluster2 = extrapTrackParamAtCluster2;
846           }
847           
848         }
849         
850       }
851       
852       // if no clusterCh1 found then consider to add clusterCh2 only
853       if (!foundSecondCluster) {
854         foundOneCluster = kTRUE;
855         
856         if (GetRecoParam()->TrackAllTracks()) {
857           // copy trackCandidate into a new track put at the end of fRecTracksPtr and add the new cluster
858           newTrack = new ((*fRecTracksPtr)[fRecTracksPtr->GetLast()+1]) AliMUONTrack(trackCandidate);
859           UpdateTrack(*newTrack,extrapTrackParamAtCluster2,addChi2TrackAtCluster2);
860           fNRecTracks++;
861           
862           // if we are arrived on station(1..) 5, recompute track parameters and covariances starting from this station
863           // (going in the right direction)
864           if (nextStation == 4) RetraceTrack(*newTrack,kTRUE);
865           
866           // Printout for debuging
867           if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
868             cout << "FollowTrackInStation: added one cluster in chamber(1..): " << ch2+1 << endl;
869             if (AliLog::GetGlobalDebugLevel() >= 3) newTrack->RecursiveDump();
870           }
871           
872         } else if (!foundTwoClusters && addChi2TrackAtCluster2 < bestAddChi2TrackAtCluster1) {
873           // keep track of the best single cluster except if a couple of clusters has already been found
874           bestAddChi2TrackAtCluster1 = addChi2TrackAtCluster2;
875           bestTrackParamAtCluster1 = extrapTrackParamAtCluster2;
876         }
877         
878       }
879       
880     }
881     
882   }
883   
884   // look for candidates in chamber 1 not already attached to a track
885   // if we want to keep all possible tracks or if no good couple of clusters has been found
886   if (GetRecoParam()->TrackAllTracks() || !foundTwoClusters) {
887     
888     // add MCS effect for next step
889     AliMUONTrackExtrap::AddMCSEffect(&extrapTrackParamAtCh,AliMUONConstants::ChamberThicknessInX0(),1.);
890     
891     //Extrapolate trackCandidate to chamber "ch1"
892     AliMUONTrackExtrap::ExtrapToZCov(&extrapTrackParamAtCh, AliMUONConstants::DefaultChamberZ(ch1),
893                                      GetRecoParam()->UseSmoother());
894     
895     // Printout for debuging
896     if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 2) || (AliLog::GetGlobalDebugLevel() >= 2)) {
897       cout<<endl<<"Track parameters and covariances at first cluster extrapolated to z = "<<AliMUONConstants::DefaultChamberZ(ch1)<<":"<<endl;
898       extrapTrackParamAtCh.GetParameters().Print();
899       extrapTrackParamAtCh.GetCovariances().Print();
900     }
901     
902     // Printout for debuging
903     if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
904       cout << "FollowTrackInStation: look for single clusters in chamber(1..): " << ch1+1 << endl;
905     }
906     
907     // reset cluster iterator of chamber 1
908     nextInCh1.Reset();
909     iCluster1 = -1;
910     
911     // look for second candidates in chamber 1
912     while ( ( clusterCh1 = static_cast<AliMUONVCluster*>(nextInCh1()) ) ) {
913       iCluster1++;
914       
915       if (clusterCh1Used[iCluster1]) continue; // Skip clusters already used
916       
917       // try to add the current cluster fast
918       if (!TryOneClusterFast(extrapTrackParamAtCh, clusterCh1)) continue;
919       
920       // try to add the current cluster accuratly
921       chi2OfCluster = TryOneCluster(extrapTrackParamAtCh, clusterCh1, extrapTrackParamAtCluster1,
922                                     GetRecoParam()->UseSmoother());
923       
924       // if good chi2 then consider to add clusterCh1
925       // We do not try to attach a cluster in the other chamber too since it has already been done above
926       if (chi2OfCluster < maxChi2OfCluster) {
927         foundOneCluster = kTRUE;
928         
929         // Printout for debuging
930         if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
931           cout << "FollowTrackInStation: found one cluster in chamber(1..): " << ch1+1
932                << " (Chi2 = " << chi2OfCluster << ")" << endl;
933           clusterCh1->Print();
934         }
935         
936         if (GetRecoParam()->UseSmoother()) {
937           // save extrapolated parameters for smoother
938           extrapTrackParamAtCluster1.SetExtrapParameters(extrapTrackParamAtCluster1.GetParameters());
939           
940           // save extrapolated covariance matrix for smoother
941           extrapTrackParamAtCluster1.SetExtrapCovariances(extrapTrackParamAtCluster1.GetCovariances());
942         }
943         
944         // Compute new track parameters including "clusterCh1" using kalman filter
945         addChi2TrackAtCluster1 = RunKalmanFilter(extrapTrackParamAtCluster1);
946         
947         // skip track with absolute bending momentum out of limits
948         bendingMomentum = TMath::Abs(1. / extrapTrackParamAtCluster1.GetInverseBendingMomentum());
949         if (bendingMomentum < GetRecoParam()->GetMinBendingMomentum() ||
950             bendingMomentum > GetRecoParam()->GetMaxBendingMomentum()) continue;
951         
952         if (GetRecoParam()->TrackAllTracks()) {
953           // copy trackCandidate into a new track put at the end of fRecTracksPtr and add the new cluster
954           newTrack = new ((*fRecTracksPtr)[fRecTracksPtr->GetLast()+1]) AliMUONTrack(trackCandidate);
955           UpdateTrack(*newTrack,extrapTrackParamAtCluster1,addChi2TrackAtCluster1);
956           fNRecTracks++;
957           
958           // if we are arrived on station(1..) 5, recompute track parameters and covariances starting from this station
959           // (going in the right direction)
960           if (nextStation == 4) RetraceTrack(*newTrack,kTRUE);
961           
962           // Printout for debuging
963           if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
964             cout << "FollowTrackInStation: added one cluster in chamber(1..): " << ch1+1 << endl;
965             if (AliLog::GetGlobalDebugLevel() >= 3) newTrack->RecursiveDump();
966           }
967           
968         } else if (addChi2TrackAtCluster1 < bestAddChi2TrackAtCluster1) {
969           // keep track of the best single cluster except if a couple of clusters has already been found
970           bestAddChi2TrackAtCluster1 = addChi2TrackAtCluster1;
971           bestTrackParamAtCluster1 = extrapTrackParamAtCluster1;
972         }
973         
974       }
975       
976     }
977     
978   }
979   
980   // fill out the best track if required else clean up the fRecTracksPtr array
981   if (!GetRecoParam()->TrackAllTracks()) {
982     if (foundTwoClusters) {
983       UpdateTrack(trackCandidate,bestTrackParamAtCluster1,bestTrackParamAtCluster2,bestAddChi2TrackAtCluster1,bestAddChi2TrackAtCluster2);
984       
985       // if we are arrived on station(1..) 5, recompute track parameters and covariances starting from this station
986       // (going in the right direction)
987       if (nextStation == 4) RetraceTrack(trackCandidate,kTRUE);
988       
989       // Printout for debuging
990       if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
991         cout << "FollowTrackInStation: added the two best clusters in station(1..): " << nextStation+1 << endl;
992         if (AliLog::GetGlobalDebugLevel() >= 3) newTrack->RecursiveDump();
993       }
994       
995     } else if (foundOneCluster) {
996       UpdateTrack(trackCandidate,bestTrackParamAtCluster1,bestAddChi2TrackAtCluster1);
997       
998       // if we are arrived on station(1..) 5, recompute track parameters and covariances starting from this station
999       // (going in the right direction)
1000       if (nextStation == 4) RetraceTrack(trackCandidate,kTRUE);
1001       
1002       // Printout for debuging
1003       if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
1004         cout << "FollowTrackInStation: added the best cluster in chamber(1..): " << bestTrackParamAtCluster1.GetClusterPtr()->GetChamberId()+1 << endl;
1005         if (AliLog::GetGlobalDebugLevel() >= 3) newTrack->RecursiveDump();
1006       }
1007       
1008     } else {
1009       delete [] clusterCh1Used;
1010       return kFALSE;
1011     }
1012     
1013   } else if (foundOneCluster || foundTwoClusters) {
1014     
1015     // remove obsolete track
1016     fRecTracksPtr->Remove(&trackCandidate);
1017     fNRecTracks--;
1018     
1019   } else {
1020     delete [] clusterCh1Used;
1021     return kFALSE;
1022   }
1023   
1024   delete [] clusterCh1Used;
1025   return kTRUE;
1026   
1027 }
1028
1029   //__________________________________________________________________________
1030 Double_t AliMUONTrackReconstructorK::RunKalmanFilter(AliMUONTrackParam &trackParamAtCluster)
1031 {
1032   /// Compute new track parameters and their covariances including new cluster using kalman filter
1033   /// return the additional track chi2
1034   AliDebug(1,"Enter RunKalmanFilter");
1035   
1036   // Get actual track parameters (p)
1037   TMatrixD param(trackParamAtCluster.GetParameters());
1038   
1039   // Get new cluster parameters (m)
1040   AliMUONVCluster *cluster = trackParamAtCluster.GetClusterPtr();
1041   TMatrixD clusterParam(5,1);
1042   clusterParam.Zero();
1043   clusterParam(0,0) = cluster->GetX();
1044   clusterParam(2,0) = cluster->GetY();
1045   
1046   // Compute the actual parameter weight (W)
1047   TMatrixD paramWeight(trackParamAtCluster.GetCovariances());
1048   if (paramWeight.Determinant() != 0) {
1049     paramWeight.Invert();
1050   } else {
1051     AliWarning(" Determinant = 0");
1052     return 1.e10;
1053   }
1054   
1055   // Compute the new cluster weight (U)
1056   TMatrixD clusterWeight(5,5);
1057   clusterWeight.Zero();
1058   clusterWeight(0,0) = 1. / cluster->GetErrX2();
1059   clusterWeight(2,2) = 1. / cluster->GetErrY2();
1060
1061   // Compute the new parameters covariance matrix ( (W+U)^-1 )
1062   TMatrixD newParamCov(paramWeight,TMatrixD::kPlus,clusterWeight);
1063   if (newParamCov.Determinant() != 0) {
1064     newParamCov.Invert();
1065   } else {
1066     AliWarning(" Determinant = 0");
1067     return 1.e10;
1068   }
1069   
1070   // Save the new parameters covariance matrix
1071   trackParamAtCluster.SetCovariances(newParamCov);
1072   
1073   // Compute the new parameters (p' = ((W+U)^-1)U(m-p) + p)
1074   TMatrixD tmp(clusterParam,TMatrixD::kMinus,param);
1075   TMatrixD tmp2(clusterWeight,TMatrixD::kMult,tmp); // U(m-p)
1076   TMatrixD newParam(newParamCov,TMatrixD::kMult,tmp2); // ((W+U)^-1)U(m-p)
1077   newParam += param; // ((W+U)^-1)U(m-p) + p
1078   
1079   // Save the new parameters
1080   trackParamAtCluster.SetParameters(newParam);
1081   
1082   // Compute the additional chi2 (= ((p'-p)^-1)W(p'-p) + ((p'-m)^-1)U(p'-m))
1083   tmp = newParam; // p'
1084   tmp -= param; // (p'-p)
1085   TMatrixD tmp3(paramWeight,TMatrixD::kMult,tmp); // W(p'-p)
1086   TMatrixD addChi2Track(tmp,TMatrixD::kTransposeMult,tmp3); // ((p'-p)^-1)W(p'-p)
1087   tmp = newParam; // p'
1088   tmp -= clusterParam; // (p'-m)
1089   TMatrixD tmp4(clusterWeight,TMatrixD::kMult,tmp); // U(p'-m)
1090   addChi2Track += TMatrixD(tmp,TMatrixD::kTransposeMult,tmp4); // ((p'-p)^-1)W(p'-p) + ((p'-m)^-1)U(p'-m)
1091   
1092   return addChi2Track(0,0);
1093   
1094 }
1095
1096   //__________________________________________________________________________
1097 void AliMUONTrackReconstructorK::UpdateTrack(AliMUONTrack &track, AliMUONTrackParam &trackParamAtCluster, Double_t addChi2)
1098 {
1099   /// Add 1 cluster to the track candidate
1100   /// Update chi2 of the track 
1101   
1102   // Flag cluster as being (not) removable
1103   if (GetRecoParam()->RequestStation(trackParamAtCluster.GetClusterPtr()->GetChamberId()/2))
1104     trackParamAtCluster.SetRemovable(kFALSE);
1105   else trackParamAtCluster.SetRemovable(kTRUE);
1106   trackParamAtCluster.SetLocalChi2(0.); // --> Local chi2 not used
1107   
1108   // Update the track chi2 into trackParamAtCluster
1109   trackParamAtCluster.SetTrackChi2(track.GetGlobalChi2() + addChi2);
1110   
1111   // Update the chi2 of the new track
1112   track.SetGlobalChi2(trackParamAtCluster.GetTrackChi2());
1113   
1114   // Update array of TrackParamAtCluster
1115   track.AddTrackParamAtCluster(trackParamAtCluster,*(trackParamAtCluster.GetClusterPtr()));
1116   
1117 }
1118
1119   //__________________________________________________________________________
1120 void AliMUONTrackReconstructorK::UpdateTrack(AliMUONTrack &track, AliMUONTrackParam &trackParamAtCluster1, AliMUONTrackParam &trackParamAtCluster2,
1121                                              Double_t addChi2AtCluster1, Double_t addChi2AtCluster2)
1122 {
1123   /// Add 2 clusters to the track candidate (order is important)
1124   /// Update track and local chi2
1125   
1126   // Update local chi2 at first cluster
1127   AliMUONVCluster* cluster1 = trackParamAtCluster1.GetClusterPtr();
1128   Double_t deltaX = trackParamAtCluster1.GetNonBendingCoor() - cluster1->GetX();
1129   Double_t deltaY = trackParamAtCluster1.GetBendingCoor() - cluster1->GetY();
1130   Double_t localChi2AtCluster1 = deltaX*deltaX / cluster1->GetErrX2() +
1131                                  deltaY*deltaY / cluster1->GetErrY2();
1132   trackParamAtCluster1.SetLocalChi2(localChi2AtCluster1);
1133   
1134   // Flag first cluster as being removable
1135   trackParamAtCluster1.SetRemovable(kTRUE);
1136   
1137   // Update local chi2 at second cluster
1138   AliMUONVCluster* cluster2 = trackParamAtCluster2.GetClusterPtr();
1139   AliMUONTrackParam extrapTrackParamAtCluster2(trackParamAtCluster1);
1140   AliMUONTrackExtrap::ExtrapToZ(&extrapTrackParamAtCluster2, trackParamAtCluster2.GetZ());
1141   deltaX = extrapTrackParamAtCluster2.GetNonBendingCoor() - cluster2->GetX();
1142   deltaY = extrapTrackParamAtCluster2.GetBendingCoor() - cluster2->GetY();
1143   Double_t localChi2AtCluster2 = deltaX*deltaX / cluster2->GetErrX2() +
1144                                  deltaY*deltaY / cluster2->GetErrY2();
1145   trackParamAtCluster2.SetLocalChi2(localChi2AtCluster2);
1146   
1147   // Flag second cluster as being removable
1148   trackParamAtCluster2.SetRemovable(kTRUE);
1149   
1150   // Update the track chi2 into trackParamAtCluster2
1151   trackParamAtCluster2.SetTrackChi2(track.GetGlobalChi2() + addChi2AtCluster2);
1152   
1153   // Update the track chi2 into trackParamAtCluster1
1154   trackParamAtCluster1.SetTrackChi2(trackParamAtCluster2.GetTrackChi2() + addChi2AtCluster1);
1155   
1156   // Update the chi2 of the new track
1157   track.SetGlobalChi2(trackParamAtCluster1.GetTrackChi2());
1158   
1159   // Update array of trackParamAtCluster
1160   track.AddTrackParamAtCluster(trackParamAtCluster1,*cluster1);
1161   track.AddTrackParamAtCluster(trackParamAtCluster2,*cluster2);
1162   
1163 }
1164
1165   //__________________________________________________________________________
1166 Bool_t AliMUONTrackReconstructorK::RecoverTrack(AliMUONTrack &trackCandidate, AliMUONVClusterStore& clusterStore, Int_t nextStation)
1167 {
1168   /// Try to recover the track candidate in the next station
1169   /// by removing the worst of the two clusters attached in the current station
1170   /// Return kTRUE if recovering succeeds
1171   AliDebug(1,"Enter RecoverTrack");
1172   
1173   // Do not try to recover track until we have attached cluster(s) on station(1..) 3
1174   if (nextStation > 1) return kFALSE;
1175   
1176   Int_t worstClusterNumber = -1;
1177   Double_t localChi2, worstLocalChi2 = -1.;
1178   
1179   // Look for the cluster to remove
1180   for (Int_t clusterNumber = 0; clusterNumber < 2; clusterNumber++) {
1181     AliMUONTrackParam *trackParamAtCluster = (AliMUONTrackParam*)trackCandidate.GetTrackParamAtCluster()->UncheckedAt(clusterNumber);
1182     
1183     // check if current cluster is in the previous station
1184     if (trackParamAtCluster->GetClusterPtr()->GetChamberId()/2 != nextStation+1) break;
1185     
1186     // check if current cluster is removable
1187     if (!trackParamAtCluster->IsRemovable()) return kFALSE;
1188     
1189     // reset the current cluster as being not removable if it is on a required station
1190     if (GetRecoParam()->RequestStation(nextStation+1)) trackParamAtCluster->SetRemovable(kFALSE);
1191     
1192     // Pick up cluster with the worst chi2
1193     localChi2 = trackParamAtCluster->GetLocalChi2();
1194     if (localChi2 > worstLocalChi2) {
1195       worstLocalChi2 = localChi2;
1196       worstClusterNumber = clusterNumber;
1197     }
1198   }
1199   
1200   // check if worst cluster found
1201   if (worstClusterNumber < 0) return kFALSE;
1202   
1203   // Remove the worst cluster
1204   trackCandidate.RemoveTrackParamAtCluster((AliMUONTrackParam*)trackCandidate.GetTrackParamAtCluster()->UncheckedAt(worstClusterNumber));
1205   
1206   // Re-calculate track parameters at the (new) first cluster
1207   RetracePartialTrack(trackCandidate,(AliMUONTrackParam*)trackCandidate.GetTrackParamAtCluster()->UncheckedAt(1));
1208   
1209   // skip track with absolute bending momentum out of limits
1210   Double_t bendingMomentum = TMath::Abs(1. / ((AliMUONTrackParam*)trackCandidate.GetTrackParamAtCluster()->First())->GetInverseBendingMomentum());
1211   if (bendingMomentum < GetRecoParam()->GetMinBendingMomentum() ||
1212       bendingMomentum > GetRecoParam()->GetMaxBendingMomentum()) return kFALSE;
1213   
1214   // Look for new cluster(s) in next station
1215   return FollowTrackInStation(trackCandidate, clusterStore, nextStation);
1216   
1217 }
1218
1219   //__________________________________________________________________________
1220 Bool_t AliMUONTrackReconstructorK::RunSmoother(AliMUONTrack &track)
1221 {
1222   /// Compute new track parameters and their covariances using smoother
1223   AliDebug(1,"Enter UseSmoother");
1224   
1225   AliMUONTrackParam *previousTrackParam = (AliMUONTrackParam*) track.GetTrackParamAtCluster()->First();
1226   
1227   // Smoothed parameters and covariances at first cluster = filtered parameters and covariances
1228   previousTrackParam->SetSmoothParameters(previousTrackParam->GetParameters());
1229   previousTrackParam->SetSmoothCovariances(previousTrackParam->GetCovariances());
1230   
1231   // Compute local chi2 at first cluster
1232   AliMUONVCluster *cluster = previousTrackParam->GetClusterPtr();
1233   Double_t dX = cluster->GetX() - previousTrackParam->GetNonBendingCoor();
1234   Double_t dY = cluster->GetY() - previousTrackParam->GetBendingCoor();
1235   Double_t chi2 = dX * dX / cluster->GetErrX2() + dY * dY / cluster->GetErrY2();
1236   
1237   // Save local chi2 at first cluster
1238   previousTrackParam->SetLocalChi2(chi2);
1239   
1240   AliMUONTrackParam *currentTrackParam = (AliMUONTrackParam*) track.GetTrackParamAtCluster()->After(previousTrackParam);
1241   while (currentTrackParam) {
1242     
1243     // Get variables
1244     const TMatrixD &extrapParameters          = previousTrackParam->GetExtrapParameters();  // X(k+1 k)
1245     const TMatrixD &filteredParameters        = currentTrackParam->GetParameters();         // X(k k)
1246     const TMatrixD &previousSmoothParameters  = previousTrackParam->GetSmoothParameters();  // X(k+1 n)
1247     const TMatrixD &propagator                = previousTrackParam->GetPropagator();        // F(k)
1248     const TMatrixD &extrapCovariances         = previousTrackParam->GetExtrapCovariances(); // C(k+1 k)
1249     const TMatrixD &filteredCovariances       = currentTrackParam->GetCovariances();        // C(k k)
1250     const TMatrixD &previousSmoothCovariances = previousTrackParam->GetSmoothCovariances(); // C(k+1 n)
1251     
1252     // Compute smoother gain: A(k) = C(kk) * F(f)^t * (C(k+1 k))^-1
1253     TMatrixD extrapWeight(extrapCovariances);
1254     if (extrapWeight.Determinant() != 0) {
1255       extrapWeight.Invert(); // (C(k+1 k))^-1
1256     } else {
1257       AliWarning(" Determinant = 0");
1258       return kFALSE;
1259     }
1260     TMatrixD smootherGain(filteredCovariances,TMatrixD::kMultTranspose,propagator); // C(kk) * F(f)^t
1261     smootherGain *= extrapWeight; // C(kk) * F(f)^t * (C(k+1 k))^-1
1262     
1263     // Compute smoothed parameters: X(k n) = X(k k) + A(k) * (X(k+1 n) - X(k+1 k))
1264     TMatrixD tmpParam(previousSmoothParameters,TMatrixD::kMinus,extrapParameters); // X(k+1 n) - X(k+1 k)
1265     TMatrixD smoothParameters(smootherGain,TMatrixD::kMult,tmpParam); // A(k) * (X(k+1 n) - X(k+1 k))
1266     smoothParameters += filteredParameters; // X(k k) + A(k) * (X(k+1 n) - X(k+1 k))
1267     
1268     // Save smoothed parameters
1269     currentTrackParam->SetSmoothParameters(smoothParameters);
1270     
1271     // Compute smoothed covariances: C(k n) = C(k k) + A(k) * (C(k+1 n) - C(k+1 k)) * (A(k))^t
1272     TMatrixD tmpCov(previousSmoothCovariances,TMatrixD::kMinus,extrapCovariances); // C(k+1 n) - C(k+1 k)
1273     TMatrixD tmpCov2(tmpCov,TMatrixD::kMultTranspose,smootherGain); // (C(k+1 n) - C(k+1 k)) * (A(k))^t
1274     TMatrixD smoothCovariances(smootherGain,TMatrixD::kMult,tmpCov2); // A(k) * (C(k+1 n) - C(k+1 k)) * (A(k))^t
1275     smoothCovariances += filteredCovariances; // C(k k) + A(k) * (C(k+1 n) - C(k+1 k)) * (A(k))^t
1276     
1277     // Save smoothed covariances
1278     currentTrackParam->SetSmoothCovariances(smoothCovariances);
1279     
1280     // Compute smoothed residual: r(k n) = cluster - X(k n)
1281     cluster = currentTrackParam->GetClusterPtr();
1282     TMatrixD smoothResidual(2,1);
1283     smoothResidual.Zero();
1284     smoothResidual(0,0) = cluster->GetX() - smoothParameters(0,0);
1285     smoothResidual(1,0) = cluster->GetY() - smoothParameters(2,0);
1286     
1287     // Compute weight of smoothed residual: W(k n) = (clusterCov - C(k n))^-1
1288     TMatrixD smoothResidualWeight(2,2);
1289     smoothResidualWeight(0,0) = cluster->GetErrX2() - smoothCovariances(0,0);
1290     smoothResidualWeight(0,1) = - smoothCovariances(0,2);
1291     smoothResidualWeight(1,0) = - smoothCovariances(2,0);
1292     smoothResidualWeight(1,1) = cluster->GetErrY2() - smoothCovariances(2,2);
1293     if (smoothResidualWeight.Determinant() != 0) {
1294       smoothResidualWeight.Invert();
1295     } else {
1296       AliWarning(" Determinant = 0");
1297       return kFALSE;
1298     }
1299     
1300     // Compute local chi2 = (r(k n))^t * W(k n) * r(k n)
1301     TMatrixD tmpChi2(smoothResidual,TMatrixD::kTransposeMult,smoothResidualWeight); // (r(k n))^t * W(k n)
1302     TMatrixD localChi2(tmpChi2,TMatrixD::kMult,smoothResidual); // (r(k n))^t * W(k n) * r(k n)
1303     
1304     // Save local chi2
1305     currentTrackParam->SetLocalChi2(localChi2(0,0));
1306     
1307     previousTrackParam = currentTrackParam;
1308     currentTrackParam = (AliMUONTrackParam*) track.GetTrackParamAtCluster()->After(previousTrackParam);
1309   }
1310   
1311   return kTRUE;
1312   
1313 }
1314
1315   //__________________________________________________________________________
1316 void AliMUONTrackReconstructorK::ComplementTracks(const AliMUONVClusterStore& clusterStore)
1317 {
1318   /// Complete tracks by adding missing clusters (if there is an overlap between
1319   /// two detection elements, the track may have two clusters in the same chamber)
1320   /// Recompute track parameters and covariances at each clusters
1321   AliDebug(1,"Enter ComplementTracks");
1322   
1323   Int_t chamberId, detElemId;
1324   Double_t chi2OfCluster, addChi2TrackAtCluster, bestAddChi2TrackAtCluster;
1325   Double_t maxChi2OfCluster = 2. * GetRecoParam()->GetSigmaCutForTracking() *
1326                                    GetRecoParam()->GetSigmaCutForTracking(); // 2 because 2 quantities in chi2
1327   Bool_t foundOneCluster, trackModified;
1328   AliMUONVCluster *cluster;
1329   AliMUONTrackParam *trackParam, *previousTrackParam, *nextTrackParam, trackParamAtCluster, bestTrackParamAtCluster;
1330   
1331   AliMUONTrack *track = (AliMUONTrack*) fRecTracksPtr->First();
1332   while (track) {
1333     trackModified = kFALSE;
1334     
1335     trackParam = (AliMUONTrackParam*)track->GetTrackParamAtCluster()->First();
1336     previousTrackParam = trackParam;
1337     while (trackParam) {
1338       foundOneCluster = kFALSE;
1339       bestAddChi2TrackAtCluster = 1.e10;
1340       chamberId = trackParam->GetClusterPtr()->GetChamberId();
1341       detElemId = trackParam->GetClusterPtr()->GetDetElemId();
1342       
1343       // prepare nextTrackParam before adding new cluster because of the sorting
1344       nextTrackParam = (AliMUONTrackParam*)track->GetTrackParamAtCluster()->After(trackParam);
1345       
1346       // Create iterators to loop over clusters in current chamber
1347       TIter nextInCh(clusterStore.CreateChamberIterator(chamberId,chamberId));
1348       
1349       // look for one second candidate in the same chamber
1350       while ( ( cluster = static_cast<AliMUONVCluster*>(nextInCh()) ) ) {
1351         
1352         // look for a cluster in another detection element
1353         if (cluster->GetDetElemId() == detElemId) continue;
1354         
1355         // try to add the current cluster fast
1356         if (!TryOneClusterFast(*trackParam, cluster)) continue;
1357         
1358         // try to add the current cluster accurately
1359         // never use track parameters at last cluster because the covariance matrix is meaningless
1360         if (nextTrackParam) chi2OfCluster = TryOneCluster(*trackParam, cluster, trackParamAtCluster);
1361         else chi2OfCluster = TryOneCluster(*previousTrackParam, cluster, trackParamAtCluster);
1362         
1363         // if good chi2 then consider to add this cluster to the track
1364         if (chi2OfCluster < maxChi2OfCluster) {
1365           
1366           // Compute local track parameters including current cluster using kalman filter
1367           addChi2TrackAtCluster = RunKalmanFilter(trackParamAtCluster);
1368           
1369           // keep track of the best cluster
1370           if (addChi2TrackAtCluster < bestAddChi2TrackAtCluster) {
1371             bestAddChi2TrackAtCluster = addChi2TrackAtCluster;
1372             bestTrackParamAtCluster = trackParamAtCluster;
1373             foundOneCluster = kTRUE;
1374           }
1375           
1376         }
1377         
1378       }
1379       
1380       // add new cluster if any
1381       if (foundOneCluster) {
1382         
1383         // Printout for debuging
1384         if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
1385           cout << "ComplementTracks: found one cluster in chamber(1..): " << chamberId+1 << endl;
1386           bestTrackParamAtCluster.GetClusterPtr()->Print();
1387           if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 2) || (AliLog::GetGlobalDebugLevel() >= 2)) {
1388             cout<<endl<<"Track parameters and covariances at cluster:"<<endl;
1389             bestTrackParamAtCluster.GetParameters().Print();
1390             bestTrackParamAtCluster.GetCovariances().Print();
1391           }
1392         }
1393         
1394         trackParam->SetRemovable(kTRUE);
1395         bestTrackParamAtCluster.SetRemovable(kTRUE);
1396         track->AddTrackParamAtCluster(bestTrackParamAtCluster,*(bestTrackParamAtCluster.GetClusterPtr()));
1397         trackModified = kTRUE;
1398       }
1399       
1400       previousTrackParam = trackParam;
1401       trackParam = nextTrackParam;
1402     }
1403     
1404     // re-compute track parameters using kalman filter if needed
1405     if (trackModified) RetraceTrack(*track,kTRUE);
1406     
1407     track = (AliMUONTrack*) fRecTracksPtr->After(track);
1408   }
1409   
1410 }
1411
1412 //__________________________________________________________________________
1413 void AliMUONTrackReconstructorK::ImproveTrack(AliMUONTrack &track)
1414 {
1415   /// Improve the given track by removing removable clusters with local chi2 highter than the defined cut
1416   /// Removable clusters are identified by the method AliMUONTrack::TagRemovableClusters()
1417   /// Recompute track parameters and covariances at the remaining clusters
1418   AliDebug(1,"Enter ImproveTrack");
1419   
1420   Double_t localChi2, worstLocalChi2;
1421   AliMUONTrackParam *trackParamAtCluster, *worstTrackParamAtCluster, *nextTrackParam;
1422   Bool_t smoothed;
1423   Double_t sigmaCut2 = GetRecoParam()->GetSigmaCutForImprovement() *
1424                        GetRecoParam()->GetSigmaCutForImprovement();
1425   
1426   while (!track.IsImproved()) {
1427     
1428     // identify removable clusters
1429     track.TagRemovableClusters(GetRecoParam()->RequestedStationMask());
1430     
1431     // Run smoother if required
1432     smoothed = kFALSE;
1433     if (GetRecoParam()->UseSmoother()) smoothed = RunSmoother(track);
1434     
1435     // Use standard procedure to compute local chi2 if smoother not required or not working
1436     if (!smoothed) {
1437       
1438       // Update track parameters and covariances
1439       track.UpdateCovTrackParamAtCluster();
1440       
1441       // Compute local chi2 of each clusters
1442       track.ComputeLocalChi2(kTRUE);
1443     }
1444     
1445     // Look for the cluster to remove
1446     worstTrackParamAtCluster = 0x0;
1447     worstLocalChi2 = 0.;
1448     trackParamAtCluster = (AliMUONTrackParam*)track.GetTrackParamAtCluster()->First();
1449     while (trackParamAtCluster) {
1450       
1451       // save parameters into smooth parameters in case of smoother did not work properly
1452       if (GetRecoParam()->UseSmoother() && !smoothed) {
1453         trackParamAtCluster->SetSmoothParameters(trackParamAtCluster->GetParameters());
1454         trackParamAtCluster->SetSmoothCovariances(trackParamAtCluster->GetCovariances());
1455       }
1456       
1457       // Pick up cluster with the worst chi2
1458       localChi2 = trackParamAtCluster->GetLocalChi2();
1459       if (localChi2 > worstLocalChi2) {
1460         worstLocalChi2 = localChi2;
1461         worstTrackParamAtCluster = trackParamAtCluster;
1462       }
1463       
1464       trackParamAtCluster = (AliMUONTrackParam*)track.GetTrackParamAtCluster()->After(trackParamAtCluster);
1465     }
1466     
1467     // Check if worst cluster found
1468     if (!worstTrackParamAtCluster) {
1469       AliWarning("Bad local chi2 values?");
1470       break;
1471     }
1472     
1473     // Check whether the worst chi2 is under requirement or not
1474     if (worstLocalChi2 < 2. * sigmaCut2) { // 2 because 2 quantities in chi2
1475       track.SetImproved(kTRUE);
1476       break;
1477     }
1478     
1479     // if the worst cluster is not removable then stop improvement
1480     if (!worstTrackParamAtCluster->IsRemovable()) break;
1481     
1482     // get track parameters at cluster next to the one to be removed
1483     nextTrackParam = (AliMUONTrackParam*) track.GetTrackParamAtCluster()->After(worstTrackParamAtCluster);
1484     
1485     // Remove the worst cluster
1486     track.RemoveTrackParamAtCluster(worstTrackParamAtCluster);
1487     
1488     // Re-calculate track parameters
1489     // - from the cluster immediately downstream the one suppressed
1490     // - or from the begining - if parameters have been re-computed using the standard method (kalman parameters have been lost)
1491     //                  - or if the removed cluster was the last one
1492     if (smoothed && nextTrackParam) RetracePartialTrack(track,nextTrackParam);
1493     else RetraceTrack(track,kTRUE);
1494     
1495     // Printout for debuging
1496     if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
1497       cout << "ImproveTracks: track " << fRecTracksPtr->IndexOf(&track)+1 << " improved " << endl;
1498     }
1499     
1500   }
1501   
1502 }
1503
1504 //__________________________________________________________________________
1505 void AliMUONTrackReconstructorK::FinalizeTrack(AliMUONTrack &track)
1506 {
1507   /// Update track parameters and covariances at each attached cluster
1508   /// using smoother if required, if not already done
1509   
1510   AliMUONTrackParam *trackParamAtCluster;
1511   Bool_t smoothed = kFALSE;
1512   
1513   // update track parameters (using smoother if required) if not already done
1514   if (!track.IsImproved()) {
1515     smoothed = kFALSE;
1516     if (GetRecoParam()->UseSmoother()) smoothed = RunSmoother(track);
1517     if (!smoothed) track.UpdateCovTrackParamAtCluster();
1518   } else smoothed = GetRecoParam()->UseSmoother();
1519   
1520   // copy smoothed parameters and covariances if any
1521   if (smoothed) {
1522     
1523     trackParamAtCluster = (AliMUONTrackParam*) (track.GetTrackParamAtCluster()->First());
1524     while (trackParamAtCluster) {
1525       
1526       trackParamAtCluster->SetParameters(trackParamAtCluster->GetSmoothParameters());
1527       trackParamAtCluster->SetCovariances(trackParamAtCluster->GetSmoothCovariances());
1528       
1529       trackParamAtCluster = (AliMUONTrackParam*) (track.GetTrackParamAtCluster()->After(trackParamAtCluster));
1530     }
1531     
1532   }
1533   
1534 }
1535
1536   //__________________________________________________________________________
1537 Bool_t AliMUONTrackReconstructorK::RefitTrack(AliMUONTrack &track, Bool_t enableImprovement)
1538 {
1539   /// re-fit the given track
1540   
1541   // check validity of the track
1542   if (track.GetNClusters() < 3) {
1543     AliWarning("the track does not contain enough clusters --> unable to refit");
1544     return kFALSE;
1545   }
1546   
1547   // re-compute track parameters and covariances using Kalman filter
1548   RetraceTrack(track,kTRUE);
1549   
1550   // Improve the reconstructed tracks if required
1551   track.SetImproved(kFALSE);
1552   if (enableImprovement && GetRecoParam()->ImproveTracks()) ImproveTrack(track);
1553   
1554   // Fill AliMUONTrack data members
1555   FinalizeTrack(track);
1556   
1557   return kTRUE;
1558   
1559 }
1560