]> git.uio.no Git - u/mrichter/AliRoot.git/blob - MUON/AliMUONTrackReconstructorK.cxx
Fixes for memory leaks (Christian)
[u/mrichter/AliRoot.git] / MUON / AliMUONTrackReconstructorK.cxx
1 /**************************************************************************
2  * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
3  *                                                                        *
4  * Author: The ALICE Off-line Project.                                    *
5  * Contributors are mentioned in the code where appropriate.              *
6  *                                                                        *
7  * Permission to use, copy, modify and distribute this software and its   *
8  * documentation strictly for non-commercial purposes is hereby granted   *
9  * without fee, provided that the above copyright notice appears in all   *
10  * copies and that both the copyright notice and this permission notice   *
11  * appear in the supporting documentation. The authors make no claims     *
12  * about the suitability of this software for any purpose. It is          *
13  * provided "as is" without express or implied warranty.                  *
14  **************************************************************************/
15
16 /* $Id$ */
17
18 //-----------------------------------------------------------------------------
19 /// \class AliMUONTrackReconstructorK
20 ///
21 /// MUON track reconstructor using the kalman method
22 ///
23 /// This class contains as data:
24 /// - the parameters for the track reconstruction
25 ///
26 /// It contains as methods, among others:
27 /// - MakeTracks to build the tracks
28 ///
29 //-----------------------------------------------------------------------------
30
31 #include "AliMUONTrackReconstructorK.h"
32 #include "AliMUONConstants.h"
33 #include "AliMUONHitForRec.h"
34 #include "AliMUONTrack.h"
35 #include "AliMUONTrackParam.h"
36 #include "AliMUONTrackExtrap.h"
37
38 #include "AliLog.h"
39
40 #include <Riostream.h>
41 #include <TMath.h>
42 #include <TMatrixD.h>
43
44 /// \cond CLASSIMP
45 ClassImp(AliMUONTrackReconstructorK) // Class implementation in ROOT context
46 /// \endcond
47
48 //************* Defaults parameters for reconstruction
49 const Bool_t AliMUONTrackReconstructorK::fgkRunSmoother = kTRUE;
50
51
52   //__________________________________________________________________________
53 AliMUONTrackReconstructorK::AliMUONTrackReconstructorK()
54   : AliMUONVTrackReconstructor()
55 {
56   /// Constructor for class AliMUONTrackReconstructorK
57   AliInfo("*** Tracking with Kalman Filter ***");
58 }
59
60   //__________________________________________________________________________
61 AliMUONTrackReconstructorK::~AliMUONTrackReconstructorK()
62 {
63 /// Destructor
64
65
66   //__________________________________________________________________________
67 void AliMUONTrackReconstructorK::MakeTrackCandidates()
68 {
69   /// To make track candidates (assuming linear propagation if the flag fgkMakeTrackCandidatesFast is set to kTRUE):
70   /// Start with segments station(1..) 4 or 5 then follow track in station 5 or 4.
71   /// Good candidates are made of at least three hitForRec's.
72   /// Keep only best candidates or all of them according to the flag fgkTrackAllTracks.
73   TClonesArray *segments;
74   AliMUONTrack *track;
75   Int_t iCandidate = 0;
76   Bool_t hitFound;
77
78   AliDebug(1,"Enter MakeTrackCandidates");
79
80   // Loop over stations(1..) 5 and 4 and make track candidates
81   for (Int_t istat=4; istat>=3; istat--) {
82     
83     // Make segments in the station
84     segments = MakeSegmentsInStation(istat);
85     
86     // Loop over segments
87     for (Int_t iseg=0; iseg<segments->GetEntriesFast(); iseg++) {
88       AliDebug(1,Form("Making primary candidate(1..) %d",++iCandidate));
89       
90       // Transform segments to tracks and put them at the end of fRecTracksPtr
91       track = new ((*fRecTracksPtr)[fRecTracksPtr->GetLast()+1]) AliMUONTrack((AliMUONObjectPair*)((*segments)[iseg]));
92       fNRecTracks++;
93       
94       // Printout for debuging
95       if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 2) || (AliLog::GetGlobalDebugLevel() >= 2)) {
96         cout<<endl<<"Track parameter covariances at first hit:"<<endl;
97         ((AliMUONTrackParam*) (track->GetTrackParamAtHit()->First()))->GetCovariances().Print();
98       }
99       
100       // Look for compatible hitForRec(s) in the other station
101       if (fgkMakeTrackCandidatesFast) hitFound = FollowLinearTrackInStation(*track,7-istat);
102       else {
103         // First recompute track parameters and covariances on station(1..) 5 using Kalman filter
104         // (to make sure all tracks are treated in the same way)
105         if (istat == 4) RetraceTrack(*track,kFALSE);
106         hitFound = FollowTrackInStation(*track,7-istat);
107       }
108       
109       // Remove track if no hit found
110       if (!hitFound) {
111         fRecTracksPtr->Remove(track);
112         fNRecTracks--;
113       }
114       
115     }
116     // delete the array of segments
117     delete segments;
118   }
119   
120   
121   // Retrace tracks using Kalman filter and remove bad ones
122   if (fgkMakeTrackCandidatesFast) {
123     fRecTracksPtr->Compress(); // this is essential before checking tracks
124     
125     Int_t currentNRecTracks = fNRecTracks;
126     for (Int_t iRecTrack = 0; iRecTrack < currentNRecTracks; iRecTrack++) {
127       track = (AliMUONTrack*) fRecTracksPtr->UncheckedAt(iRecTrack);
128       
129       // Recompute track parameters and covariances using Kalman filter
130       RetraceTrack(*track,kTRUE);
131       
132       // Remove the track if the normalized chi2 is too high
133       if (track->GetNormalizedChi2() > fgkSigmaToCutForTracking * fgkSigmaToCutForTracking) {
134         fRecTracksPtr->Remove(track);
135         fNRecTracks--;
136       }
137       
138     }
139     
140   }
141   
142   fRecTracksPtr->Compress(); // this is essential before checking tracks
143   
144   // Keep all different tracks or only the best ones as required
145   if (fgkTrackAllTracks) RemoveIdenticalTracks();
146   else RemoveDoubleTracks();
147   
148   AliDebug(1,Form("Number of good candidates = %d",fNRecTracks));
149   
150 }
151
152   //__________________________________________________________________________
153 void AliMUONTrackReconstructorK::RetraceTrack(AliMUONTrack &trackCandidate, Bool_t resetSeed)
154 {
155   /// Re-run the kalman filter from the most downstream hit to the most uptream one
156   AliDebug(1,"Enter RetraceTrack");
157   
158   AliMUONTrackParam* startingTrackParam = (AliMUONTrackParam*) trackCandidate.GetTrackParamAtHit()->Last();
159   
160   // Reset the "seed" (= track parameters and their covariances at last hit) if required
161   if (resetSeed) {
162     // => Shift track parameters at the position of the last hit
163     AliMUONHitForRec* hitForRecAtHit = startingTrackParam->GetHitForRecPtr();
164     startingTrackParam->SetNonBendingCoor(hitForRecAtHit->GetNonBendingCoor());
165     startingTrackParam->SetBendingCoor(hitForRecAtHit->GetBendingCoor());
166     
167     // => Re-compute and reset track parameters covariances at last hit (as if the other hits did not exist)
168     const TMatrixD& kParamCov = startingTrackParam->GetCovariances();
169     TMatrixD newParamCov(5,5);
170     newParamCov.Zero();
171     // Non bending plane
172     newParamCov(0,0) = hitForRecAtHit->GetNonBendingReso2();
173     newParamCov(1,1) = 100.*kParamCov(1,1);
174     // Bending plane
175     newParamCov(2,2) = hitForRecAtHit->GetBendingReso2();
176     newParamCov(3,3) = 100.*kParamCov(3,3);
177     // Inverse bending momentum
178     newParamCov(4,4) = 0.5*startingTrackParam->GetInverseBendingMomentum() * 0.5*startingTrackParam->GetInverseBendingMomentum();
179     startingTrackParam->SetCovariances(newParamCov);
180     
181     // Reset the track chi2
182     startingTrackParam->SetTrackChi2(0.);
183   
184   }
185   
186   // Redo the tracking
187   RetracePartialTrack(trackCandidate, startingTrackParam);
188   
189 }
190
191   //__________________________________________________________________________
192 void AliMUONTrackReconstructorK::RetracePartialTrack(AliMUONTrack &trackCandidate, const AliMUONTrackParam* startingTrackParam)
193 {
194   /// Re-run the kalman filter from the hit attached to startingTrackParam to the most uptream hit
195   AliDebug(1,"Enter RetracePartialTrack");
196   
197   // Printout for debuging
198   if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
199     cout << "RetracePartialTrack: track chi2 before re-tracking: " << trackCandidate.GetFitFMin() << endl;
200   }
201   
202   // Reset the track chi2
203   trackCandidate.SetFitFMin(startingTrackParam->GetTrackChi2());
204   
205   // loop over attached hits until the first one and recompute track parameters and covariances using kalman filter
206   Int_t expectedChamber = startingTrackParam->GetHitForRecPtr()->GetChamberNumber() - 1;
207   Int_t currentChamber;
208   Double_t addChi2TrackAtHit;
209   AliMUONTrackParam* trackParamAtHit = (AliMUONTrackParam*) trackCandidate.GetTrackParamAtHit()->Before(startingTrackParam); 
210   while (trackParamAtHit) {
211     
212     // reset track parameters and their covariances
213     trackParamAtHit->SetParameters(startingTrackParam->GetParameters());
214     trackParamAtHit->SetZ(startingTrackParam->GetZ());
215     trackParamAtHit->SetCovariances(startingTrackParam->GetCovariances());
216     
217     // add MCS effect
218     AliMUONTrackExtrap::AddMCSEffect(trackParamAtHit,AliMUONConstants::ChamberThicknessInX0(),1.);
219     
220     // reset propagator for smoother
221     if (fgkRunSmoother) trackParamAtHit->ResetPropagator();
222     
223     // add MCS in missing chambers if any (at most 2 chambers can be missing according to tracking criteria)
224     currentChamber = trackParamAtHit->GetHitForRecPtr()->GetChamberNumber();
225     while (currentChamber < expectedChamber) {
226       // extrapolation to the missing chamber (update the propagator)
227       AliMUONTrackExtrap::ExtrapToZCov(trackParamAtHit, AliMUONConstants::DefaultChamberZ(expectedChamber), fgkRunSmoother);
228       // add MCS effect
229       AliMUONTrackExtrap::AddMCSEffect(trackParamAtHit,AliMUONConstants::ChamberThicknessInX0(),1.);
230       expectedChamber--;
231     }
232     
233     // extrapolation to the plane of the hitForRec attached to the current trackParamAtHit (update the propagator)
234     AliMUONTrackExtrap::ExtrapToZCov(trackParamAtHit, trackParamAtHit->GetHitForRecPtr()->GetZ(), fgkRunSmoother);
235     
236     if (fgkRunSmoother) {
237       // save extrapolated parameters for smoother
238       trackParamAtHit->SetExtrapParameters(trackParamAtHit->GetParameters());
239       
240       // save extrapolated covariance matrix for smoother
241       trackParamAtHit->SetExtrapCovariances(trackParamAtHit->GetCovariances());
242     }
243     
244     // Compute new track parameters including "hitForRecCh2" using kalman filter
245     addChi2TrackAtHit = RunKalmanFilter(*trackParamAtHit);
246     
247     // Update the track chi2
248     trackCandidate.SetFitFMin(trackCandidate.GetFitFMin() + addChi2TrackAtHit);
249     trackParamAtHit->SetTrackChi2(trackCandidate.GetFitFMin());
250     
251     // prepare next step, add MCS effects in parameter covariances
252     expectedChamber--;
253     startingTrackParam = trackParamAtHit;
254     trackParamAtHit = (AliMUONTrackParam*) (trackCandidate.GetTrackParamAtHit()->Before(startingTrackParam)); 
255   }
256   
257   // Printout for debuging
258   if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
259     cout << "RetracePartialTrack: track chi2 after re-tracking: " << trackCandidate.GetFitFMin() << endl;
260   }
261   
262 }
263
264   //__________________________________________________________________________
265 void AliMUONTrackReconstructorK::FollowTracks()
266 {
267   /// Follow tracks in stations(1..) 3, 2 and 1
268   AliDebug(1,"Enter FollowTracks");
269   
270   AliMUONTrack *track;
271   Int_t currentNRecTracks;
272   Bool_t hitFound;
273   
274   for (Int_t station = 2; station >= 0; station--) {
275     
276     // Save the actual number of reconstructed track in case of
277     // tracks are added or suppressed during the tracking procedure
278     // !! Do not compress fRecTracksPtr until the end of the loop over tracks !!
279     currentNRecTracks = fNRecTracks;
280     
281     for (Int_t iRecTrack = 0; iRecTrack <currentNRecTracks; iRecTrack++) {
282       AliDebug(1,Form("FollowTracks: track candidate(1..) %d", iRecTrack+1));
283       
284       track = (AliMUONTrack*) fRecTracksPtr->UncheckedAt(iRecTrack);
285       
286       // Printout for debuging
287       if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 2) || (AliLog::GetGlobalDebugLevel() >= 2)) {
288         cout<<endl<<"Track parameter covariances at first hit:"<<endl;
289         ((AliMUONTrackParam*) (track->GetTrackParamAtHit()->First()))->GetCovariances().Print();
290       }
291       
292       // Look for compatible hitForRec in station(0..) "station"
293       hitFound = FollowTrackInStation(*track,station);
294       
295       // Try to recover track if required
296       if (!hitFound && fgkRecoverTracks) hitFound = RecoverTrack(*track,station);
297       
298       // remove track if no hit found
299       if (!hitFound) {
300         fRecTracksPtr->Remove(track);
301         fNRecTracks--;
302       }
303       
304     }
305     
306     fRecTracksPtr->Compress(); // this is essential before checking tracks
307     
308     // Keep only the best tracks if required
309     if (!fgkTrackAllTracks) RemoveDoubleTracks();
310     
311   }
312   
313 }
314
315   //__________________________________________________________________________
316 Bool_t AliMUONTrackReconstructorK::FollowTrackInStation(AliMUONTrack &trackCandidate, Int_t nextStation)
317 {
318   /// Follow trackCandidate in station(0..) nextStation and search for compatible HitForRec(s)
319   /// Keep all possibilities or only the best one(s) according to the flag fgkTrackAllTracks:
320   /// kTRUE:  duplicate "trackCandidate" if there are several possibilities and add the new tracks at the end of
321   ///         fRecTracksPtr to avoid conficts with other track candidates at this current stage of the tracking procedure.
322   ///         Remove the obsolete "trackCandidate" at the end.
323   /// kFALSE: add only the best hit(s) to the "trackCandidate". Try to add a couple of hits in priority.
324   /// return kTRUE if new hits have been found (otherwise return kFALSE)
325   AliDebug(1,Form("Enter FollowTrackInStation(1..) %d", nextStation+1));
326   
327   // Order the chamber according to the propagation direction (tracking starts with chamber 2):
328   // - nextStation == station(1...) 5 => forward propagation
329   // - nextStation < station(1...) 5 => backward propagation
330   Int_t ch1, ch2;
331   if (nextStation==4) {
332     ch1 = 2*nextStation+1;
333     ch2 = 2*nextStation;
334   } else {
335     ch1 = 2*nextStation;
336     ch2 = 2*nextStation+1;
337   }
338   
339   Double_t chi2OfHitForRec;
340   Double_t maxChi2OfHitForRec = 2. * fgkSigmaToCutForTracking * fgkSigmaToCutForTracking; // 2 because 2 quantities in chi2
341   Double_t addChi2TrackAtHit1;
342   Double_t addChi2TrackAtHit2;
343   Double_t bestAddChi2TrackAtHit1 = 1.e10;
344   Double_t bestAddChi2TrackAtHit2 = 1.e10;
345   Bool_t foundOneHit = kFALSE;
346   Bool_t foundTwoHits = kFALSE;
347   AliMUONTrack *newTrack = 0x0;
348   AliMUONHitForRec *hitForRecCh1, *hitForRecCh2;
349   AliMUONTrackParam extrapTrackParam;
350   AliMUONTrackParam extrapTrackParamAtHit1;
351   AliMUONTrackParam extrapTrackParamAtHit2;
352   AliMUONTrackParam bestTrackParamAtHit1;
353   AliMUONTrackParam bestTrackParamAtHit2;
354   Bool_t *hitForRecCh1Used = new Bool_t[fNHitsForRecPerChamber[ch1]];
355   for (Int_t hit1 = 0; hit1 < fNHitsForRecPerChamber[ch1]; hit1++) hitForRecCh1Used[hit1] = kFALSE;
356
357   // Get track parameters
358   AliMUONTrackParam extrapTrackParamAtCh(*(AliMUONTrackParam*)trackCandidate.GetTrackParamAtHit()->First());
359   
360   // Add MCS effect
361   AliMUONTrackExtrap::AddMCSEffect(&extrapTrackParamAtCh,AliMUONConstants::ChamberThicknessInX0(),1.);
362   
363   // reset propagator for smoother
364   if (fgkRunSmoother) extrapTrackParamAtCh.ResetPropagator();
365   
366   // Add MCS in the missing chamber if any (only 1 chamber can be missing according to tracking criteria)
367   if (ch1 < ch2 && extrapTrackParamAtCh.GetHitForRecPtr()->GetChamberNumber() > ch2 + 1) {
368     // extrapolation to the missing chamber
369     AliMUONTrackExtrap::ExtrapToZCov(&extrapTrackParamAtCh, AliMUONConstants::DefaultChamberZ(ch2 + 1), fgkRunSmoother);
370     // add MCS effect
371     AliMUONTrackExtrap::AddMCSEffect(&extrapTrackParamAtCh,AliMUONConstants::ChamberThicknessInX0(),1.);
372   }
373   
374   //Extrapolate trackCandidate to chamber "ch2"
375   AliMUONTrackExtrap::ExtrapToZCov(&extrapTrackParamAtCh, AliMUONConstants::DefaultChamberZ(ch2), fgkRunSmoother);
376   
377   // Printout for debuging
378   if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 2) || (AliLog::GetGlobalDebugLevel() >= 2)) {
379     cout<<endl<<"Track parameter covariances at first hit extrapolated to z = "<<AliMUONConstants::DefaultChamberZ(ch2)<<":"<<endl;
380     extrapTrackParamAtCh.GetCovariances().Print();
381   }
382   
383   // Printout for debuging
384   if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
385     cout << "FollowTrackInStation: look for hits in chamber(1..): " << ch2+1 << endl;
386   }
387   
388   // look for candidates in chamber 2 
389   for (Int_t hit2 = 0; hit2 < fNHitsForRecPerChamber[ch2]; hit2++) {
390     
391     hitForRecCh2 = (AliMUONHitForRec*) fHitsForRecPtr->UncheckedAt(fIndexOfFirstHitForRecPerChamber[ch2]+hit2);
392     
393     // try to add the current hit fast
394     if (!TryOneHitForRecFast(extrapTrackParamAtCh, hitForRecCh2)) continue;
395     
396     // try to add the current hit accuratly
397     chi2OfHitForRec = TryOneHitForRec(extrapTrackParamAtCh, hitForRecCh2, extrapTrackParamAtHit2, fgkRunSmoother);
398     
399     // if good chi2 then try to attach a hitForRec in the other chamber too
400     if (chi2OfHitForRec < maxChi2OfHitForRec) {
401       Bool_t foundSecondHit = kFALSE;
402       
403       // Printout for debuging
404       if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
405         cout << "FollowTrackInStation: found one hit in chamber(1..): " << ch2+1
406              << " (Chi2 = " << chi2OfHitForRec << ")" << endl;
407         cout << "                      look for second hits in chamber(1..): " << ch1+1 << " ..." << endl;
408       }
409       
410       if (fgkRunSmoother) {
411         // save extrapolated parameters for smoother
412         extrapTrackParamAtHit2.SetExtrapParameters(extrapTrackParamAtHit2.GetParameters());
413         
414         // save extrapolated covariance matrix for smoother
415         extrapTrackParamAtHit2.SetExtrapCovariances(extrapTrackParamAtHit2.GetCovariances());
416       }
417       
418       // Compute new track parameters including "hitForRecCh2" using kalman filter
419       addChi2TrackAtHit2 = RunKalmanFilter(extrapTrackParamAtHit2);
420       
421       // copy new track parameters for next step
422       extrapTrackParam = extrapTrackParamAtHit2;
423       
424       // add MCS effect
425       AliMUONTrackExtrap::AddMCSEffect(&extrapTrackParam,AliMUONConstants::ChamberThicknessInX0(),1.);
426       
427       // reset propagator for smoother
428       if (fgkRunSmoother) extrapTrackParam.ResetPropagator();
429       
430       //Extrapolate track parameters to chamber "ch1"
431       AliMUONTrackExtrap::ExtrapToZCov(&extrapTrackParam, AliMUONConstants::DefaultChamberZ(ch1), fgkRunSmoother);
432       
433       for (Int_t hit1 = 0; hit1 < fNHitsForRecPerChamber[ch1]; hit1++) {
434         
435         hitForRecCh1 = (AliMUONHitForRec*) fHitsForRecPtr->UncheckedAt(fIndexOfFirstHitForRecPerChamber[ch1]+hit1);
436         
437         // try to add the current hit fast
438         if (!TryOneHitForRecFast(extrapTrackParam, hitForRecCh1)) continue;
439         
440         // try to add the current hit accuratly
441         chi2OfHitForRec = TryOneHitForRec(extrapTrackParam, hitForRecCh1, extrapTrackParamAtHit1, fgkRunSmoother);
442         
443         // if good chi2 then consider to add the 2 hitForRec to the "trackCandidate"
444         if (chi2OfHitForRec < maxChi2OfHitForRec) {
445           foundSecondHit = kTRUE;
446           foundTwoHits = kTRUE;
447           
448           // Printout for debuging
449           if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
450             cout << "FollowTrackInStation: found one hit in chamber(1..): " << ch1+1
451                  << " (Chi2 = " << chi2OfHitForRec << ")" << endl;
452           }
453           
454           if (fgkRunSmoother) {
455             // save extrapolated parameters for smoother
456             extrapTrackParamAtHit1.SetExtrapParameters(extrapTrackParamAtHit1.GetParameters());
457             
458             // save extrapolated covariance matrix for smoother
459             extrapTrackParamAtHit1.SetExtrapCovariances(extrapTrackParamAtHit1.GetCovariances());
460           }
461           
462           // Compute new track parameters including "hitForRecCh1" using kalman filter
463           addChi2TrackAtHit1 = RunKalmanFilter(extrapTrackParamAtHit1);
464           
465           if (fgkTrackAllTracks) {
466             // copy trackCandidate into a new track put at the end of fRecTracksPtr and add the new hitForRec's
467             newTrack = new ((*fRecTracksPtr)[fRecTracksPtr->GetLast()+1]) AliMUONTrack(trackCandidate);
468             UpdateTrack(*newTrack,extrapTrackParamAtHit1,extrapTrackParamAtHit2,addChi2TrackAtHit1,addChi2TrackAtHit2);
469             fNRecTracks++;
470             
471             // if we are arrived on station(1..) 5, recompute track parameters and covariances starting from this station
472             // (going in the right direction)
473             if (nextStation == 4) RetraceTrack(*newTrack,kTRUE);
474             
475             // Tag hitForRecCh1 as used
476             hitForRecCh1Used[hit1] = kTRUE;
477             
478             // Printout for debuging
479             if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
480               cout << "FollowTrackInStation: added two hits in station(1..): " << nextStation+1 << endl;
481               if (AliLog::GetGlobalDebugLevel() >= 3) newTrack->RecursiveDump();
482             }
483             
484           } else if (addChi2TrackAtHit1+addChi2TrackAtHit2 < bestAddChi2TrackAtHit1+bestAddChi2TrackAtHit2) {
485             // keep track of the best couple of hits
486             bestAddChi2TrackAtHit1 = addChi2TrackAtHit1;
487             bestAddChi2TrackAtHit2 = addChi2TrackAtHit2;
488             bestTrackParamAtHit1 = extrapTrackParamAtHit1;
489             bestTrackParamAtHit2 = extrapTrackParamAtHit2;
490           }
491           
492         }
493         
494       }
495       
496       // if no hitForRecCh1 found then consider to add hitForRecCh2 only
497       if (!foundSecondHit) {
498         foundOneHit = kTRUE;
499         
500         if (fgkTrackAllTracks) {
501           // copy trackCandidate into a new track put at the end of fRecTracksPtr and add the new hitForRec's
502           newTrack = new ((*fRecTracksPtr)[fRecTracksPtr->GetLast()+1]) AliMUONTrack(trackCandidate);
503           UpdateTrack(*newTrack,extrapTrackParamAtHit2,addChi2TrackAtHit2);
504           fNRecTracks++;
505           
506           // if we are arrived on station(1..) 5, recompute track parameters and covariances starting from this station
507           // (going in the right direction)
508           if (nextStation == 4) RetraceTrack(*newTrack,kTRUE);
509           
510           // Printout for debuging
511           if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
512             cout << "FollowTrackInStation: added one hit in chamber(1..): " << ch2+1 << endl;
513             if (AliLog::GetGlobalDebugLevel() >= 3) newTrack->RecursiveDump();
514           }
515           
516         } else if (!foundTwoHits && addChi2TrackAtHit2 < bestAddChi2TrackAtHit1) {
517           // keep track of the best single hitForRec except if a couple of hits has already been found
518           bestAddChi2TrackAtHit1 = addChi2TrackAtHit2;
519           bestTrackParamAtHit1 = extrapTrackParamAtHit2;
520         }
521         
522       }
523       
524     }
525     
526   }
527   
528   // look for candidates in chamber 1 not already attached to a track
529   // if we want to keep all possible tracks or if no good couple of hitForRec has been found
530   if (fgkTrackAllTracks || !foundTwoHits) {
531     
532     // Printout for debuging
533     if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
534       cout << "FollowTrackInStation: look for single hits in chamber(1..): " << ch1+1 << endl;
535     }
536     
537     // add MCS effect for next step
538     AliMUONTrackExtrap::AddMCSEffect(&extrapTrackParamAtCh,AliMUONConstants::ChamberThicknessInX0(),1.);
539     
540     //Extrapolate trackCandidate to chamber "ch1"
541     AliMUONTrackExtrap::ExtrapToZCov(&extrapTrackParamAtCh, AliMUONConstants::DefaultChamberZ(ch1), fgkRunSmoother);
542     
543     for (Int_t hit1 = 0; hit1 < fNHitsForRecPerChamber[ch1]; hit1++) {
544       
545       hitForRecCh1 = (AliMUONHitForRec*) fHitsForRecPtr->UncheckedAt(fIndexOfFirstHitForRecPerChamber[ch1]+hit1);
546       
547       if (hitForRecCh1Used[hit1]) continue; // Skip hitForRec already used
548       
549       // try to add the current hit fast
550       if (!TryOneHitForRecFast(extrapTrackParamAtCh, hitForRecCh1)) continue;
551       
552       // try to add the current hit accuratly
553       chi2OfHitForRec = TryOneHitForRec(extrapTrackParamAtCh, hitForRecCh1, extrapTrackParamAtHit1, fgkRunSmoother);
554       
555       // if good chi2 then consider to add hitForRecCh1
556       // We do not try to attach a hitForRec in the other chamber too since it has already been done above
557       if (chi2OfHitForRec < maxChi2OfHitForRec) {
558         foundOneHit = kTRUE;
559         
560         // Printout for debuging
561         if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
562           cout << "FollowTrackInStation: found one hit in chamber(1..): " << ch1+1
563                << " (Chi2 = " << chi2OfHitForRec << ")" << endl;
564         }
565         
566         if (fgkRunSmoother) {
567           // save extrapolated parameters for smoother
568           extrapTrackParamAtHit1.SetExtrapParameters(extrapTrackParamAtHit1.GetParameters());
569           
570           // save extrapolated covariance matrix for smoother
571           extrapTrackParamAtHit1.SetExtrapCovariances(extrapTrackParamAtHit1.GetCovariances());
572         }
573         
574         // Compute new track parameters including "hitForRecCh1" using kalman filter
575         addChi2TrackAtHit1 = RunKalmanFilter(extrapTrackParamAtHit1);
576         
577         if (fgkTrackAllTracks) {
578           // copy trackCandidate into a new track put at the end of fRecTracksPtr and add the new hitForRec's
579           newTrack = new ((*fRecTracksPtr)[fRecTracksPtr->GetLast()+1]) AliMUONTrack(trackCandidate);
580           UpdateTrack(*newTrack,extrapTrackParamAtHit1,addChi2TrackAtHit1);
581           fNRecTracks++;
582           
583           // if we are arrived on station(1..) 5, recompute track parameters and covariances starting from this station
584           // (going in the right direction)
585           if (nextStation == 4) RetraceTrack(*newTrack,kTRUE);
586           
587           // Printout for debuging
588           if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
589             cout << "FollowTrackInStation: added one hit in chamber(1..): " << ch1+1 << endl;
590             if (AliLog::GetGlobalDebugLevel() >= 3) newTrack->RecursiveDump();
591           }
592           
593         } else if (addChi2TrackAtHit1 < bestAddChi2TrackAtHit1) {
594           // keep track of the best single hitForRec except if a couple of hits has already been found
595           bestAddChi2TrackAtHit1 = addChi2TrackAtHit1;
596           bestTrackParamAtHit1 = extrapTrackParamAtHit1;
597         }
598         
599       }
600       
601     }
602     
603   }
604   
605   // fill out the best track if required else clean up the fRecTracksPtr array
606   if (!fgkTrackAllTracks) {
607     if (foundTwoHits) {
608       UpdateTrack(trackCandidate,bestTrackParamAtHit1,bestTrackParamAtHit2,bestAddChi2TrackAtHit1,bestAddChi2TrackAtHit2);
609       
610       // if we are arrived on station(1..) 5, recompute track parameters and covariances starting from this station
611       // (going in the right direction)
612       if (nextStation == 4) RetraceTrack(trackCandidate,kTRUE);
613
614       // Printout for debuging
615       if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
616         cout << "FollowTrackInStation: added the two best hits in station(1..): " << nextStation+1 << endl;
617         if (AliLog::GetGlobalDebugLevel() >= 3) newTrack->RecursiveDump();
618       }
619       
620     } else if (foundOneHit) {
621       UpdateTrack(trackCandidate,bestTrackParamAtHit1,bestAddChi2TrackAtHit1);
622       
623       // if we are arrived on station(1..) 5, recompute track parameters and covariances starting from this station
624       // (going in the right direction)
625       if (nextStation == 4) RetraceTrack(trackCandidate,kTRUE);
626
627       // Printout for debuging
628       if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
629         cout << "FollowTrackInStation: added the best hit in chamber(1..): " << bestTrackParamAtHit1.GetHitForRecPtr()->GetChamberNumber()+1 << endl;
630         if (AliLog::GetGlobalDebugLevel() >= 3) newTrack->RecursiveDump();
631       }
632       
633     } else {
634       delete [] hitForRecCh1Used;
635       return kFALSE;
636     }
637   } else if (foundOneHit || foundTwoHits) {
638     
639     // remove obsolete track
640     fRecTracksPtr->Remove(&trackCandidate);
641     fNRecTracks--;
642     
643   } else {
644     delete [] hitForRecCh1Used;
645     return kFALSE;
646   }  
647   delete [] hitForRecCh1Used;
648   return kTRUE;
649   
650 }
651
652   //__________________________________________________________________________
653 Double_t AliMUONTrackReconstructorK::RunKalmanFilter(AliMUONTrackParam &trackParamAtHit)
654 {
655   /// Compute new track parameters and their covariances including new hit using kalman filter
656   /// return the additional track chi2
657   AliDebug(1,"Enter RunKalmanFilter");
658   
659   // Get actual track parameters (p)
660   TMatrixD param(trackParamAtHit.GetParameters());
661   
662   // Get new hit parameters (m)
663   AliMUONHitForRec *hitForRecAtHit = trackParamAtHit.GetHitForRecPtr();
664   TMatrixD hit(5,1);
665   hit.Zero();
666   hit(0,0) = hitForRecAtHit->GetNonBendingCoor();
667   hit(2,0) = hitForRecAtHit->GetBendingCoor();
668   
669   // Compute the actual parameter weight (W)
670   TMatrixD paramWeight(trackParamAtHit.GetCovariances());
671   if (paramWeight.Determinant() != 0) {
672     paramWeight.Invert();
673   } else {
674     AliWarning(" Determinant = 0");
675     return 1.e10;
676   }
677   
678   // Compute the new hit weight (U)
679   TMatrixD hitWeight(5,5);
680   hitWeight.Zero();
681   hitWeight(0,0) = 1. / hitForRecAtHit->GetNonBendingReso2();
682   hitWeight(2,2) = 1. / hitForRecAtHit->GetBendingReso2();
683
684   // Compute the new parameters covariance matrix ( (W+U)^-1 )
685   TMatrixD newParamCov(paramWeight,TMatrixD::kPlus,hitWeight);
686   if (newParamCov.Determinant() != 0) {
687     newParamCov.Invert();
688   } else {
689     AliWarning(" Determinant = 0");
690     return 1.e10;
691   }
692   
693   // Save the new parameters covariance matrix
694   trackParamAtHit.SetCovariances(newParamCov);
695   
696   // Compute the new parameters (p' = ((W+U)^-1)U(m-p) + p)
697   TMatrixD tmp(hit,TMatrixD::kMinus,param);
698   TMatrixD tmp2(hitWeight,TMatrixD::kMult,tmp); // U(m-p)
699   TMatrixD newParam(newParamCov,TMatrixD::kMult,tmp2); // ((W+U)^-1)U(m-p)
700   newParam += param; // ((W+U)^-1)U(m-p) + p
701   
702   // Save the new parameters
703   trackParamAtHit.SetParameters(newParam);
704   
705   // Compute the additional chi2 (= ((p'-p)^-1)W(p'-p) + ((p'-m)^-1)U(p'-m))
706   tmp = newParam; // p'
707   tmp -= param; // (p'-p)
708   TMatrixD tmp3(paramWeight,TMatrixD::kMult,tmp); // W(p'-p)
709   TMatrixD addChi2Track(tmp,TMatrixD::kTransposeMult,tmp3); // ((p'-p)^-1)W(p'-p)
710   tmp = newParam; // p'
711   tmp -= hit; // (p'-m)
712   TMatrixD tmp4(hitWeight,TMatrixD::kMult,tmp); // U(p'-m)
713   addChi2Track += TMatrixD(tmp,TMatrixD::kTransposeMult,tmp4); // ((p'-p)^-1)W(p'-p) + ((p'-m)^-1)U(p'-m)
714   
715   return addChi2Track(0,0);
716   
717 }
718
719   //__________________________________________________________________________
720 void AliMUONTrackReconstructorK::UpdateTrack(AliMUONTrack &track, AliMUONTrackParam &trackParamAtHit, Double_t addChi2)
721 {
722   /// Add 1 hit to the track candidate
723   /// Update chi2 of the track 
724   
725   // Flag hit as being not removable
726   trackParamAtHit.SetRemovable(kFALSE);
727   trackParamAtHit.SetLocalChi2(0.); // --> Local chi2 not used
728   
729   // Update the track chi2 into TrackParamAtHit
730   trackParamAtHit.SetTrackChi2(track.GetFitFMin() + addChi2);
731   
732   // Update the chi2 of the new track
733   track.SetFitFMin(trackParamAtHit.GetTrackChi2());
734   
735   // Update array of TrackParamAtHit
736   track.AddTrackParamAtHit(&trackParamAtHit,trackParamAtHit.GetHitForRecPtr());
737   track.GetTrackParamAtHit()->Sort();
738   
739 }
740
741   //__________________________________________________________________________
742 void AliMUONTrackReconstructorK::UpdateTrack(AliMUONTrack &track, AliMUONTrackParam &trackParamAtHit1, AliMUONTrackParam &trackParamAtHit2,
743                                              Double_t addChi2AtHit1, Double_t addChi2AtHit2)
744 {
745   /// Add 2 hits to the track candidate
746   /// Update track and local chi2
747   
748   // Update local chi2 at first hit
749   AliMUONHitForRec* hit1 = trackParamAtHit1.GetHitForRecPtr();
750   Double_t deltaX = trackParamAtHit1.GetNonBendingCoor() - hit1->GetNonBendingCoor();
751   Double_t deltaY = trackParamAtHit1.GetBendingCoor() - hit1->GetBendingCoor();
752   Double_t localChi2AtHit1 = deltaX*deltaX / hit1->GetNonBendingReso2() +
753                              deltaY*deltaY / hit1->GetBendingReso2();
754   trackParamAtHit1.SetLocalChi2(localChi2AtHit1);
755   
756   // Flag first hit as being removable
757   trackParamAtHit1.SetRemovable(kTRUE);
758   
759   // Update local chi2 at second hit
760   AliMUONHitForRec* hit2 = trackParamAtHit2.GetHitForRecPtr();
761   AliMUONTrackParam extrapTrackParamAtHit2(trackParamAtHit1);
762   AliMUONTrackExtrap::ExtrapToZ(&extrapTrackParamAtHit2, trackParamAtHit2.GetZ());
763   deltaX = extrapTrackParamAtHit2.GetNonBendingCoor() - hit2->GetNonBendingCoor();
764   deltaY = extrapTrackParamAtHit2.GetBendingCoor() - hit2->GetBendingCoor();
765   Double_t localChi2AtHit2 = deltaX*deltaX / hit2->GetNonBendingReso2() +
766                              deltaY*deltaY / hit2->GetBendingReso2();
767   trackParamAtHit2.SetLocalChi2(localChi2AtHit2);
768   
769   // Flag second hit as being removable
770   trackParamAtHit2.SetRemovable(kTRUE);
771   
772   // Update the track chi2 into TrackParamAtHit1
773   trackParamAtHit1.SetTrackChi2(track.GetFitFMin() + addChi2AtHit1);
774   
775   // Update the track chi2 into TrackParamAtHit2
776   trackParamAtHit2.SetTrackChi2(trackParamAtHit1.GetTrackChi2() + addChi2AtHit2);
777   
778   // Update the chi2 of the new track
779   track.SetFitFMin(trackParamAtHit2.GetTrackChi2());
780   
781   // Update array of TrackParamAtHit
782   track.AddTrackParamAtHit(&trackParamAtHit1,trackParamAtHit1.GetHitForRecPtr());
783   track.AddTrackParamAtHit(&trackParamAtHit2,trackParamAtHit2.GetHitForRecPtr());
784   track.GetTrackParamAtHit()->Sort();
785   
786 }
787
788   //__________________________________________________________________________
789 Bool_t AliMUONTrackReconstructorK::RecoverTrack(AliMUONTrack &trackCandidate, Int_t nextStation)
790 {
791   /// Try to recover the track candidate in the next station
792   /// by removing the worst of the two hits attached in the current station
793   /// Return kTRUE if recovering succeeds
794   AliDebug(1,"Enter RecoverTrack");
795   
796   // Do not try to recover track until we have attached hit(s) on station(1..) 3
797   if (nextStation > 1) return kFALSE;
798   
799   Int_t worstHitNumber = -1;
800   Double_t localChi2, worstChi2 = 0.;
801   
802   // Look for the hit to remove
803   for (Int_t hitNumber = 0; hitNumber < 2; hitNumber++) {
804     AliMUONTrackParam *trackParamAtHit = (AliMUONTrackParam*)trackCandidate.GetTrackParamAtHit()->UncheckedAt(hitNumber);
805     
806     // check if current hit is removable
807     if (!trackParamAtHit->IsRemovable()) return kFALSE;
808     
809     // Pick up hit with the worst chi2
810     localChi2 = trackParamAtHit->GetLocalChi2();
811     if (localChi2 > worstChi2) {
812       worstChi2 = localChi2;
813       worstHitNumber = hitNumber;
814     }
815   }
816   
817   // Reset best hit as being NOT removable
818   ((AliMUONTrackParam*)trackCandidate.GetTrackParamAtHit()->UncheckedAt((worstHitNumber+1)%2))->SetRemovable(kFALSE);
819   
820   // Remove the worst hit
821   trackCandidate.RemoveTrackParamAtHit((AliMUONTrackParam*)trackCandidate.GetTrackParamAtHit()->UncheckedAt(worstHitNumber));
822   
823   // Re-calculate track parameters at the (new) first hit
824   RetracePartialTrack(trackCandidate,(AliMUONTrackParam*)trackCandidate.GetTrackParamAtHit()->UncheckedAt(1));
825   
826   // Look for new hit(s) in next station
827   return FollowTrackInStation(trackCandidate,nextStation);
828   
829 }
830
831   //__________________________________________________________________________
832 Bool_t AliMUONTrackReconstructorK::RunSmoother(AliMUONTrack &track)
833 {
834   /// Compute new track parameters and their covariances using smoother
835   AliDebug(1,"Enter RunSmoother");
836   
837   AliMUONTrackParam *previousTrackParam = (AliMUONTrackParam*) track.GetTrackParamAtHit()->First();
838   
839   // Smoothed parameters and covariances at first hit = filtered parameters and covariances
840   previousTrackParam->SetSmoothParameters(previousTrackParam->GetParameters());
841   previousTrackParam->SetSmoothCovariances(previousTrackParam->GetCovariances());
842   
843   // Compute local chi2 at first hit
844   AliMUONHitForRec *hitForRecAtHit = previousTrackParam->GetHitForRecPtr();
845   Double_t dX = hitForRecAtHit->GetNonBendingCoor() - previousTrackParam->GetNonBendingCoor();
846   Double_t dY = hitForRecAtHit->GetBendingCoor() - previousTrackParam->GetBendingCoor();
847   Double_t localChi2 = dX * dX / hitForRecAtHit->GetNonBendingReso2() + dY * dY / hitForRecAtHit->GetBendingReso2();
848   
849   // Save local chi2 at first hit
850   previousTrackParam->SetLocalChi2(localChi2);
851   
852   AliMUONTrackParam *currentTrackParam = (AliMUONTrackParam*) track.GetTrackParamAtHit()->After(previousTrackParam);
853   while (currentTrackParam) {
854     
855     // Get variables
856     const TMatrixD &extrapParameters          = previousTrackParam->GetExtrapParameters();  // X(k+1 k)
857     const TMatrixD &filteredParameters        = currentTrackParam->GetParameters();         // X(k k)
858     const TMatrixD &previousSmoothParameters  = previousTrackParam->GetSmoothParameters();  // X(k+1 n)
859     const TMatrixD &propagator                = previousTrackParam->GetPropagator();        // F(k)
860     const TMatrixD &extrapCovariances         = previousTrackParam->GetExtrapCovariances(); // C(k+1 k)
861     const TMatrixD &filteredCovariances       = currentTrackParam->GetCovariances();        // C(k k)
862     const TMatrixD &previousSmoothCovariances = previousTrackParam->GetSmoothCovariances(); // C(k+1 n)
863     
864     // Compute smoother gain: A(k) = C(kk) * F(f)^t * (C(k+1 k))^-1
865     TMatrixD extrapWeight(extrapCovariances);
866     if (extrapWeight.Determinant() != 0) {
867       extrapWeight.Invert(); // (C(k+1 k))^-1
868     } else {
869       AliWarning(" Determinant = 0");
870       return kFALSE;
871     }
872     TMatrixD smootherGain(filteredCovariances,TMatrixD::kMultTranspose,propagator); // C(kk) * F(f)^t
873     smootherGain *= extrapWeight; // C(kk) * F(f)^t * (C(k+1 k))^-1
874     
875     // Compute smoothed parameters: X(k n) = X(k k) + A(k) * (X(k+1 n) - X(k+1 k))
876     TMatrixD tmpParam(previousSmoothParameters,TMatrixD::kMinus,extrapParameters); // X(k+1 n) - X(k+1 k)
877     TMatrixD smoothParameters(smootherGain,TMatrixD::kMult,tmpParam); // A(k) * (X(k+1 n) - X(k+1 k))
878     smoothParameters += filteredParameters; // X(k k) + A(k) * (X(k+1 n) - X(k+1 k))
879     
880     // Save smoothed parameters
881     currentTrackParam->SetSmoothParameters(smoothParameters);
882     
883     // Compute smoothed covariances: C(k n) = C(k k) + A(k) * (C(k+1 n) - C(k+1 k)) * (A(k))^t
884     TMatrixD tmpCov(previousSmoothCovariances,TMatrixD::kMinus,extrapCovariances); // C(k+1 n) - C(k+1 k)
885     TMatrixD tmpCov2(tmpCov,TMatrixD::kMultTranspose,smootherGain); // (C(k+1 n) - C(k+1 k)) * (A(k))^t
886     TMatrixD smoothCovariances(smootherGain,TMatrixD::kMult,tmpCov2); // A(k) * (C(k+1 n) - C(k+1 k)) * (A(k))^t
887     smoothCovariances += filteredCovariances; // C(k k) + A(k) * (C(k+1 n) - C(k+1 k)) * (A(k))^t
888     
889     // Save smoothed covariances
890     currentTrackParam->SetSmoothCovariances(smoothCovariances);
891     
892     // Compute smoothed residual: r(k n) = hit - X(k n)
893     hitForRecAtHit = currentTrackParam->GetHitForRecPtr();
894     TMatrixD smoothResidual(2,1);
895     smoothResidual.Zero();
896     smoothResidual(0,0) = hitForRecAtHit->GetNonBendingCoor() - smoothParameters(0,0);
897     smoothResidual(1,0) = hitForRecAtHit->GetBendingCoor() - smoothParameters(2,0);
898     
899     // Compute weight of smoothed residual: W(k n) = (hitCov - C(k n))^-1
900     TMatrixD smoothResidualWeight(2,2);
901     smoothResidualWeight(0,0) = hitForRecAtHit->GetNonBendingReso2() - smoothCovariances(0,0);
902     smoothResidualWeight(0,1) = - smoothCovariances(0,2);
903     smoothResidualWeight(1,0) = - smoothCovariances(2,0);
904     smoothResidualWeight(1,1) = hitForRecAtHit->GetBendingReso2() - smoothCovariances(2,2);
905     if (smoothResidualWeight.Determinant() != 0) {
906       smoothResidualWeight.Invert();
907     } else {
908       AliWarning(" Determinant = 0");
909       return kFALSE;
910     }
911     
912     // Compute local chi2 = (r(k n))^t * W(k n) * r(k n)
913     TMatrixD tmpChi2(smoothResidual,TMatrixD::kTransposeMult,smoothResidualWeight); // (r(k n))^t * W(k n)
914     TMatrixD localChi2(tmpChi2,TMatrixD::kMult,smoothResidual); // (r(k n))^t * W(k n) * r(k n)
915     
916     // Save local chi2
917     currentTrackParam->SetLocalChi2(localChi2(0,0));
918     
919     previousTrackParam = currentTrackParam;
920     currentTrackParam = (AliMUONTrackParam*) track.GetTrackParamAtHit()->After(previousTrackParam);
921   }
922   
923   return kTRUE;
924   
925 }
926
927   //__________________________________________________________________________
928 void AliMUONTrackReconstructorK::ImproveTracks()
929 {
930   /// Improve tracks by removing clusters with local chi2 highter than the defined cut
931   /// Recompute track parameters and covariances at the remaining clusters
932   AliDebug(1,"Enter ImproveTracks");
933   
934   Double_t localChi2, worstLocalChi2;
935   Int_t worstChamber;
936   AliMUONTrackParam *trackParamAtHit, *worstTrackParamAtHit;
937   Bool_t smoothed;
938   
939   // Remove double track to improve only "good" tracks
940   RemoveDoubleTracks();
941   
942   AliMUONTrack *track = (AliMUONTrack*) fRecTracksPtr->First();
943   while (track) {
944     
945     while (!track->IsImproved()) {
946       
947       // Run smoother if required
948       smoothed = kFALSE;
949       if (fgkRunSmoother) smoothed = RunSmoother(*track);
950       
951       // Use standard procedure to compute local chi2 if smoother not required or not working
952       if (!smoothed) {
953         
954         // Update track parameters and covariances
955         track->UpdateCovTrackParamAtHit();
956         
957         // Compute local chi2 of each hits
958         track->ComputeLocalChi2(kTRUE);
959       }
960       
961       // Look for the hit to remove
962       worstTrackParamAtHit = NULL;
963       worstLocalChi2 = 0.;
964       trackParamAtHit = (AliMUONTrackParam*)track->GetTrackParamAtHit()->First();
965       while (trackParamAtHit) {
966         
967         // Pick up hit with the worst chi2
968         localChi2 = trackParamAtHit->GetLocalChi2();
969         if (localChi2 > worstLocalChi2) {
970           worstLocalChi2 = localChi2;
971           worstTrackParamAtHit = trackParamAtHit;
972         }
973         
974       trackParamAtHit = (AliMUONTrackParam*)track->GetTrackParamAtHit()->After(trackParamAtHit);
975       }
976       
977       // Check if bad removable hit found
978       if (!worstTrackParamAtHit) {
979         track->SetImproved(kTRUE);
980         break;
981       }
982       
983       // check whether the worst hit is removable or not
984       if (!worstTrackParamAtHit->IsRemovable()) {
985         track->SetImproved(kTRUE);
986         break;
987       }
988       
989       // Check whether the worst chi2 is under requirement or not
990       if (worstLocalChi2 < 2. * fgkSigmaToCutForImprovement * fgkSigmaToCutForImprovement) { // 2 because 2 quantities in chi2
991         track->SetImproved(kTRUE);
992         break;
993       }
994       
995       // Reset the second hit in the same station as the bad one as being NOT removable
996       worstChamber = worstTrackParamAtHit->GetHitForRecPtr()->GetChamberNumber();
997       if (worstChamber%2 == 0) ((AliMUONTrackParam*)track->GetTrackParamAtHit()->After(worstTrackParamAtHit))->SetRemovable(kFALSE);
998       else ((AliMUONTrackParam*)track->GetTrackParamAtHit()->Before(worstTrackParamAtHit))->SetRemovable(kFALSE);
999       
1000       // Save pointer to the trackParamAtHit next to the one to be removed
1001       trackParamAtHit = (AliMUONTrackParam*)track->GetTrackParamAtHit()->After(worstTrackParamAtHit);
1002       
1003       // Remove the worst hit
1004       track->RemoveTrackParamAtHit(worstTrackParamAtHit);
1005       
1006       // Re-calculate track parameters
1007       // - from the hit immediately downstream the one suppressed
1008       // - or from the begining - if parameters have been re-computed using the standard method (kalman parameters have been lost)
1009       //                        - or if the removed hit was the last one
1010       if (smoothed && trackParamAtHit) RetracePartialTrack(*track,trackParamAtHit);
1011       else RetraceTrack(*track,kTRUE);
1012       
1013       // Printout for debuging
1014       if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
1015         cout << "ImproveTracks: track " << fRecTracksPtr->IndexOf(track)+1 << " improved " << endl;
1016       }
1017       
1018     }
1019     
1020     track = (AliMUONTrack*) fRecTracksPtr->After(track);
1021   }
1022   
1023 }
1024
1025   //__________________________________________________________________________
1026 void AliMUONTrackReconstructorK::Finalize()
1027 {
1028   /// Fill AliMUONTrack's fHitForRecAtHit array
1029   AliMUONTrack *track;
1030   AliMUONTrackParam *trackParamAtHit;
1031   Bool_t smoothed = kFALSE;
1032   
1033   track = (AliMUONTrack*) fRecTracksPtr->First();
1034   while (track) {
1035     
1036     // update track parameters (using smoother if required) if not already done
1037     if (!track->IsImproved()) {
1038       smoothed = kFALSE;
1039       if (fgkRunSmoother) smoothed = RunSmoother(*track);
1040       if (!smoothed) track->UpdateCovTrackParamAtHit();
1041     }
1042     
1043     trackParamAtHit = (AliMUONTrackParam*) (track->GetTrackParamAtHit()->First());
1044     while (trackParamAtHit) {
1045       
1046       // copy smoothed parameters and covariances if any
1047       if (smoothed) {
1048         trackParamAtHit->SetParameters(trackParamAtHit->GetSmoothParameters());
1049         trackParamAtHit->SetCovariances(trackParamAtHit->GetSmoothCovariances());
1050       }
1051       
1052       // update array of track hits
1053       track->AddHitForRecAtHit(trackParamAtHit->GetHitForRecPtr());
1054       
1055       trackParamAtHit = (AliMUONTrackParam*) (track->GetTrackParamAtHit()->After(trackParamAtHit));
1056     }
1057     
1058     track = (AliMUONTrack*) fRecTracksPtr->After(track);
1059     
1060   }
1061     
1062 }
1063