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