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