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