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