Main changes:
[u/mrichter/AliRoot.git] / MUON / AliMUONTrackReconstructorK.cxx
1 /**************************************************************************
2  * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
3  *                                                                        *
4  * Author: The ALICE Off-line Project.                                    *
5  * Contributors are mentioned in the code where appropriate.              *
6  *                                                                        *
7  * Permission to use, copy, modify and distribute this software and its   *
8  * documentation strictly for non-commercial purposes is hereby granted   *
9  * without fee, provided that the above copyright notice appears in all   *
10  * copies and that both the copyright notice and this permission notice   *
11  * appear in the supporting documentation. The authors make no claims     *
12  * about the suitability of this software for any purpose. It is          *
13  * provided "as is" without express or implied warranty.                  *
14  **************************************************************************/
15
16 /* $Id$ */
17
18 //-----------------------------------------------------------------------------
19 /// \class AliMUONTrackReconstructorK
20 ///
21 /// MUON track reconstructor using the kalman method
22 ///
23 /// This class contains as data:
24 /// - the parameters for the track reconstruction
25 ///
26 /// It contains as methods, among others:
27 /// - MakeTracks to build the tracks
28 ///
29 //-----------------------------------------------------------------------------
30
31 #include "AliMUONTrackReconstructorK.h"
32
33 #include "AliMUONConstants.h"
34 #include "AliMUONVCluster.h"
35 #include "AliMUONVClusterStore.h"
36 #include "AliMUONTrack.h"
37 #include "AliMUONTrackParam.h"
38 #include "AliMUONTrackExtrap.h"
39
40 #include "AliLog.h"
41
42 #include <Riostream.h>
43 #include <TMath.h>
44 #include <TMatrixD.h>
45
46 /// \cond CLASSIMP
47 ClassImp(AliMUONTrackReconstructorK) // Class implementation in ROOT context
48 /// \endcond
49
50   //__________________________________________________________________________
51 AliMUONTrackReconstructorK::AliMUONTrackReconstructorK()
52   : AliMUONVTrackReconstructor()
53 {
54   /// Constructor
55 }
56
57   //__________________________________________________________________________
58 AliMUONTrackReconstructorK::~AliMUONTrackReconstructorK()
59 {
60 /// Destructor
61
62
63   //__________________________________________________________________________
64 void AliMUONTrackReconstructorK::MakeTrackCandidates(const AliMUONVClusterStore& clusterStore)
65 {
66   /// To make track candidates (assuming linear propagation if the flag fgkMakeTrackCandidatesFast is set to kTRUE):
67   /// Start with segments station(1..) 4 or 5 then follow track in station 5 or 4.
68   /// Good candidates are made of at least three clusters.
69   /// Keep only best candidates or all of them according to the flag fgkTrackAllTracks.
70   
71   TClonesArray *segments;
72   AliMUONTrack *track;
73   Int_t iCandidate = 0;
74   Bool_t clusterFound;
75
76   AliDebug(1,"Enter MakeTrackCandidates");
77
78   // Loop over stations(1..) 5 and 4 and make track candidates
79   for (Int_t istat=4; istat>=3; istat--) {
80     
81     // Make segments in the station
82     segments = MakeSegmentsInStation(clusterStore, istat);
83     
84     // Loop over segments
85     for (Int_t iseg=0; iseg<segments->GetEntriesFast(); iseg++) {
86       AliDebug(1,Form("Making primary candidate(1..) %d",++iCandidate));
87       
88       // Transform segments to tracks and put them at the end of fRecTracksPtr
89       track = new ((*fRecTracksPtr)[fRecTracksPtr->GetLast()+1]) AliMUONTrack((AliMUONObjectPair*)((*segments)[iseg]));
90       fNRecTracks++;
91       
92       // Printout for debuging
93       if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 2) || (AliLog::GetGlobalDebugLevel() >= 2)) {
94         cout<<endl<<"Track parameter covariances at first cluster:"<<endl;
95         ((AliMUONTrackParam*) (track->GetTrackParamAtCluster()->First()))->GetCovariances().Print();
96       }
97       
98       // Look for compatible cluster(s) in the other station
99       if (AliMUONReconstructor::GetRecoParam()->MakeTrackCandidatesFast())
100         clusterFound = FollowLinearTrackInStation(*track, clusterStore, 7-istat);
101       else {
102         // First recompute track parameters and covariances on station(1..) 5 using Kalman filter
103         // (to make sure all tracks are treated in the same way)
104         if (istat == 4) RetraceTrack(*track, kFALSE);
105         clusterFound = FollowTrackInStation(*track, clusterStore, 7-istat);
106       }
107       
108       // Remove track if no cluster found
109       if (!clusterFound) {
110         fRecTracksPtr->Remove(track);
111         fNRecTracks--;
112       }
113       
114     }
115     // delete the array of segments
116     delete segments;
117   }
118   
119   
120   // Retrace tracks using Kalman filter and remove bad ones
121   if (AliMUONReconstructor::GetRecoParam()->MakeTrackCandidatesFast()) {
122     fRecTracksPtr->Compress(); // this is essential before checking tracks
123     
124     Int_t currentNRecTracks = fNRecTracks;
125     for (Int_t iRecTrack = 0; iRecTrack < currentNRecTracks; iRecTrack++) {
126       track = (AliMUONTrack*) fRecTracksPtr->UncheckedAt(iRecTrack);
127       
128       // Recompute track parameters and covariances using Kalman filter
129       RetraceTrack(*track,kTRUE);
130       
131       // Remove the track if the normalized chi2 is too high
132       if (track->GetNormalizedChi2() > AliMUONReconstructor::GetRecoParam()->GetSigmaCutForTracking() *
133                                        AliMUONReconstructor::GetRecoParam()->GetSigmaCutForTracking()) {
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 (AliMUONReconstructor::GetRecoParam()->TrackAllTracks()) 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 cluster to the most uptream one
156   AliDebug(1,"Enter RetraceTrack");
157   
158   AliMUONTrackParam* startingTrackParam = (AliMUONTrackParam*) trackCandidate.GetTrackParamAtCluster()->Last();
159   
160   // Reset the "seed" (= track parameters and their covariances at last cluster) if required
161   if (resetSeed) {
162     // => Shift track parameters at the position of the last cluster
163     AliMUONVCluster* cluster = startingTrackParam->GetClusterPtr();
164     startingTrackParam->SetNonBendingCoor(cluster->GetX());
165     startingTrackParam->SetBendingCoor(cluster->GetY());
166     
167     // => Re-compute and reset track parameters covariances at last cluster (as if the other clusters 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) = cluster->GetErrX2();
173     newParamCov(1,1) = 100.*kParamCov(1,1);
174     // Bending plane
175     newParamCov(2,2) = cluster->GetErrY2();
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 cluster attached to startingTrackParam to the most uptream cluster
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.GetGlobalChi2() << endl;
200   }
201   
202   // Reset the track chi2
203   trackCandidate.SetGlobalChi2(startingTrackParam->GetTrackChi2());
204   
205   // loop over attached clusters until the first one and recompute track parameters and covariances using kalman filter
206   Int_t expectedChamber = startingTrackParam->GetClusterPtr()->GetChamberId() - 1;
207   Int_t currentChamber;
208   Double_t addChi2TrackAtCluster;
209   AliMUONTrackParam* trackParamAtCluster = (AliMUONTrackParam*) trackCandidate.GetTrackParamAtCluster()->Before(startingTrackParam); 
210   while (trackParamAtCluster) {
211     
212     // reset track parameters and their covariances
213     trackParamAtCluster->SetParameters(startingTrackParam->GetParameters());
214     trackParamAtCluster->SetZ(startingTrackParam->GetZ());
215     trackParamAtCluster->SetCovariances(startingTrackParam->GetCovariances());
216     
217     // add MCS effect
218     AliMUONTrackExtrap::AddMCSEffect(trackParamAtCluster,AliMUONConstants::ChamberThicknessInX0(),1.);
219     
220     // reset propagator for smoother
221     if (AliMUONReconstructor::GetRecoParam()->UseSmoother()) trackParamAtCluster->ResetPropagator();
222     
223     // add MCS in missing chambers if any (at most 2 chambers can be missing according to tracking criteria)
224     currentChamber = trackParamAtCluster->GetClusterPtr()->GetChamberId();
225     while (currentChamber < expectedChamber) {
226       // extrapolation to the missing chamber (update the propagator)
227       AliMUONTrackExtrap::ExtrapToZCov(trackParamAtCluster, AliMUONConstants::DefaultChamberZ(expectedChamber),
228                                        AliMUONReconstructor::GetRecoParam()->UseSmoother());
229       // add MCS effect
230       AliMUONTrackExtrap::AddMCSEffect(trackParamAtCluster,AliMUONConstants::ChamberThicknessInX0(),1.);
231       expectedChamber--;
232     }
233     
234     // extrapolation to the plane of the cluster attached to the current trackParamAtCluster (update the propagator)
235     AliMUONTrackExtrap::ExtrapToZCov(trackParamAtCluster, trackParamAtCluster->GetClusterPtr()->GetZ(),
236                                      AliMUONReconstructor::GetRecoParam()->UseSmoother());
237     
238     if (AliMUONReconstructor::GetRecoParam()->UseSmoother()) {
239       // save extrapolated parameters for smoother
240       trackParamAtCluster->SetExtrapParameters(trackParamAtCluster->GetParameters());
241       
242       // save extrapolated covariance matrix for smoother
243       trackParamAtCluster->SetExtrapCovariances(trackParamAtCluster->GetCovariances());
244     }
245     
246     // Compute new track parameters including "clusterCh2" using kalman filter
247     addChi2TrackAtCluster = RunKalmanFilter(*trackParamAtCluster);
248     
249     // Update the track chi2
250     trackCandidate.SetGlobalChi2(trackCandidate.GetGlobalChi2() + addChi2TrackAtCluster);
251     trackParamAtCluster->SetTrackChi2(trackCandidate.GetGlobalChi2());
252     
253     // prepare next step
254     expectedChamber = currentChamber - 1;
255     startingTrackParam = trackParamAtCluster;
256     trackParamAtCluster = (AliMUONTrackParam*) (trackCandidate.GetTrackParamAtCluster()->Before(startingTrackParam)); 
257   }
258   
259   // Printout for debuging
260   if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
261     cout << "RetracePartialTrack: track chi2 after re-tracking: " << trackCandidate.GetGlobalChi2() << endl;
262   }
263   
264 }
265
266   //__________________________________________________________________________
267 void AliMUONTrackReconstructorK::FollowTracks(const AliMUONVClusterStore& clusterStore)
268 {
269   /// Follow tracks in stations(1..) 3, 2 and 1
270   AliDebug(1,"Enter FollowTracks");
271   
272   AliMUONTrack *track;
273   Int_t currentNRecTracks;
274   Bool_t clusterFound;
275   
276   for (Int_t station = 2; station >= 0; station--) {
277     
278     // Save the actual number of reconstructed track in case of
279     // tracks are added or suppressed during the tracking procedure
280     // !! Do not compress fRecTracksPtr until the end of the loop over tracks !!
281     currentNRecTracks = fNRecTracks;
282     
283     for (Int_t iRecTrack = 0; iRecTrack <currentNRecTracks; iRecTrack++) {
284       AliDebug(1,Form("FollowTracks: track candidate(1..) %d", iRecTrack+1));
285       
286       track = (AliMUONTrack*) fRecTracksPtr->UncheckedAt(iRecTrack);
287       
288       // Printout for debuging
289       if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 2) || (AliLog::GetGlobalDebugLevel() >= 2)) {
290         cout<<endl<<"Track parameter covariances at first cluster:"<<endl;
291         ((AliMUONTrackParam*) (track->GetTrackParamAtCluster()->First()))->GetCovariances().Print();
292       }
293       
294       // Look for compatible cluster(s) in station(0..) "station"
295       clusterFound = FollowTrackInStation(*track, clusterStore, station);
296       
297       // Try to recover track if required
298       if (!clusterFound && AliMUONReconstructor::GetRecoParam()->RecoverTracks())
299         clusterFound = RecoverTrack(*track, clusterStore, station);
300       
301       // remove track if no cluster found
302       if (!clusterFound) {
303         fRecTracksPtr->Remove(track);
304         fNRecTracks--;
305       }
306       
307     }
308     
309     fRecTracksPtr->Compress(); // this is essential before checking tracks
310     
311     // Keep only the best tracks if required
312     if (!AliMUONReconstructor::GetRecoParam()->TrackAllTracks()) RemoveDoubleTracks();
313     
314   }
315   
316 }
317
318   //__________________________________________________________________________
319 Bool_t AliMUONTrackReconstructorK::FollowTrackInStation(AliMUONTrack &trackCandidate, const AliMUONVClusterStore& clusterStore, Int_t nextStation)
320 {
321   /// Follow trackCandidate in station(0..) nextStation and search for compatible cluster(s)
322   /// Keep all possibilities or only the best one(s) according to the flag fgkTrackAllTracks:
323   /// kTRUE:  duplicate "trackCandidate" if there are several possibilities and add the new tracks at the end of
324   ///         fRecTracksPtr to avoid conficts with other track candidates at this current stage of the tracking procedure.
325   ///         Remove the obsolete "trackCandidate" at the end.
326   /// kFALSE: add only the best cluster(s) to the "trackCandidate". Try to add a couple of clusters in priority.
327   /// return kTRUE if new cluster(s) have been found (otherwise return kFALSE)
328   AliDebug(1,Form("Enter FollowTrackInStation(1..) %d", nextStation+1));
329   
330   // Order the chamber according to the propagation direction (tracking starts with chamber 2):
331   // - nextStation == station(1...) 5 => forward propagation
332   // - nextStation < station(1...) 5 => backward propagation
333   Int_t ch1, ch2;
334   if (nextStation==4) {
335     ch1 = 2*nextStation+1;
336     ch2 = 2*nextStation;
337   } else {
338     ch1 = 2*nextStation;
339     ch2 = 2*nextStation+1;
340   }
341   
342   Double_t chi2OfCluster;
343   Double_t maxChi2OfCluster = 2. * AliMUONReconstructor::GetRecoParam()->GetSigmaCutForTracking() *
344                                    AliMUONReconstructor::GetRecoParam()->GetSigmaCutForTracking(); // 2 because 2 quantities in chi2
345   Double_t addChi2TrackAtCluster1;
346   Double_t addChi2TrackAtCluster2;
347   Double_t bestAddChi2TrackAtCluster1 = 1.e10;
348   Double_t bestAddChi2TrackAtCluster2 = 1.e10;
349   Bool_t foundOneCluster = kFALSE;
350   Bool_t foundTwoClusters = kFALSE;
351   AliMUONTrack *newTrack = 0x0;
352   AliMUONVCluster *clusterCh1, *clusterCh2;
353   AliMUONTrackParam extrapTrackParam;
354   AliMUONTrackParam extrapTrackParamAtCluster1;
355   AliMUONTrackParam extrapTrackParamAtCluster2;
356   AliMUONTrackParam bestTrackParamAtCluster1;
357   AliMUONTrackParam bestTrackParamAtCluster2;
358   
359   Int_t nClusters = clusterStore.GetSize();
360   Bool_t *clusterCh1Used = new Bool_t[nClusters];
361   for (Int_t i = 0; i < nClusters; i++) clusterCh1Used[i] = kFALSE;
362   Int_t iCluster1;
363   
364   // Get track parameters
365   AliMUONTrackParam extrapTrackParamAtCh(*(AliMUONTrackParam*)trackCandidate.GetTrackParamAtCluster()->First());
366   
367   // Add MCS effect
368   AliMUONTrackExtrap::AddMCSEffect(&extrapTrackParamAtCh,AliMUONConstants::ChamberThicknessInX0(),1.);
369   
370   // reset propagator for smoother
371   if (AliMUONReconstructor::GetRecoParam()->UseSmoother()) extrapTrackParamAtCh.ResetPropagator();
372   
373   // Add MCS in the missing chamber if any (only 1 chamber can be missing according to tracking criteria)
374   if (ch1 < ch2 && extrapTrackParamAtCh.GetClusterPtr()->GetChamberId() > ch2 + 1) {
375     // extrapolation to the missing chamber
376     AliMUONTrackExtrap::ExtrapToZCov(&extrapTrackParamAtCh, AliMUONConstants::DefaultChamberZ(ch2 + 1),
377                                      AliMUONReconstructor::GetRecoParam()->UseSmoother());
378     // add MCS effect
379     AliMUONTrackExtrap::AddMCSEffect(&extrapTrackParamAtCh,AliMUONConstants::ChamberThicknessInX0(),1.);
380   }
381   
382   //Extrapolate trackCandidate to chamber "ch2"
383   AliMUONTrackExtrap::ExtrapToZCov(&extrapTrackParamAtCh, AliMUONConstants::DefaultChamberZ(ch2),
384                                    AliMUONReconstructor::GetRecoParam()->UseSmoother());
385   
386   // Printout for debuging
387   if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 2) || (AliLog::GetGlobalDebugLevel() >= 2)) {
388     cout<<endl<<"Track parameter covariances at first cluster extrapolated to z = "<<AliMUONConstants::DefaultChamberZ(ch2)<<":"<<endl;
389     extrapTrackParamAtCh.GetCovariances().Print();
390   }
391   
392   // Printout for debuging
393   if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
394     cout << "FollowTrackInStation: look for clusters in chamber(1..): " << ch2+1 << endl;
395   }
396   
397   // Create iterators to loop over clusters in both chambers
398   TIter nextInCh1(clusterStore.CreateChamberIterator(ch1,ch1));
399   TIter nextInCh2(clusterStore.CreateChamberIterator(ch2,ch2));
400   
401   // look for candidates in chamber 2
402   while ( ( clusterCh2 = static_cast<AliMUONVCluster*>(nextInCh2()) ) ) {
403     
404     // try to add the current cluster fast
405     if (!TryOneClusterFast(extrapTrackParamAtCh, clusterCh2)) continue;
406     
407     // try to add the current cluster accuratly
408     chi2OfCluster = TryOneCluster(extrapTrackParamAtCh, clusterCh2, extrapTrackParamAtCluster2,
409                                   AliMUONReconstructor::GetRecoParam()->UseSmoother());
410     
411     // if good chi2 then try to attach a cluster in the other chamber too
412     if (chi2OfCluster < maxChi2OfCluster) {
413       Bool_t foundSecondCluster = kFALSE;
414       
415       // Printout for debuging
416       if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
417         cout << "FollowTrackInStation: found one cluster in chamber(1..): " << ch2+1
418              << " (Chi2 = " << chi2OfCluster << ")" << endl;
419         cout << "                      look for second clusters in chamber(1..): " << ch1+1 << " ..." << endl;
420       }
421       
422       if (AliMUONReconstructor::GetRecoParam()->UseSmoother()) {
423         // save extrapolated parameters for smoother
424         extrapTrackParamAtCluster2.SetExtrapParameters(extrapTrackParamAtCluster2.GetParameters());
425         
426         // save extrapolated covariance matrix for smoother
427         extrapTrackParamAtCluster2.SetExtrapCovariances(extrapTrackParamAtCluster2.GetCovariances());
428       }
429       
430       // Compute new track parameters including "clusterCh2" using kalman filter
431       addChi2TrackAtCluster2 = RunKalmanFilter(extrapTrackParamAtCluster2);
432       
433       // copy new track parameters for next step
434       extrapTrackParam = extrapTrackParamAtCluster2;
435       
436       // add MCS effect
437       AliMUONTrackExtrap::AddMCSEffect(&extrapTrackParam,AliMUONConstants::ChamberThicknessInX0(),1.);
438       
439       // reset propagator for smoother
440       if (AliMUONReconstructor::GetRecoParam()->UseSmoother()) extrapTrackParam.ResetPropagator();
441       
442       //Extrapolate track parameters to chamber "ch1"
443       AliMUONTrackExtrap::ExtrapToZCov(&extrapTrackParam, AliMUONConstants::DefaultChamberZ(ch1),
444                                        AliMUONReconstructor::GetRecoParam()->UseSmoother());
445       
446       // reset cluster iterator of chamber 1
447       nextInCh1.Reset();
448       iCluster1 = -1;
449       
450       // look for second candidates in chamber 1
451       while ( ( clusterCh1 = static_cast<AliMUONVCluster*>(nextInCh1()) ) ) {
452         iCluster1++;
453         
454         // try to add the current cluster fast
455         if (!TryOneClusterFast(extrapTrackParam, clusterCh1)) continue;
456         
457         // try to add the current cluster accuratly
458         chi2OfCluster = TryOneCluster(extrapTrackParam, clusterCh1, extrapTrackParamAtCluster1,
459                                           AliMUONReconstructor::GetRecoParam()->UseSmoother());
460         
461         // if good chi2 then consider to add the 2 clusters to the "trackCandidate"
462         if (chi2OfCluster < maxChi2OfCluster) {
463           foundSecondCluster = kTRUE;
464           foundTwoClusters = kTRUE;
465           
466           // Printout for debuging
467           if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
468             cout << "FollowTrackInStation: found one cluster in chamber(1..): " << ch1+1
469                  << " (Chi2 = " << chi2OfCluster << ")" << endl;
470           }
471           
472           if (AliMUONReconstructor::GetRecoParam()->UseSmoother()) {
473             // save extrapolated parameters for smoother
474             extrapTrackParamAtCluster1.SetExtrapParameters(extrapTrackParamAtCluster1.GetParameters());
475             
476             // save extrapolated covariance matrix for smoother
477             extrapTrackParamAtCluster1.SetExtrapCovariances(extrapTrackParamAtCluster1.GetCovariances());
478           }
479           
480           // Compute new track parameters including "clusterCh1" using kalman filter
481           addChi2TrackAtCluster1 = RunKalmanFilter(extrapTrackParamAtCluster1);
482           
483           if (AliMUONReconstructor::GetRecoParam()->TrackAllTracks()) {
484             // copy trackCandidate into a new track put at the end of fRecTracksPtr and add the new clusters
485             newTrack = new ((*fRecTracksPtr)[fRecTracksPtr->GetLast()+1]) AliMUONTrack(trackCandidate);
486             UpdateTrack(*newTrack,extrapTrackParamAtCluster1,extrapTrackParamAtCluster2,addChi2TrackAtCluster1,addChi2TrackAtCluster2);
487             fNRecTracks++;
488             
489             // if we are arrived on station(1..) 5, recompute track parameters and covariances starting from this station
490             // (going in the right direction)
491             if (nextStation == 4) RetraceTrack(*newTrack,kTRUE);
492             
493             // Tag clusterCh1 as used
494             clusterCh1Used[iCluster1] = kTRUE;
495             
496             // Printout for debuging
497             if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
498               cout << "FollowTrackInStation: added two clusters in station(1..): " << nextStation+1 << endl;
499               if (AliLog::GetGlobalDebugLevel() >= 3) newTrack->RecursiveDump();
500             }
501             
502           } else if (addChi2TrackAtCluster1+addChi2TrackAtCluster2 < bestAddChi2TrackAtCluster1+bestAddChi2TrackAtCluster2) {
503             // keep track of the best couple of clusters
504             bestAddChi2TrackAtCluster1 = addChi2TrackAtCluster1;
505             bestAddChi2TrackAtCluster2 = addChi2TrackAtCluster2;
506             bestTrackParamAtCluster1 = extrapTrackParamAtCluster1;
507             bestTrackParamAtCluster2 = extrapTrackParamAtCluster2;
508           }
509           
510         }
511         
512       }
513       
514       // if no clusterCh1 found then consider to add clusterCh2 only
515       if (!foundSecondCluster) {
516         foundOneCluster = kTRUE;
517         
518         if (AliMUONReconstructor::GetRecoParam()->TrackAllTracks()) {
519           // copy trackCandidate into a new track put at the end of fRecTracksPtr and add the new cluster
520           newTrack = new ((*fRecTracksPtr)[fRecTracksPtr->GetLast()+1]) AliMUONTrack(trackCandidate);
521           UpdateTrack(*newTrack,extrapTrackParamAtCluster2,addChi2TrackAtCluster2);
522           fNRecTracks++;
523           
524           // if we are arrived on station(1..) 5, recompute track parameters and covariances starting from this station
525           // (going in the right direction)
526           if (nextStation == 4) RetraceTrack(*newTrack,kTRUE);
527           
528           // Printout for debuging
529           if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
530             cout << "FollowTrackInStation: added one cluster in chamber(1..): " << ch2+1 << endl;
531             if (AliLog::GetGlobalDebugLevel() >= 3) newTrack->RecursiveDump();
532           }
533           
534         } else if (!foundTwoClusters && addChi2TrackAtCluster2 < bestAddChi2TrackAtCluster1) {
535           // keep track of the best single cluster except if a couple of clusters has already been found
536           bestAddChi2TrackAtCluster1 = addChi2TrackAtCluster2;
537           bestTrackParamAtCluster1 = extrapTrackParamAtCluster2;
538         }
539         
540       }
541       
542     }
543     
544   }
545   
546   // look for candidates in chamber 1 not already attached to a track
547   // if we want to keep all possible tracks or if no good couple of clusters has been found
548   if (AliMUONReconstructor::GetRecoParam()->TrackAllTracks() || !foundTwoClusters) {
549     
550     // Printout for debuging
551     if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
552       cout << "FollowTrackInStation: look for single clusters in chamber(1..): " << ch1+1 << endl;
553     }
554     
555     // add MCS effect for next step
556     AliMUONTrackExtrap::AddMCSEffect(&extrapTrackParamAtCh,AliMUONConstants::ChamberThicknessInX0(),1.);
557     
558     //Extrapolate trackCandidate to chamber "ch1"
559     AliMUONTrackExtrap::ExtrapToZCov(&extrapTrackParamAtCh, AliMUONConstants::DefaultChamberZ(ch1),
560                                      AliMUONReconstructor::GetRecoParam()->UseSmoother());
561     
562     // reset cluster iterator of chamber 1
563     nextInCh1.Reset();
564     iCluster1 = -1;
565     
566     // look for second candidates in chamber 1
567     while ( ( clusterCh1 = static_cast<AliMUONVCluster*>(nextInCh1()) ) ) {
568       iCluster1++;
569       
570       if (clusterCh1Used[iCluster1]) continue; // Skip clusters already used
571       
572       // try to add the current cluster fast
573       if (!TryOneClusterFast(extrapTrackParamAtCh, clusterCh1)) continue;
574       
575       // try to add the current cluster accuratly
576       chi2OfCluster = TryOneCluster(extrapTrackParamAtCh, clusterCh1, extrapTrackParamAtCluster1,
577                                     AliMUONReconstructor::GetRecoParam()->UseSmoother());
578       
579       // if good chi2 then consider to add clusterCh1
580       // We do not try to attach a cluster in the other chamber too since it has already been done above
581       if (chi2OfCluster < maxChi2OfCluster) {
582         foundOneCluster = kTRUE;
583         
584         // Printout for debuging
585         if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
586           cout << "FollowTrackInStation: found one cluster in chamber(1..): " << ch1+1
587                << " (Chi2 = " << chi2OfCluster << ")" << endl;
588         }
589         
590         if (AliMUONReconstructor::GetRecoParam()->UseSmoother()) {
591           // save extrapolated parameters for smoother
592           extrapTrackParamAtCluster1.SetExtrapParameters(extrapTrackParamAtCluster1.GetParameters());
593           
594           // save extrapolated covariance matrix for smoother
595           extrapTrackParamAtCluster1.SetExtrapCovariances(extrapTrackParamAtCluster1.GetCovariances());
596         }
597         
598         // Compute new track parameters including "clusterCh1" using kalman filter
599         addChi2TrackAtCluster1 = RunKalmanFilter(extrapTrackParamAtCluster1);
600         
601         if (AliMUONReconstructor::GetRecoParam()->TrackAllTracks()) {
602           // copy trackCandidate into a new track put at the end of fRecTracksPtr and add the new cluster
603           newTrack = new ((*fRecTracksPtr)[fRecTracksPtr->GetLast()+1]) AliMUONTrack(trackCandidate);
604           UpdateTrack(*newTrack,extrapTrackParamAtCluster1,addChi2TrackAtCluster1);
605           fNRecTracks++;
606           
607           // if we are arrived on station(1..) 5, recompute track parameters and covariances starting from this station
608           // (going in the right direction)
609           if (nextStation == 4) RetraceTrack(*newTrack,kTRUE);
610           
611           // Printout for debuging
612           if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
613             cout << "FollowTrackInStation: added one cluster in chamber(1..): " << ch1+1 << endl;
614             if (AliLog::GetGlobalDebugLevel() >= 3) newTrack->RecursiveDump();
615           }
616           
617         } else if (addChi2TrackAtCluster1 < bestAddChi2TrackAtCluster1) {
618           // keep track of the best single cluster except if a couple of clusters has already been found
619           bestAddChi2TrackAtCluster1 = addChi2TrackAtCluster1;
620           bestTrackParamAtCluster1 = extrapTrackParamAtCluster1;
621         }
622         
623       }
624       
625     }
626     
627   }
628   
629   // fill out the best track if required else clean up the fRecTracksPtr array
630   if (!AliMUONReconstructor::GetRecoParam()->TrackAllTracks()) {
631     if (foundTwoClusters) {
632       UpdateTrack(trackCandidate,bestTrackParamAtCluster1,bestTrackParamAtCluster2,bestAddChi2TrackAtCluster1,bestAddChi2TrackAtCluster2);
633       
634       // if we are arrived on station(1..) 5, recompute track parameters and covariances starting from this station
635       // (going in the right direction)
636       if (nextStation == 4) RetraceTrack(trackCandidate,kTRUE);
637
638       // Printout for debuging
639       if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
640         cout << "FollowTrackInStation: added the two best clusters in station(1..): " << nextStation+1 << endl;
641         if (AliLog::GetGlobalDebugLevel() >= 3) newTrack->RecursiveDump();
642       }
643       
644     } else if (foundOneCluster) {
645       UpdateTrack(trackCandidate,bestTrackParamAtCluster1,bestAddChi2TrackAtCluster1);
646       
647       // if we are arrived on station(1..) 5, recompute track parameters and covariances starting from this station
648       // (going in the right direction)
649       if (nextStation == 4) RetraceTrack(trackCandidate,kTRUE);
650
651       // Printout for debuging
652       if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
653         cout << "FollowTrackInStation: added the best cluster in chamber(1..): " << bestTrackParamAtCluster1.GetClusterPtr()->GetChamberId()+1 << endl;
654         if (AliLog::GetGlobalDebugLevel() >= 3) newTrack->RecursiveDump();
655       }
656       
657     } else {
658       delete [] clusterCh1Used;
659       return kFALSE;
660     }
661   } else if (foundOneCluster || foundTwoClusters) {
662     
663     // remove obsolete track
664     fRecTracksPtr->Remove(&trackCandidate);
665     fNRecTracks--;
666     
667   } else {
668     delete [] clusterCh1Used;
669     return kFALSE;
670   }  
671   delete [] clusterCh1Used;
672   return kTRUE;
673   
674 }
675
676   //__________________________________________________________________________
677 Double_t AliMUONTrackReconstructorK::RunKalmanFilter(AliMUONTrackParam &trackParamAtCluster)
678 {
679   /// Compute new track parameters and their covariances including new cluster using kalman filter
680   /// return the additional track chi2
681   AliDebug(1,"Enter RunKalmanFilter");
682   
683   // Get actual track parameters (p)
684   TMatrixD param(trackParamAtCluster.GetParameters());
685   
686   // Get new cluster parameters (m)
687   AliMUONVCluster *cluster = trackParamAtCluster.GetClusterPtr();
688   TMatrixD clusterParam(5,1);
689   clusterParam.Zero();
690   clusterParam(0,0) = cluster->GetX();
691   clusterParam(2,0) = cluster->GetY();
692   
693   // Compute the actual parameter weight (W)
694   TMatrixD paramWeight(trackParamAtCluster.GetCovariances());
695   if (paramWeight.Determinant() != 0) {
696     paramWeight.Invert();
697   } else {
698     AliWarning(" Determinant = 0");
699     return 1.e10;
700   }
701   
702   // Compute the new cluster weight (U)
703   TMatrixD clusterWeight(5,5);
704   clusterWeight.Zero();
705   clusterWeight(0,0) = 1. / cluster->GetErrX2();
706   clusterWeight(2,2) = 1. / cluster->GetErrY2();
707
708   // Compute the new parameters covariance matrix ( (W+U)^-1 )
709   TMatrixD newParamCov(paramWeight,TMatrixD::kPlus,clusterWeight);
710   if (newParamCov.Determinant() != 0) {
711     newParamCov.Invert();
712   } else {
713     AliWarning(" Determinant = 0");
714     return 1.e10;
715   }
716   
717   // Save the new parameters covariance matrix
718   trackParamAtCluster.SetCovariances(newParamCov);
719   
720   // Compute the new parameters (p' = ((W+U)^-1)U(m-p) + p)
721   TMatrixD tmp(clusterParam,TMatrixD::kMinus,param);
722   TMatrixD tmp2(clusterWeight,TMatrixD::kMult,tmp); // U(m-p)
723   TMatrixD newParam(newParamCov,TMatrixD::kMult,tmp2); // ((W+U)^-1)U(m-p)
724   newParam += param; // ((W+U)^-1)U(m-p) + p
725   
726   // Save the new parameters
727   trackParamAtCluster.SetParameters(newParam);
728   
729   // Compute the additional chi2 (= ((p'-p)^-1)W(p'-p) + ((p'-m)^-1)U(p'-m))
730   tmp = newParam; // p'
731   tmp -= param; // (p'-p)
732   TMatrixD tmp3(paramWeight,TMatrixD::kMult,tmp); // W(p'-p)
733   TMatrixD addChi2Track(tmp,TMatrixD::kTransposeMult,tmp3); // ((p'-p)^-1)W(p'-p)
734   tmp = newParam; // p'
735   tmp -= clusterParam; // (p'-m)
736   TMatrixD tmp4(clusterWeight,TMatrixD::kMult,tmp); // U(p'-m)
737   addChi2Track += TMatrixD(tmp,TMatrixD::kTransposeMult,tmp4); // ((p'-p)^-1)W(p'-p) + ((p'-m)^-1)U(p'-m)
738   
739   return addChi2Track(0,0);
740   
741 }
742
743   //__________________________________________________________________________
744 void AliMUONTrackReconstructorK::UpdateTrack(AliMUONTrack &track, AliMUONTrackParam &trackParamAtCluster, Double_t addChi2)
745 {
746   /// Add 1 cluster to the track candidate
747   /// Update chi2 of the track 
748   
749   // Flag cluster as being not removable
750   trackParamAtCluster.SetRemovable(kFALSE);
751   trackParamAtCluster.SetLocalChi2(0.); // --> Local chi2 not used
752   
753   // Update the track chi2 into trackParamAtCluster
754   trackParamAtCluster.SetTrackChi2(track.GetGlobalChi2() + addChi2);
755   
756   // Update the chi2 of the new track
757   track.SetGlobalChi2(trackParamAtCluster.GetTrackChi2());
758   
759   // Update array of TrackParamAtCluster
760   track.AddTrackParamAtCluster(trackParamAtCluster,*(trackParamAtCluster.GetClusterPtr()));
761   track.GetTrackParamAtCluster()->Sort();
762   
763 }
764
765   //__________________________________________________________________________
766 void AliMUONTrackReconstructorK::UpdateTrack(AliMUONTrack &track, AliMUONTrackParam &trackParamAtCluster1, AliMUONTrackParam &trackParamAtCluster2,
767                                              Double_t addChi2AtCluster1, Double_t addChi2AtCluster2)
768 {
769   /// Add 2 clusters to the track candidate (order is important)
770   /// Update track and local chi2
771   
772   // Update local chi2 at first cluster
773   AliMUONVCluster* cluster1 = trackParamAtCluster1.GetClusterPtr();
774   Double_t deltaX = trackParamAtCluster1.GetNonBendingCoor() - cluster1->GetX();
775   Double_t deltaY = trackParamAtCluster1.GetBendingCoor() - cluster1->GetY();
776   Double_t localChi2AtCluster1 = deltaX*deltaX / cluster1->GetErrX2() +
777                                  deltaY*deltaY / cluster1->GetErrY2();
778   trackParamAtCluster1.SetLocalChi2(localChi2AtCluster1);
779   
780   // Flag first cluster as being removable
781   trackParamAtCluster1.SetRemovable(kTRUE);
782   
783   // Update local chi2 at second cluster
784   AliMUONVCluster* cluster2 = trackParamAtCluster2.GetClusterPtr();
785   AliMUONTrackParam extrapTrackParamAtCluster2(trackParamAtCluster1);
786   AliMUONTrackExtrap::ExtrapToZ(&extrapTrackParamAtCluster2, trackParamAtCluster2.GetZ());
787   deltaX = extrapTrackParamAtCluster2.GetNonBendingCoor() - cluster2->GetX();
788   deltaY = extrapTrackParamAtCluster2.GetBendingCoor() - cluster2->GetY();
789   Double_t localChi2AtCluster2 = deltaX*deltaX / cluster2->GetErrX2() +
790                                  deltaY*deltaY / cluster2->GetErrY2();
791   trackParamAtCluster2.SetLocalChi2(localChi2AtCluster2);
792   
793   // Flag second cluster as being removable
794   trackParamAtCluster2.SetRemovable(kTRUE);
795   
796   // Update the track chi2 into trackParamAtCluster2
797   trackParamAtCluster2.SetTrackChi2(track.GetGlobalChi2() + addChi2AtCluster2);
798   
799   // Update the track chi2 into trackParamAtCluster1
800   trackParamAtCluster1.SetTrackChi2(trackParamAtCluster2.GetTrackChi2() + addChi2AtCluster1);
801   
802   // Update the chi2 of the new track
803   track.SetGlobalChi2(trackParamAtCluster1.GetTrackChi2());
804   
805   // Update array of trackParamAtCluster
806   track.AddTrackParamAtCluster(trackParamAtCluster1,*cluster1);
807   track.AddTrackParamAtCluster(trackParamAtCluster2,*cluster2);
808   track.GetTrackParamAtCluster()->Sort();
809   
810 }
811
812   //__________________________________________________________________________
813 Bool_t AliMUONTrackReconstructorK::RecoverTrack(AliMUONTrack &trackCandidate, const AliMUONVClusterStore& clusterStore, Int_t nextStation)
814 {
815   /// Try to recover the track candidate in the next station
816   /// by removing the worst of the two clusters attached in the current station
817   /// Return kTRUE if recovering succeeds
818   AliDebug(1,"Enter RecoverTrack");
819   
820   // Do not try to recover track until we have attached cluster(s) on station(1..) 3
821   if (nextStation > 1) return kFALSE;
822   
823   Int_t worstClusterNumber = -1;
824   Double_t localChi2, worstLocalChi2 = 0.;
825   
826   // Look for the cluster to remove
827   for (Int_t clusterNumber = 0; clusterNumber < 2; clusterNumber++) {
828     AliMUONTrackParam *trackParamAtCluster = (AliMUONTrackParam*)trackCandidate.GetTrackParamAtCluster()->UncheckedAt(clusterNumber);
829     
830     // check if current cluster is removable
831     if (!trackParamAtCluster->IsRemovable()) return kFALSE;
832     
833     // Pick up cluster with the worst chi2
834     localChi2 = trackParamAtCluster->GetLocalChi2();
835     if (localChi2 > worstLocalChi2) {
836       worstLocalChi2 = localChi2;
837       worstClusterNumber = clusterNumber;
838     }
839   }
840   
841   // Reset best cluster as being NOT removable
842   ((AliMUONTrackParam*)trackCandidate.GetTrackParamAtCluster()->UncheckedAt((worstClusterNumber+1)%2))->SetRemovable(kFALSE);
843   
844   // Remove the worst cluster
845   trackCandidate.RemoveTrackParamAtCluster((AliMUONTrackParam*)trackCandidate.GetTrackParamAtCluster()->UncheckedAt(worstClusterNumber));
846   
847   // Re-calculate track parameters at the (new) first cluster
848   RetracePartialTrack(trackCandidate,(AliMUONTrackParam*)trackCandidate.GetTrackParamAtCluster()->UncheckedAt(1));
849   
850   // Look for new cluster(s) in next station
851   return FollowTrackInStation(trackCandidate, clusterStore, nextStation);
852   
853 }
854
855   //__________________________________________________________________________
856 Bool_t AliMUONTrackReconstructorK::RunSmoother(AliMUONTrack &track)
857 {
858   /// Compute new track parameters and their covariances using smoother
859   AliDebug(1,"Enter UseSmoother");
860   
861   AliMUONTrackParam *previousTrackParam = (AliMUONTrackParam*) track.GetTrackParamAtCluster()->First();
862   
863   // Smoothed parameters and covariances at first cluster = filtered parameters and covariances
864   previousTrackParam->SetSmoothParameters(previousTrackParam->GetParameters());
865   previousTrackParam->SetSmoothCovariances(previousTrackParam->GetCovariances());
866   
867   // Compute local chi2 at first cluster
868   AliMUONVCluster *cluster = previousTrackParam->GetClusterPtr();
869   Double_t dX = cluster->GetX() - previousTrackParam->GetNonBendingCoor();
870   Double_t dY = cluster->GetY() - previousTrackParam->GetBendingCoor();
871   Double_t localChi2 = dX * dX / cluster->GetErrX2() + dY * dY / cluster->GetErrY2();
872   
873   // Save local chi2 at first cluster
874   previousTrackParam->SetLocalChi2(localChi2);
875   
876   AliMUONTrackParam *currentTrackParam = (AliMUONTrackParam*) track.GetTrackParamAtCluster()->After(previousTrackParam);
877   while (currentTrackParam) {
878     
879     // Get variables
880     const TMatrixD &extrapParameters          = previousTrackParam->GetExtrapParameters();  // X(k+1 k)
881     const TMatrixD &filteredParameters        = currentTrackParam->GetParameters();         // X(k k)
882     const TMatrixD &previousSmoothParameters  = previousTrackParam->GetSmoothParameters();  // X(k+1 n)
883     const TMatrixD &propagator                = previousTrackParam->GetPropagator();        // F(k)
884     const TMatrixD &extrapCovariances         = previousTrackParam->GetExtrapCovariances(); // C(k+1 k)
885     const TMatrixD &filteredCovariances       = currentTrackParam->GetCovariances();        // C(k k)
886     const TMatrixD &previousSmoothCovariances = previousTrackParam->GetSmoothCovariances(); // C(k+1 n)
887     
888     // Compute smoother gain: A(k) = C(kk) * F(f)^t * (C(k+1 k))^-1
889     TMatrixD extrapWeight(extrapCovariances);
890     if (extrapWeight.Determinant() != 0) {
891       extrapWeight.Invert(); // (C(k+1 k))^-1
892     } else {
893       AliWarning(" Determinant = 0");
894       return kFALSE;
895     }
896     TMatrixD smootherGain(filteredCovariances,TMatrixD::kMultTranspose,propagator); // C(kk) * F(f)^t
897     smootherGain *= extrapWeight; // C(kk) * F(f)^t * (C(k+1 k))^-1
898     
899     // Compute smoothed parameters: X(k n) = X(k k) + A(k) * (X(k+1 n) - X(k+1 k))
900     TMatrixD tmpParam(previousSmoothParameters,TMatrixD::kMinus,extrapParameters); // X(k+1 n) - X(k+1 k)
901     TMatrixD smoothParameters(smootherGain,TMatrixD::kMult,tmpParam); // A(k) * (X(k+1 n) - X(k+1 k))
902     smoothParameters += filteredParameters; // X(k k) + A(k) * (X(k+1 n) - X(k+1 k))
903     
904     // Save smoothed parameters
905     currentTrackParam->SetSmoothParameters(smoothParameters);
906     
907     // Compute smoothed covariances: C(k n) = C(k k) + A(k) * (C(k+1 n) - C(k+1 k)) * (A(k))^t
908     TMatrixD tmpCov(previousSmoothCovariances,TMatrixD::kMinus,extrapCovariances); // C(k+1 n) - C(k+1 k)
909     TMatrixD tmpCov2(tmpCov,TMatrixD::kMultTranspose,smootherGain); // (C(k+1 n) - C(k+1 k)) * (A(k))^t
910     TMatrixD smoothCovariances(smootherGain,TMatrixD::kMult,tmpCov2); // A(k) * (C(k+1 n) - C(k+1 k)) * (A(k))^t
911     smoothCovariances += filteredCovariances; // C(k k) + A(k) * (C(k+1 n) - C(k+1 k)) * (A(k))^t
912     
913     // Save smoothed covariances
914     currentTrackParam->SetSmoothCovariances(smoothCovariances);
915     
916     // Compute smoothed residual: r(k n) = cluster - X(k n)
917     cluster = currentTrackParam->GetClusterPtr();
918     TMatrixD smoothResidual(2,1);
919     smoothResidual.Zero();
920     smoothResidual(0,0) = cluster->GetX() - smoothParameters(0,0);
921     smoothResidual(1,0) = cluster->GetY() - smoothParameters(2,0);
922     
923     // Compute weight of smoothed residual: W(k n) = (clusterCov - C(k n))^-1
924     TMatrixD smoothResidualWeight(2,2);
925     smoothResidualWeight(0,0) = cluster->GetErrX2() - smoothCovariances(0,0);
926     smoothResidualWeight(0,1) = - smoothCovariances(0,2);
927     smoothResidualWeight(1,0) = - smoothCovariances(2,0);
928     smoothResidualWeight(1,1) = cluster->GetErrY2() - smoothCovariances(2,2);
929     if (smoothResidualWeight.Determinant() != 0) {
930       smoothResidualWeight.Invert();
931     } else {
932       AliWarning(" Determinant = 0");
933       return kFALSE;
934     }
935     
936     // Compute local chi2 = (r(k n))^t * W(k n) * r(k n)
937     TMatrixD tmpChi2(smoothResidual,TMatrixD::kTransposeMult,smoothResidualWeight); // (r(k n))^t * W(k n)
938     TMatrixD localChi2(tmpChi2,TMatrixD::kMult,smoothResidual); // (r(k n))^t * W(k n) * r(k n)
939     
940     // Save local chi2
941     currentTrackParam->SetLocalChi2(localChi2(0,0));
942     
943     previousTrackParam = currentTrackParam;
944     currentTrackParam = (AliMUONTrackParam*) track.GetTrackParamAtCluster()->After(previousTrackParam);
945   }
946   
947   return kTRUE;
948   
949 }
950
951   //__________________________________________________________________________
952 void AliMUONTrackReconstructorK::ComplementTracks(const AliMUONVClusterStore& clusterStore)
953 {
954   /// Complete tracks by adding missing clusters (if there is an overlap between
955   /// two detection elements, the track may have two clusters in the same chamber)
956   /// Recompute track parameters and covariances at each clusters
957   AliDebug(1,"Enter ComplementTracks");
958   
959   Int_t chamberId, detElemId;
960   Double_t chi2OfCluster, addChi2TrackAtCluster, bestAddChi2TrackAtCluster;
961   Double_t maxChi2OfCluster = 2. * AliMUONReconstructor::GetRecoParam()->GetSigmaCutForTracking() *
962                                    AliMUONReconstructor::GetRecoParam()->GetSigmaCutForTracking(); // 2 because 2 quantities in chi2
963   Bool_t foundOneCluster, trackModified;
964   AliMUONVCluster *cluster;
965   AliMUONTrackParam *trackParam, *previousTrackParam, *nextTrackParam, trackParamAtCluster, bestTrackParamAtCluster;
966   
967   // Remove double track to complete only "good" tracks
968   RemoveDoubleTracks();
969   
970   AliMUONTrack *track = (AliMUONTrack*) fRecTracksPtr->First();
971   while (track) {
972     trackModified = kFALSE;
973     
974     trackParam = (AliMUONTrackParam*)track->GetTrackParamAtCluster()->First();
975     previousTrackParam = trackParam;
976     while (trackParam) {
977       foundOneCluster = kFALSE;
978       bestAddChi2TrackAtCluster = 1.e10;
979       chamberId = trackParam->GetClusterPtr()->GetChamberId();
980       detElemId = trackParam->GetClusterPtr()->GetDetElemId();
981       
982       // prepare nextTrackParam before adding new cluster because of the sorting
983       nextTrackParam = (AliMUONTrackParam*)track->GetTrackParamAtCluster()->After(trackParam);
984       
985       // Create iterators to loop over clusters in current chamber
986       TIter nextInCh(clusterStore.CreateChamberIterator(chamberId,chamberId));
987       
988       // look for one second candidate in the same chamber
989       while ( ( cluster = static_cast<AliMUONVCluster*>(nextInCh()) ) ) {
990         
991         // look for a cluster in another detection element
992         if (cluster->GetDetElemId() == detElemId) continue;
993         
994         // try to add the current cluster fast
995         if (!TryOneClusterFast(*trackParam, cluster)) continue;
996         
997         // try to add the current cluster accurately
998         // never use track parameters at last cluster because the covariance matrix is meaningless
999         if (nextTrackParam) chi2OfCluster = TryOneCluster(*trackParam, cluster, trackParamAtCluster);
1000         else chi2OfCluster = TryOneCluster(*previousTrackParam, cluster, trackParamAtCluster);
1001         
1002         // if good chi2 then consider to add this cluster to the track
1003         if (chi2OfCluster < maxChi2OfCluster) {
1004           
1005           // Compute local track parameters including current cluster using kalman filter
1006           addChi2TrackAtCluster = RunKalmanFilter(trackParamAtCluster);
1007           
1008           // keep track of the best cluster
1009           if (addChi2TrackAtCluster < bestAddChi2TrackAtCluster) {
1010             bestAddChi2TrackAtCluster = addChi2TrackAtCluster;
1011             bestTrackParamAtCluster = trackParamAtCluster;
1012             foundOneCluster = kTRUE;
1013           }
1014           
1015         }
1016         
1017       }
1018       
1019       // add new cluster if any
1020       if (foundOneCluster) {
1021         UpdateTrack(*track,bestTrackParamAtCluster,bestAddChi2TrackAtCluster);
1022         bestTrackParamAtCluster.SetAloneInChamber(kFALSE);
1023         trackParam->SetAloneInChamber(kFALSE);
1024         trackModified = kTRUE;
1025       }
1026       
1027       previousTrackParam = trackParam;
1028       trackParam = nextTrackParam;
1029     }
1030     
1031     // re-compute track parameters using kalman filter if needed
1032     if (trackModified) RetraceTrack(*track,kTRUE);
1033     
1034     track = (AliMUONTrack*) fRecTracksPtr->After(track);
1035   }
1036   
1037 }
1038
1039 //__________________________________________________________________________
1040 void AliMUONTrackReconstructorK::ImproveTracks()
1041 {
1042   /// Improve tracks by removing clusters with local chi2 highter than the defined cut
1043   /// Recompute track parameters and covariances at the remaining clusters
1044   AliDebug(1,"Enter ImproveTracks");
1045   
1046   Double_t localChi2, worstLocalChi2;
1047   Int_t worstChamber, previousChamber;
1048   AliMUONTrack *track, *nextTrack;
1049   AliMUONTrackParam *trackParamAtCluster, *worstTrackParamAtCluster, *previousTrackParam, *nextTrackParam;
1050   Bool_t smoothed;
1051   Double_t sigmaCut2 = AliMUONReconstructor::GetRecoParam()->GetSigmaCutForImprovement() *
1052                        AliMUONReconstructor::GetRecoParam()->GetSigmaCutForImprovement();
1053   
1054   // Remove double track to improve only "good" tracks
1055   RemoveDoubleTracks();
1056   
1057   track = (AliMUONTrack*) fRecTracksPtr->First();
1058   while (track) {
1059     
1060     // prepare next track in case the actual track is suppressed
1061     nextTrack = (AliMUONTrack*) fRecTracksPtr->After(track);
1062     
1063     while (!track->IsImproved()) {
1064       
1065       // Run smoother if required
1066       smoothed = kFALSE;
1067       if (AliMUONReconstructor::GetRecoParam()->UseSmoother()) smoothed = RunSmoother(*track);
1068       
1069       // Use standard procedure to compute local chi2 if smoother not required or not working
1070       if (!smoothed) {
1071         
1072         // Update track parameters and covariances
1073         track->UpdateCovTrackParamAtCluster();
1074         
1075         // Compute local chi2 of each clusters
1076         track->ComputeLocalChi2(kTRUE);
1077       }
1078       
1079       // Look for the cluster to remove
1080       worstTrackParamAtCluster = NULL;
1081       worstLocalChi2 = 0.;
1082       trackParamAtCluster = (AliMUONTrackParam*)track->GetTrackParamAtCluster()->First();
1083       while (trackParamAtCluster) {
1084         
1085         // Pick up cluster with the worst chi2
1086         localChi2 = trackParamAtCluster->GetLocalChi2();
1087         if (localChi2 > worstLocalChi2) {
1088           worstLocalChi2 = localChi2;
1089           worstTrackParamAtCluster = trackParamAtCluster;
1090         }
1091         
1092         trackParamAtCluster = (AliMUONTrackParam*)track->GetTrackParamAtCluster()->After(trackParamAtCluster);
1093       }
1094       
1095       // Check if bad removable cluster found
1096       if (!worstTrackParamAtCluster) {
1097         track->SetImproved(kTRUE);
1098         break;
1099       }
1100       
1101       // Check whether the worst chi2 is under requirement or not
1102       if (worstLocalChi2 < 2. * sigmaCut2) { // 2 because 2 quantities in chi2
1103         track->SetImproved(kTRUE);
1104         break;
1105       }
1106       
1107       // if the worst cluster is not removable then remove the entire track
1108       if (!worstTrackParamAtCluster->IsRemovable() && worstTrackParamAtCluster->IsAloneInChamber()) {
1109         fRecTracksPtr->Remove(track);
1110         fNRecTracks--;
1111         break;
1112       }
1113       
1114       // Reset the second cluster in the same station as being not removable
1115       // or reset the second cluster in the same chamber as being alone
1116       worstChamber = worstTrackParamAtCluster->GetClusterPtr()->GetChamberId();
1117       previousTrackParam = (AliMUONTrackParam*) track->GetTrackParamAtCluster()->Before(worstTrackParamAtCluster);
1118       nextTrackParam = (AliMUONTrackParam*) track->GetTrackParamAtCluster()->After(worstTrackParamAtCluster);
1119       if (worstTrackParamAtCluster->IsAloneInChamber()) { // Worst cluster removable and alone in chamber
1120         
1121         if (worstChamber%2 == 0) { // Modify flags in next chamber
1122           
1123           nextTrackParam->SetRemovable(kFALSE);
1124           if (!nextTrackParam->IsAloneInChamber()) // Make sure both clusters in second chamber are not removable anymore
1125             ((AliMUONTrackParam*) track->GetTrackParamAtCluster()->After(nextTrackParam))->SetRemovable(kFALSE);
1126           
1127         } else { // Modify flags in previous chamber
1128           
1129           previousTrackParam->SetRemovable(kFALSE);
1130           if (!previousTrackParam->IsAloneInChamber()) // Make sure both clusters in second chamber are not removable anymore
1131             ((AliMUONTrackParam*) track->GetTrackParamAtCluster()->Before(previousTrackParam))->SetRemovable(kFALSE);
1132           
1133         }
1134         
1135       } else { // Worst cluster not alone in its chamber
1136         
1137         if (previousTrackParam) previousChamber = previousTrackParam->GetClusterPtr()->GetChamberId();
1138         else previousChamber = -1;
1139         
1140         if (previousChamber == worstChamber) { // the second cluster on the same chamber is the previous one
1141           
1142           previousTrackParam->SetAloneInChamber(kTRUE);
1143           // transfert the removability to the second cluster
1144           if (worstTrackParamAtCluster->IsRemovable()) previousTrackParam->SetRemovable(kTRUE);
1145           
1146         } else { // the second cluster on the same chamber is the next one
1147           
1148           nextTrackParam->SetAloneInChamber(kTRUE);
1149           // transfert the removability to the second cluster
1150           if (worstTrackParamAtCluster->IsRemovable()) nextTrackParam->SetRemovable(kTRUE);
1151           
1152         }
1153         
1154       }
1155       
1156       // Remove the worst cluster
1157       track->RemoveTrackParamAtCluster(worstTrackParamAtCluster);
1158       
1159       // Re-calculate track parameters
1160       // - from the cluster immediately downstream the one suppressed
1161       // - or from the begining - if parameters have been re-computed using the standard method (kalman parameters have been lost)
1162       //                        - or if the removed cluster was the last one
1163       if (smoothed && nextTrackParam) RetracePartialTrack(*track,nextTrackParam);
1164       else RetraceTrack(*track,kTRUE);
1165       
1166       // Printout for debuging
1167       if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructorK") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
1168         cout << "ImproveTracks: track " << fRecTracksPtr->IndexOf(track)+1 << " improved " << endl;
1169       }
1170       
1171     }
1172     
1173     track = nextTrack;
1174   }
1175   
1176   // compress the array in case of some tracks have been removed
1177   fRecTracksPtr->Compress();
1178   
1179 }
1180
1181   //__________________________________________________________________________
1182 void AliMUONTrackReconstructorK::Finalize()
1183 {
1184   /// Update track parameters and covariances at each attached cluster
1185   
1186   AliMUONTrack *track;
1187   AliMUONTrackParam *trackParamAtCluster;
1188   Bool_t smoothed = kFALSE;
1189   
1190   track = (AliMUONTrack*) fRecTracksPtr->First();
1191   while (track) {
1192     
1193     // update track parameters (using smoother if required) if not already done
1194     if (!track->IsImproved()) {
1195       smoothed = kFALSE;
1196       if (AliMUONReconstructor::GetRecoParam()->UseSmoother()) smoothed = RunSmoother(*track);
1197       if (!smoothed) track->UpdateCovTrackParamAtCluster();
1198     }
1199     
1200     // copy smoothed parameters and covariances if any
1201     if (smoothed) {
1202       
1203       trackParamAtCluster = (AliMUONTrackParam*) (track->GetTrackParamAtCluster()->First());
1204       while (trackParamAtCluster) {
1205         
1206         trackParamAtCluster->SetParameters(trackParamAtCluster->GetSmoothParameters());
1207         trackParamAtCluster->SetCovariances(trackParamAtCluster->GetSmoothCovariances());
1208         
1209         trackParamAtCluster = (AliMUONTrackParam*) (track->GetTrackParamAtCluster()->After(trackParamAtCluster));
1210       }
1211       
1212     }
1213     
1214     track = (AliMUONTrack*) fRecTracksPtr->After(track);
1215   }
1216     
1217 }
1218