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