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