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