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