Separating run-dependent mapping data from data, which are not
[u/mrichter/AliRoot.git] / MUON / AliMUONTrack.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 AliMUONTrack
20 //-------------------
21 // Reconstructed track in ALICE dimuon spectrometer
22 //-----------------------------------------------------------------------------
23
24 #include "AliMUONTrack.h"
25
26 #include "AliMUONReconstructor.h"
27 #include "AliMUONRecoParam.h"
28 #include "AliMUONVCluster.h"
29 #include "AliMUONVClusterStore.h"
30 #include "AliMUONObjectPair.h"
31 #include "AliMUONConstants.h"
32 #include "AliMUONTrackExtrap.h"
33
34 #include "AliLog.h"
35
36 #include <TMath.h>
37 #include <TMatrixD.h>
38
39 #include <Riostream.h>
40
41 /// \cond CLASSIMP
42 ClassImp(AliMUONTrack) // Class implementation in ROOT context
43 /// \endcond
44
45 //__________________________________________________________________________
46 AliMUONTrack::AliMUONTrack()
47   : TObject(),
48     fTrackParamAtCluster(0x0),
49     fFitWithVertex(kFALSE),
50     fVertexErrXY2(),
51     fFitWithMCS(kFALSE),
52     fClusterWeightsNonBending(0x0),
53     fClusterWeightsBending(0x0),
54     fGlobalChi2(-1.),
55     fImproved(kFALSE),
56     fMatchTrigger(-1),
57     floTrgNum(-1),
58     fChi2MatchTrigger(0.),
59     fTrackID(0),
60     fTrackParamAtVertex(0x0),
61     fHitsPatternInTrigCh(0),
62     fLocalTrigger(0)
63 {
64   /// Default constructor
65   fVertexErrXY2[0] = 0.;
66   fVertexErrXY2[1] = 0.;
67 }
68
69   //__________________________________________________________________________
70 AliMUONTrack::AliMUONTrack(AliMUONObjectPair *segment)
71   : TObject(),
72     fTrackParamAtCluster(new TClonesArray("AliMUONTrackParam",10)),
73     fFitWithVertex(kFALSE),
74     fVertexErrXY2(),
75     fFitWithMCS(kFALSE),
76     fClusterWeightsNonBending(0x0),
77     fClusterWeightsBending(0x0),
78     fGlobalChi2(0.),
79     fImproved(kFALSE),
80     fMatchTrigger(-1),
81     floTrgNum(-1),    
82     fChi2MatchTrigger(0.),
83     fTrackID(0),
84     fTrackParamAtVertex(0x0),
85     fHitsPatternInTrigCh(0),
86     fLocalTrigger(0)
87 {
88   /// Constructor from two clusters
89   
90   fVertexErrXY2[0] = 0.;
91   fVertexErrXY2[1] = 0.;
92   
93   // Pointers to clusters from the segment
94   AliMUONVCluster* firstCluster = (AliMUONVCluster*) segment->First();
95   AliMUONVCluster* lastCluster = (AliMUONVCluster*) segment->Second();
96   
97   // Compute track parameters
98   Double_t z1 = firstCluster->GetZ();
99   Double_t z2 = lastCluster->GetZ();
100   Double_t dZ = z1 - z2;
101   // Non bending plane
102   Double_t nonBendingCoor1 = firstCluster->GetX();
103   Double_t nonBendingCoor2 = lastCluster->GetX();
104   Double_t nonBendingSlope = (nonBendingCoor1 - nonBendingCoor2) / dZ;
105   // Bending plane
106   Double_t bendingCoor1 = firstCluster->GetY();
107   Double_t bendingCoor2 = lastCluster->GetY();
108   Double_t bendingSlope = (bendingCoor1 - bendingCoor2) / dZ;
109   // Inverse bending momentum
110   Double_t bendingImpact = bendingCoor1 - z1 * bendingSlope;
111   Double_t inverseBendingMomentum = 1. / AliMUONTrackExtrap::GetBendingMomentumFromImpactParam(bendingImpact);
112   
113   // Set track parameters at first cluster
114   AliMUONTrackParam trackParamAtFirstCluster;
115   trackParamAtFirstCluster.SetZ(z1);
116   trackParamAtFirstCluster.SetNonBendingCoor(nonBendingCoor1);
117   trackParamAtFirstCluster.SetNonBendingSlope(nonBendingSlope);
118   trackParamAtFirstCluster.SetBendingCoor(bendingCoor1);
119   trackParamAtFirstCluster.SetBendingSlope(bendingSlope);
120   trackParamAtFirstCluster.SetInverseBendingMomentum(inverseBendingMomentum);
121   
122   // Set track parameters at last cluster
123   AliMUONTrackParam trackParamAtLastCluster;
124   trackParamAtLastCluster.SetZ(z2);
125   trackParamAtLastCluster.SetNonBendingCoor(nonBendingCoor2);
126   trackParamAtLastCluster.SetNonBendingSlope(nonBendingSlope);
127   trackParamAtLastCluster.SetBendingCoor(bendingCoor2);
128   trackParamAtLastCluster.SetBendingSlope(bendingSlope);
129   trackParamAtLastCluster.SetInverseBendingMomentum(inverseBendingMomentum);
130   
131   // Compute and set track parameters covariances at first cluster
132   TMatrixD paramCov(5,5);
133   paramCov.Zero();
134   // Non bending plane
135   paramCov(0,0) = firstCluster->GetErrX2();
136   paramCov(0,1) = firstCluster->GetErrX2() / dZ;
137   paramCov(1,0) = paramCov(0,1);
138   paramCov(1,1) = ( firstCluster->GetErrX2() + lastCluster->GetErrX2() ) / dZ / dZ;
139   // Bending plane
140   paramCov(2,2) = firstCluster->GetErrY2();
141   paramCov(2,3) = firstCluster->GetErrY2() / dZ;
142   paramCov(3,2) = paramCov(2,3);
143   paramCov(3,3) = ( firstCluster->GetErrY2() + lastCluster->GetErrY2() ) / dZ / dZ;
144   // Inverse bending momentum (vertex resolution + bending slope resolution + 10% error on dipole parameters+field)
145   paramCov(4,4) = ((AliMUONReconstructor::GetRecoParam()->GetBendingVertexDispersion() *
146                     AliMUONReconstructor::GetRecoParam()->GetBendingVertexDispersion() +
147                     (z1 * z1 * lastCluster->GetErrY2() + z2 * z2 * firstCluster->GetErrY2()) / dZ / dZ) /
148                    bendingImpact / bendingImpact + 0.1 * 0.1) * inverseBendingMomentum * inverseBendingMomentum;
149   paramCov(2,4) = - z2 * firstCluster->GetErrY2() * inverseBendingMomentum / bendingImpact / dZ;
150   paramCov(4,2) = paramCov(2,4);
151   paramCov(3,4) = - (z1 * lastCluster->GetErrY2() + z2 * firstCluster->GetErrY2()) * inverseBendingMomentum / bendingImpact / dZ / dZ;
152   paramCov(4,3) = paramCov(3,4);
153   
154   // Set covariances
155   trackParamAtFirstCluster.SetCovariances(paramCov);
156   
157   // Compute and set track parameters covariances at last cluster
158   paramCov(1,0) = - paramCov(1,0);
159   paramCov(0,1) = - paramCov(0,1);
160   paramCov(3,2) = - paramCov(3,2);
161   paramCov(2,3) = - paramCov(2,3);
162   paramCov(2,4) = z1 * lastCluster->GetErrY2() * inverseBendingMomentum / bendingImpact / dZ;
163   paramCov(4,2) = paramCov(2,4);
164   trackParamAtLastCluster.SetCovariances(paramCov);
165   
166   // Add track parameters at clusters
167   AddTrackParamAtCluster(trackParamAtFirstCluster,*firstCluster);
168   AddTrackParamAtCluster(trackParamAtLastCluster,*lastCluster);
169   
170 }
171
172 //__________________________________________________________________________
173 AliMUONTrack::AliMUONTrack(const AliMUONTrack& track)
174   : TObject(track),
175     fTrackParamAtCluster(0x0),
176     fFitWithVertex(track.fFitWithVertex),
177     fVertexErrXY2(),
178     fFitWithMCS(track.fFitWithMCS),
179     fClusterWeightsNonBending(0x0),
180     fClusterWeightsBending(0x0),
181     fGlobalChi2(track.fGlobalChi2),
182     fImproved(track.fImproved),
183     fMatchTrigger(track.fMatchTrigger),
184     floTrgNum(track.floTrgNum),    
185     fChi2MatchTrigger(track.fChi2MatchTrigger),
186     fTrackID(track.fTrackID),
187     fTrackParamAtVertex(0x0),
188     fHitsPatternInTrigCh(track.fHitsPatternInTrigCh),
189     fLocalTrigger(track.fLocalTrigger)
190 {
191   ///copy constructor
192   
193   // necessary to make a copy of the objects and not only the pointers in TClonesArray.
194   if (track.fTrackParamAtCluster) {
195     fTrackParamAtCluster = new TClonesArray("AliMUONTrackParam",10);
196     AliMUONTrackParam *trackParamAtCluster = (AliMUONTrackParam*) track.fTrackParamAtCluster->First();
197     while (trackParamAtCluster) {
198       new ((*fTrackParamAtCluster)[GetNClusters()]) AliMUONTrackParam(*trackParamAtCluster);
199       trackParamAtCluster = (AliMUONTrackParam*) track.fTrackParamAtCluster->After(trackParamAtCluster);
200     }
201   }
202   
203   // copy vertex resolution square used during the tracking procedure
204   fVertexErrXY2[0] = track.fVertexErrXY2[0];
205   fVertexErrXY2[1] = track.fVertexErrXY2[1];
206   
207   // copy cluster weights matrices if any
208   if (track.fClusterWeightsNonBending) fClusterWeightsNonBending = new TMatrixD(*(track.fClusterWeightsNonBending));
209   if (track.fClusterWeightsBending) fClusterWeightsBending = new TMatrixD(*(track.fClusterWeightsBending));
210   
211   // copy track parameters at vertex if any
212   if (track.fTrackParamAtVertex) fTrackParamAtVertex = new AliMUONTrackParam(*(track.fTrackParamAtVertex));
213   
214 }
215
216   //__________________________________________________________________________
217 AliMUONTrack & AliMUONTrack::operator=(const AliMUONTrack& track)
218 {
219   /// Asignment operator
220   // check assignement to self
221   if (this == &track)
222     return *this;
223
224   // base class assignement
225   TObject::operator=(track);
226   
227   // clear memory
228   Clear();
229   
230   // necessary to make a copy of the objects and not only the pointers in TClonesArray
231   if (track.fTrackParamAtCluster) {
232     fTrackParamAtCluster = new TClonesArray("AliMUONTrackParam",10);
233     AliMUONTrackParam *trackParamAtCluster = (AliMUONTrackParam*) track.fTrackParamAtCluster->First();
234     while (trackParamAtCluster) {
235       new ((*fTrackParamAtCluster)[GetNClusters()]) AliMUONTrackParam(*trackParamAtCluster);
236       trackParamAtCluster = (AliMUONTrackParam*) track.fTrackParamAtCluster->After(trackParamAtCluster);
237     }
238   }
239   
240   // copy cluster weights matrix if any
241   if (track.fClusterWeightsNonBending) {
242     if (fClusterWeightsNonBending) {
243       fClusterWeightsNonBending->ResizeTo(*(track.fClusterWeightsNonBending));
244       *fClusterWeightsNonBending = *(track.fClusterWeightsNonBending);
245     } else fClusterWeightsNonBending = new TMatrixD(*(track.fClusterWeightsNonBending));
246   }
247   
248   // copy cluster weights matrix if any
249   if (track.fClusterWeightsBending) {
250     if (fClusterWeightsBending) {
251       fClusterWeightsBending->ResizeTo(*(track.fClusterWeightsBending));
252       *fClusterWeightsBending = *(track.fClusterWeightsBending);
253     } else fClusterWeightsBending = new TMatrixD(*(track.fClusterWeightsBending));
254   }
255   
256   // copy track parameters at vertex if any
257   if (track.fTrackParamAtVertex) {
258     if (fTrackParamAtVertex) *fTrackParamAtVertex = *(track.fTrackParamAtVertex);
259     else fTrackParamAtVertex = new AliMUONTrackParam(*(track.fTrackParamAtVertex));
260   }
261   
262   fFitWithVertex      =  track.fFitWithVertex;
263   fVertexErrXY2[0]    =  track.fVertexErrXY2[0];
264   fVertexErrXY2[1]    =  track.fVertexErrXY2[1];
265   fFitWithMCS         =  track.fFitWithMCS;
266   fGlobalChi2         =  track.fGlobalChi2;
267   fImproved           =  track.fImproved;
268   fMatchTrigger       =  track.fMatchTrigger;
269   floTrgNum           =  track.floTrgNum;
270   fChi2MatchTrigger   =  track.fChi2MatchTrigger;
271   fTrackID            =  track.fTrackID; 
272   fHitsPatternInTrigCh = track.fHitsPatternInTrigCh;
273   fLocalTrigger        = track.fLocalTrigger;
274
275   return *this;
276 }
277
278   //__________________________________________________________________________
279 AliMUONTrack::~AliMUONTrack()
280 {
281   /// Destructor
282   delete fTrackParamAtCluster;
283   delete fClusterWeightsNonBending;
284   delete fClusterWeightsBending;
285   delete fTrackParamAtVertex;
286 }
287
288   //__________________________________________________________________________
289 void AliMUONTrack::Clear(Option_t* opt)
290 {
291   /// Clear arrays
292   if (opt && opt[0] == 'C' && fTrackParamAtCluster) fTrackParamAtCluster->Clear("C");
293   else {
294     delete fTrackParamAtCluster;
295     fTrackParamAtCluster = 0x0;
296   }
297   delete fClusterWeightsNonBending; fClusterWeightsNonBending = 0x0;
298   delete fClusterWeightsBending; fClusterWeightsBending = 0x0;
299   delete fTrackParamAtVertex; fTrackParamAtVertex = 0x0;
300 }
301
302   //__________________________________________________________________________
303 void AliMUONTrack::Reset()
304 {
305   /// Reset to default values
306   SetUniqueID(0);
307   fFitWithVertex = kFALSE;
308   fVertexErrXY2[0] = 0.;
309   fVertexErrXY2[1] = 0.;
310   fFitWithMCS = kFALSE;
311   fGlobalChi2 = -1.;
312   fImproved = kFALSE;
313   fMatchTrigger = -1;
314   floTrgNum = -1;
315   fChi2MatchTrigger = 0.;
316   fTrackID = 0;
317   fHitsPatternInTrigCh = 0;
318   fLocalTrigger = 0;
319   delete fTrackParamAtCluster; fTrackParamAtCluster = 0x0;
320   delete fClusterWeightsNonBending; fClusterWeightsNonBending = 0x0;
321   delete fClusterWeightsBending; fClusterWeightsBending = 0x0;
322   delete fTrackParamAtVertex; fTrackParamAtVertex = 0x0;
323 }
324
325   //__________________________________________________________________________
326 TClonesArray* AliMUONTrack::GetTrackParamAtCluster() const
327 {
328   /// return array of track parameters at cluster (create it if needed)
329   if (!fTrackParamAtCluster) fTrackParamAtCluster = new TClonesArray("AliMUONTrackParam",10);
330   return fTrackParamAtCluster;
331 }
332
333   //__________________________________________________________________________
334 void AliMUONTrack::AddTrackParamAtCluster(const AliMUONTrackParam &trackParam, AliMUONVCluster &cluster, Bool_t copy)
335 {
336   /// Copy given track parameters into a new TrackParamAtCluster
337   /// Link parameters with the associated cluster
338   /// If copy=kTRUE: the cluster is copied then passed the trackParam which become its owner 
339   ///     otherwise: make sure to do not delete the cluster until it is used by the track
340   
341   // check chamber ID of the associated cluster
342   if (cluster.GetChamberId() < 0 || cluster.GetChamberId() > AliMUONConstants::NTrackingCh()) {
343     AliError(Form("Chamber ID of the associated cluster is not valid (ChamberId=%d)",cluster.GetChamberId()));
344     return;
345   }
346   
347   // check whether track parameters are given at the correct cluster z position
348   if (cluster.GetZ() != trackParam.GetZ()) {
349     AliError("track parameters are given at a different z position than the one of the associated cluster");
350     return;
351   }
352   
353   // add parameters to the array of track parameters
354   if (!fTrackParamAtCluster) fTrackParamAtCluster = new TClonesArray("AliMUONTrackParam",10);
355   AliMUONTrackParam* trackParamAtCluster = new ((*fTrackParamAtCluster)[GetNClusters()]) AliMUONTrackParam(trackParam);
356   
357   // link parameters with the associated cluster or its copy
358   if (copy) {
359     AliMUONVCluster *clusterCopy = static_cast<AliMUONVCluster*>(cluster.Clone());
360     trackParamAtCluster->SetClusterPtr(clusterCopy, kTRUE);
361   } else trackParamAtCluster->SetClusterPtr(&cluster);
362   
363   // sort the array of track parameters
364   fTrackParamAtCluster->Sort();
365 }
366
367   //__________________________________________________________________________
368 void AliMUONTrack::RemoveTrackParamAtCluster(AliMUONTrackParam *trackParam)
369 {
370   /// Remove trackParam from the array of TrackParamAtCluster
371   if (!fTrackParamAtCluster || !fTrackParamAtCluster->Remove(trackParam)) {
372     AliWarning("object to remove does not exist in array fTrackParamAtCluster");
373     return;
374   }
375   
376   fTrackParamAtCluster->Compress();
377 }
378
379   //__________________________________________________________________________
380 void AliMUONTrack::UpdateTrackParamAtCluster()
381 {
382   /// Update track parameters at each attached cluster
383   
384   if (GetNClusters() == 0) {
385     AliWarning("no cluster attached to the track");
386     return;
387   }
388   
389   AliMUONTrackParam* startingTrackParam = (AliMUONTrackParam*) fTrackParamAtCluster->First();
390   AliMUONTrackParam* trackParamAtCluster = (AliMUONTrackParam*) fTrackParamAtCluster->After(startingTrackParam);
391   while (trackParamAtCluster) {
392     
393     // reset track parameters and their covariances
394     trackParamAtCluster->SetParameters(startingTrackParam->GetParameters());
395     trackParamAtCluster->SetZ(startingTrackParam->GetZ());
396     
397     // extrapolation to the given z
398     AliMUONTrackExtrap::ExtrapToZ(trackParamAtCluster, trackParamAtCluster->GetClusterPtr()->GetZ());
399     
400     // prepare next step
401     startingTrackParam = trackParamAtCluster;
402     trackParamAtCluster = (AliMUONTrackParam*) (fTrackParamAtCluster->After(trackParamAtCluster));
403   }
404
405 }
406
407   //__________________________________________________________________________
408 void AliMUONTrack::UpdateCovTrackParamAtCluster()
409 {
410   /// Update track parameters and their covariances at each attached cluster
411   /// Include effects of multiple scattering in chambers
412   
413   if (GetNClusters() == 0) {
414     AliWarning("no cluster attached to the track");
415     return;
416   }
417   
418   AliMUONTrackParam* startingTrackParam = (AliMUONTrackParam*) fTrackParamAtCluster->First();
419   AliMUONTrackParam* trackParamAtCluster = (AliMUONTrackParam*) fTrackParamAtCluster->After(startingTrackParam);
420   Int_t expectedChamber = startingTrackParam->GetClusterPtr()->GetChamberId() + 1;
421   Int_t currentChamber;
422   while (trackParamAtCluster) {
423     
424     // reset track parameters and their covariances
425     trackParamAtCluster->SetParameters(startingTrackParam->GetParameters());
426     trackParamAtCluster->SetZ(startingTrackParam->GetZ());
427     trackParamAtCluster->SetCovariances(startingTrackParam->GetCovariances());
428     
429     // add MCS effect
430     AliMUONTrackExtrap::AddMCSEffect(trackParamAtCluster,AliMUONConstants::ChamberThicknessInX0(),1.);
431     
432     // add MCS in missing chambers if any
433     currentChamber = trackParamAtCluster->GetClusterPtr()->GetChamberId();
434     while (currentChamber > expectedChamber) {
435       // extrapolation to the missing chamber
436       AliMUONTrackExtrap::ExtrapToZCov(trackParamAtCluster, AliMUONConstants::DefaultChamberZ(expectedChamber));
437       // add MCS effect
438       AliMUONTrackExtrap::AddMCSEffect(trackParamAtCluster,AliMUONConstants::ChamberThicknessInX0(),1.);
439       expectedChamber++;
440     }
441     
442     // extrapolation to the z of the current cluster
443     AliMUONTrackExtrap::ExtrapToZCov(trackParamAtCluster, trackParamAtCluster->GetClusterPtr()->GetZ());
444     
445     // prepare next step
446     expectedChamber = currentChamber + 1;
447     startingTrackParam = trackParamAtCluster;
448     trackParamAtCluster = (AliMUONTrackParam*) (fTrackParamAtCluster->After(trackParamAtCluster));
449   }
450   
451 }
452
453   //__________________________________________________________________________
454 Bool_t AliMUONTrack::IsValid()
455 {
456   /// check the validity of the current track (at least one cluster per requested station)
457   
458   Int_t nClusters = GetNClusters();
459   AliMUONTrackParam *trackParam;
460   Int_t currentStation = 0, expectedStation = 0;
461   
462   for (Int_t i = 0; i < nClusters; i++) {
463     trackParam = (AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(i);
464     
465     // skip unrequested stations
466     while (expectedStation < AliMUONConstants::NTrackingSt() &&
467            !AliMUONReconstructor::GetRecoParam()->RequestStation(expectedStation)) expectedStation++;
468     
469     currentStation = trackParam->GetClusterPtr()->GetChamberId()/2;
470     
471     // missing station
472     if (currentStation > expectedStation) return kFALSE;
473     
474     // found station --> look for next one
475     if (currentStation == expectedStation) expectedStation++;
476     
477   }
478   
479   return expectedStation == AliMUONConstants::NTrackingSt();
480   
481 }
482
483   //__________________________________________________________________________
484 void AliMUONTrack::TagRemovableClusters() {
485   /// Identify clusters that can be removed from the track,
486   /// with the only requirement to have at least 1 cluster per requested station
487   
488   Int_t nClusters = GetNClusters();
489   AliMUONTrackParam *trackParam, *nextTrackParam;
490   Int_t currentCh, nextCh;
491   
492   // reset flags to kFALSE for all clusters in required station
493   for (Int_t i = 0; i < nClusters; i++) {
494     trackParam = (AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(i);
495     if (AliMUONReconstructor::GetRecoParam()->RequestStation(trackParam->GetClusterPtr()->GetChamberId()/2))
496       trackParam->SetRemovable(kFALSE);
497     else trackParam->SetRemovable(kTRUE);
498   }
499   
500   // loop over track parameters
501   for (Int_t i = 0; i < nClusters; i++) {
502     trackParam = (AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(i);
503     
504     currentCh = trackParam->GetClusterPtr()->GetChamberId();
505     
506     // loop over next track parameters
507     for (Int_t j = i+1; j < nClusters; j++) {
508       nextTrackParam = (AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(j);
509       
510       nextCh = nextTrackParam->GetClusterPtr()->GetChamberId();
511       
512       // check if the 2 clusters are on the same station
513       if (nextCh/2 != currentCh/2) break;
514       
515       // set clusters in the same station as being removable
516       trackParam->SetRemovable(kTRUE);
517       nextTrackParam->SetRemovable(kTRUE);
518       
519     }
520     
521   }
522     
523 }
524
525   //__________________________________________________________________________
526 Bool_t AliMUONTrack::ComputeLocalChi2(Bool_t accountForMCS)
527 {
528   /// Compute each cluster contribution to the chi2 of the track
529   /// accounting for multiple scattering or not according to the flag
530   /// - Also recompute the weight matrices of the attached clusters if accountForMCS=kTRUE
531   /// - Assume that track parameters at each cluster are corrects
532   /// - Return kFALSE if computation failed
533   AliDebug(1,"Enter ComputeLocalChi2");
534   
535   if (!fTrackParamAtCluster) {
536     AliWarning("no cluster attached to this track");
537     return kFALSE;
538   }
539   
540   if (accountForMCS) { // Compute local chi2 taking into account multiple scattering effects
541       
542     // Compute MCS covariance matrix only once
543     Int_t nClusters = GetNClusters();
544     TMatrixD mcsCovariances(nClusters,nClusters);
545     ComputeMCSCovariances(mcsCovariances);
546     
547     // Make sure cluster weights are consistent with following calculations
548     if (!ComputeClusterWeights(&mcsCovariances)) {
549       AliWarning("cannot take into account the multiple scattering effects");
550       return ComputeLocalChi2(kFALSE);
551     }
552     
553     // Compute chi2 of the track
554     Double_t globalChi2 = ComputeGlobalChi2(kTRUE);
555     if (globalChi2 < 0.) return kFALSE;
556     
557     // Loop over removable clusters and compute their local chi2
558     AliMUONTrackParam* trackParamAtCluster1;
559     AliMUONVCluster *cluster, *discardedCluster;
560     Int_t iCluster1, iCluster2, iCurrentCluster1, iCurrentCluster2;
561     TMatrixD clusterWeightsNB(nClusters-1,nClusters-1);
562     TMatrixD clusterWeightsB(nClusters-1,nClusters-1);
563     Double_t *dX = new Double_t[nClusters-1];
564     Double_t *dY = new Double_t[nClusters-1];
565     Double_t globalChi2b;
566     AliMUONTrackParam* trackParamAtCluster = (AliMUONTrackParam*) fTrackParamAtCluster->First();
567     while (trackParamAtCluster) {
568       
569       discardedCluster = trackParamAtCluster->GetClusterPtr();
570       
571       // Recompute cluster weights without the current cluster
572       if (!ComputeClusterWeights(clusterWeightsNB, clusterWeightsB, &mcsCovariances, discardedCluster)) {
573         AliWarning("cannot take into account the multiple scattering effects");
574         delete [] dX;
575         delete [] dY;
576         return ComputeLocalChi2(kFALSE);
577       }
578       
579       // Compute track chi2 without the current cluster
580       globalChi2b = 0.;
581       iCurrentCluster1 = 0;
582       for (iCluster1 = 0; iCluster1 < nClusters ; iCluster1++) { 
583         trackParamAtCluster1 = (AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(iCluster1);
584         cluster = trackParamAtCluster1->GetClusterPtr();
585         
586         if (cluster == discardedCluster) continue;
587         
588         // Compute and save residuals
589         dX[iCurrentCluster1] = cluster->GetX() - trackParamAtCluster1->GetNonBendingCoor();
590         dY[iCurrentCluster1] = cluster->GetY() - trackParamAtCluster1->GetBendingCoor();
591         
592         iCurrentCluster2 = 0;
593         for (iCluster2 = 0; iCluster2 < iCluster1; iCluster2++) {
594           cluster = ((AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(iCluster2))->GetClusterPtr();
595           
596           if (cluster == discardedCluster) continue;
597           
598           // Add contribution from covariances
599           globalChi2b += (clusterWeightsNB(iCurrentCluster1, iCurrentCluster2) +
600                           clusterWeightsNB(iCurrentCluster2, iCurrentCluster1)) * dX[iCurrentCluster1] * dX[iCurrentCluster2] +
601                          (clusterWeightsB(iCurrentCluster1, iCurrentCluster2) +
602                           clusterWeightsB(iCurrentCluster2, iCurrentCluster1)) * dY[iCurrentCluster1] * dY[iCurrentCluster2];
603           
604           iCurrentCluster2++;
605         }
606         
607         // Add contribution from variances
608         globalChi2b += clusterWeightsNB(iCurrentCluster1, iCurrentCluster1) * dX[iCurrentCluster1] * dX[iCurrentCluster1] +
609                        clusterWeightsB(iCurrentCluster1, iCurrentCluster1) * dY[iCurrentCluster1] * dY[iCurrentCluster1];
610         
611         iCurrentCluster1++;
612       }
613
614       // Set local chi2
615       trackParamAtCluster->SetLocalChi2(globalChi2 - globalChi2b);
616       
617       trackParamAtCluster = (AliMUONTrackParam*) fTrackParamAtCluster->After(trackParamAtCluster);
618     }
619     
620     delete [] dX;
621     delete [] dY;
622     
623   } else { // without multiple scattering effects
624     
625     AliMUONVCluster *discardedCluster;
626     Double_t dX, dY;
627     AliMUONTrackParam* trackParamAtCluster = (AliMUONTrackParam*) fTrackParamAtCluster->First();
628     while (trackParamAtCluster) {
629       
630       discardedCluster = trackParamAtCluster->GetClusterPtr();
631       
632       // Compute residuals
633       dX = discardedCluster->GetX() - trackParamAtCluster->GetNonBendingCoor();
634       dY = discardedCluster->GetY() - trackParamAtCluster->GetBendingCoor();
635       
636       // Set local chi2
637       trackParamAtCluster->SetLocalChi2(dX * dX / discardedCluster->GetErrX2() + dY * dY / discardedCluster->GetErrY2());
638     
639       trackParamAtCluster = (AliMUONTrackParam*) fTrackParamAtCluster->After(trackParamAtCluster);
640     }
641   
642   }
643   
644   return kTRUE;
645   
646 }
647
648   //__________________________________________________________________________
649 Double_t AliMUONTrack::ComputeGlobalChi2(Bool_t accountForMCS)
650 {
651   /// Compute the chi2 of the track accounting for multiple scattering or not according to the flag
652   /// - Assume that track parameters at each cluster are corrects
653   /// - Assume the cluster weights matrices are corrects
654   /// - Return negative value if chi2 computation failed
655   AliDebug(1,"Enter ComputeGlobalChi2");
656   
657   if (!fTrackParamAtCluster) {
658     AliWarning("no cluster attached to this track");
659     return 1.e10;
660   }
661   
662   Double_t chi2 = 0.;
663   
664   if (accountForMCS) {
665     
666     // Check the weight matrices. If weight matrices are not available compute chi2 without MCS
667     if (!fClusterWeightsNonBending || !fClusterWeightsBending) {
668       AliWarning("cluster weights including multiple scattering effects are not available\n\t\t --> compute chi2 WITHOUT multiple scattering");
669       return ComputeGlobalChi2(kFALSE);
670     }
671     Int_t nClusters = GetNClusters();
672     if (fClusterWeightsNonBending->GetNrows() != nClusters || fClusterWeightsBending->GetNcols() != nClusters) {
673       AliWarning("cluster weights including multiple scattering effects are not available\n\t\t --> compute chi2 WITHOUT multiple scattering");
674       return ComputeGlobalChi2(kFALSE);
675     }
676     
677     // Compute chi2
678     AliMUONVCluster *cluster;
679     Double_t *dX = new Double_t[nClusters];
680     Double_t *dY = new Double_t[nClusters];
681     AliMUONTrackParam* trackParamAtCluster;
682     for (Int_t iCluster1 = 0; iCluster1 < nClusters; iCluster1++) { 
683       trackParamAtCluster = (AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(iCluster1);
684       cluster = trackParamAtCluster->GetClusterPtr();
685       dX[iCluster1] = cluster->GetX() - trackParamAtCluster->GetNonBendingCoor();
686       dY[iCluster1] = cluster->GetY() - trackParamAtCluster->GetBendingCoor();
687       for (Int_t iCluster2 = 0; iCluster2 < iCluster1; iCluster2++) {
688         chi2 += ((*fClusterWeightsNonBending)(iCluster1, iCluster2) + (*fClusterWeightsNonBending)(iCluster2, iCluster1)) * dX[iCluster1] * dX[iCluster2] +
689                 ((*fClusterWeightsBending)(iCluster1, iCluster2) + (*fClusterWeightsBending)(iCluster2, iCluster1)) * dY[iCluster1] * dY[iCluster2];
690       }
691       chi2 += ((*fClusterWeightsNonBending)(iCluster1, iCluster1) * dX[iCluster1] * dX[iCluster1]) +
692               ((*fClusterWeightsBending)(iCluster1, iCluster1) * dY[iCluster1] * dY[iCluster1]);
693     }
694     delete [] dX;
695     delete [] dY;
696     
697   } else {
698     
699     AliMUONVCluster *cluster;
700     Double_t dX, dY;
701     AliMUONTrackParam* trackParamAtCluster;
702     Int_t nClusters = GetNClusters();
703     for (Int_t iCluster = 0; iCluster < nClusters ; iCluster++) { 
704       trackParamAtCluster = (AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(iCluster);
705       cluster = trackParamAtCluster->GetClusterPtr();
706       dX = cluster->GetX() - trackParamAtCluster->GetNonBendingCoor();
707       dY = cluster->GetY() - trackParamAtCluster->GetBendingCoor();
708       chi2 += dX * dX / cluster->GetErrX2() + dY * dY / cluster->GetErrY2();
709     }
710     
711   }
712   
713   return chi2;
714   
715 }
716
717   //__________________________________________________________________________
718 Bool_t AliMUONTrack::ComputeClusterWeights(TMatrixD* mcsCovariances)
719 {
720   /// Compute the weight matrices of the attached clusters, in non bending and bending direction,
721   /// accounting for multiple scattering correlations and cluster resolution
722   /// - Use the provided MCS covariance matrix if any (otherwise build it temporarily)
723   /// - Assume that track parameters at each cluster are corrects
724   /// - Return kFALSE if computation failed
725   AliDebug(1,"Enter ComputeClusterWeights1");
726   
727   if (!fTrackParamAtCluster) {
728     AliWarning("no cluster attached to this track");
729     return kFALSE;
730   }
731   
732   // Alocate memory
733   Int_t nClusters = GetNClusters();
734   if (!fClusterWeightsNonBending) fClusterWeightsNonBending = new TMatrixD(nClusters,nClusters);
735   if (!fClusterWeightsBending) fClusterWeightsBending = new TMatrixD(nClusters,nClusters);
736   
737   // Compute weights matrices
738   if (!ComputeClusterWeights(*fClusterWeightsNonBending, *fClusterWeightsBending, mcsCovariances)) return kFALSE;
739   
740   return kTRUE;
741   
742 }
743
744   //__________________________________________________________________________
745 Bool_t AliMUONTrack::ComputeClusterWeights(TMatrixD& clusterWeightsNB, TMatrixD& clusterWeightsB,
746                                            TMatrixD* mcsCovariances, AliMUONVCluster* discardedCluster) const
747 {
748   /// Compute the weight matrices, in non bending and bending direction,
749   /// of the other attached clusters assuming the discarded one does not exist
750   /// accounting for multiple scattering correlations and cluster resolution
751   /// - Use the provided MCS covariance matrix if any (otherwise build it temporarily)
752   /// - Return kFALSE if computation failed
753   AliDebug(1,"Enter ComputeClusterWeights2");
754   
755   // Check MCS covariance matrix and recompute it if need
756   Int_t nClusters = GetNClusters();
757   Bool_t deleteMCSCov = kFALSE;
758   if (!mcsCovariances) {
759     mcsCovariances = new TMatrixD(nClusters,nClusters);
760     deleteMCSCov = kTRUE;
761     ComputeMCSCovariances(*mcsCovariances);
762   }
763   
764   // Resize the weights matrices; alocate memory
765   if (discardedCluster) {
766     clusterWeightsNB.ResizeTo(nClusters-1,nClusters-1);
767     clusterWeightsB.ResizeTo(nClusters-1,nClusters-1);
768   } else {
769     clusterWeightsNB.ResizeTo(nClusters,nClusters);
770     clusterWeightsB.ResizeTo(nClusters,nClusters);
771   }
772   
773   // Define variables
774   AliMUONVCluster *cluster1, *cluster2;
775   Int_t iCurrentCluster1, iCurrentCluster2;
776   
777   // Compute the covariance matrices
778   iCurrentCluster1 = 0;
779   for (Int_t iCluster1 = 0; iCluster1 < nClusters; iCluster1++) { 
780     cluster1 = ((AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(iCluster1))->GetClusterPtr();
781     
782     if (cluster1 == discardedCluster) continue;
783     
784     // Loop over next clusters
785     iCurrentCluster2 = iCurrentCluster1;
786     for (Int_t iCluster2 = iCluster1; iCluster2 < nClusters; iCluster2++) {
787       cluster2 = ((AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(iCluster2))->GetClusterPtr();
788       
789       if (cluster2 == discardedCluster) continue;
790       
791       // Fill with MCS covariances
792       clusterWeightsNB(iCurrentCluster1, iCurrentCluster2) = (*mcsCovariances)(iCluster1,iCluster2);
793       
794       // Equal contribution from multiple scattering in non bending and bending directions
795       clusterWeightsB(iCurrentCluster1, iCurrentCluster2) = clusterWeightsNB(iCurrentCluster1, iCurrentCluster2);
796       
797       // Add contribution from cluster resolution to diagonal element and symmetrize the matrix
798       if (iCurrentCluster1 == iCurrentCluster2) {
799         
800         // In non bending plane
801         clusterWeightsNB(iCurrentCluster1, iCurrentCluster1) += cluster1->GetErrX2();
802         // In bending plane
803         clusterWeightsB(iCurrentCluster1, iCurrentCluster1) += cluster1->GetErrY2();
804         
805       } else {
806         
807         // In non bending plane
808         clusterWeightsNB(iCurrentCluster2, iCurrentCluster1) = clusterWeightsNB(iCurrentCluster1, iCurrentCluster2);
809         // In bending plane
810         clusterWeightsB(iCurrentCluster2, iCurrentCluster1) = clusterWeightsB(iCurrentCluster1, iCurrentCluster2);
811         
812       }
813       
814       iCurrentCluster2++;
815     }
816     
817     iCurrentCluster1++;
818   }
819     
820   // Inversion of covariance matrices to get the weights
821   if (clusterWeightsNB.Determinant() != 0 && clusterWeightsB.Determinant() != 0) {
822     clusterWeightsNB.Invert();
823     clusterWeightsB.Invert();
824   } else {
825     AliWarning(" Determinant = 0");
826     clusterWeightsNB.ResizeTo(0,0);
827     clusterWeightsB.ResizeTo(0,0);
828     if(deleteMCSCov) delete mcsCovariances;
829     return kFALSE;
830   }
831   
832   if(deleteMCSCov) delete mcsCovariances;
833   
834   return kTRUE;
835   
836 }
837
838   //__________________________________________________________________________
839 void AliMUONTrack::ComputeMCSCovariances(TMatrixD& mcsCovariances) const
840 {
841   /// Compute the multiple scattering covariance matrix
842   /// (assume that track parameters at each cluster are corrects)
843   AliDebug(1,"Enter ComputeMCSCovariances");
844   
845   // Reset the size of the covariance matrix if needed
846   Int_t nClusters = GetNClusters();
847   if (mcsCovariances.GetNrows() != nClusters) mcsCovariances.ResizeTo(nClusters,nClusters);
848   
849   // Define variables
850   Int_t nChambers = AliMUONConstants::NTrackingCh();
851   AliMUONTrackParam* trackParamAtCluster;
852   AliMUONTrackParam extrapTrackParam;
853   Int_t currentChamber = 0, expectedChamber = 0, size = 0;
854   Double_t *mcsAngle2 = new Double_t[2*nChambers];
855   Double_t *zMCS = new Double_t[2*nChambers];
856   Int_t *indices = new Int_t[2*nClusters];
857   
858   // Compute multiple scattering dispersion angle at each chamber
859   // and save the z position where it is calculated
860   for (Int_t iCluster = 0; iCluster < nClusters; iCluster++) {
861     trackParamAtCluster = (AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(iCluster);
862     
863     // look for missing chambers if any
864     currentChamber = trackParamAtCluster->GetClusterPtr()->GetChamberId();
865     while (currentChamber > expectedChamber) {
866       
867       // Save the z position where MCS dispersion is calculated
868       zMCS[size] = AliMUONConstants::DefaultChamberZ(expectedChamber);
869       
870       // Do not take into account MCS in chambers prior the first cluster
871       if (iCluster > 0) {
872         
873         // Get track parameters at missing chamber z
874         extrapTrackParam = *trackParamAtCluster;
875         AliMUONTrackExtrap::ExtrapToZ(&extrapTrackParam, zMCS[size]);
876         
877         // Save multiple scattering dispersion angle in missing chamber
878         mcsAngle2[size] = AliMUONTrackExtrap::GetMCSAngle2(extrapTrackParam,AliMUONConstants::ChamberThicknessInX0(),1.);
879         
880       } else mcsAngle2[size] = 0.;
881       
882       expectedChamber++;
883       size++;
884     }
885     
886     // Save z position where MCS dispersion is calculated
887     zMCS[size] = trackParamAtCluster->GetZ();
888     
889     // Save multiple scattering dispersion angle in current chamber
890     mcsAngle2[size] = AliMUONTrackExtrap::GetMCSAngle2(*trackParamAtCluster,AliMUONConstants::ChamberThicknessInX0(),1.);
891     
892     // Save indice in zMCS array corresponding to the current cluster
893     indices[iCluster] = size;
894     
895     expectedChamber = currentChamber + 1;
896     size++;
897   }
898   
899   // complete array of z if last cluster is on the last but one chamber
900   if (currentChamber != nChambers-1) zMCS[size++] = AliMUONConstants::DefaultChamberZ(nChambers-1);
901   
902   // Compute the covariance matrix
903   for (Int_t iCluster1 = 0; iCluster1 < nClusters; iCluster1++) { 
904     
905     for (Int_t iCluster2 = iCluster1; iCluster2 < nClusters; iCluster2++) {
906       
907       // Initialization to 0 (diagonal plus upper triangular part)
908       mcsCovariances(iCluster1,iCluster2) = 0.;
909       
910       // Compute contribution from multiple scattering in upstream chambers
911       for (Int_t k = 0; k < indices[iCluster1]; k++) {  
912         mcsCovariances(iCluster1,iCluster2) += (zMCS[indices[iCluster1]] - zMCS[k]) * (zMCS[indices[iCluster2]] - zMCS[k]) * mcsAngle2[k];
913       }
914       
915       // Symetrize the matrix
916       mcsCovariances(iCluster2,iCluster1) = mcsCovariances(iCluster1,iCluster2);
917     }
918     
919   }
920     
921   delete [] mcsAngle2;
922   delete [] zMCS;
923   delete [] indices;
924   
925 }
926
927   //__________________________________________________________________________
928 Int_t AliMUONTrack::ClustersInCommon(AliMUONTrack* track) const
929 {
930   /// Returns the number of clusters in common between the current track ("this")
931   /// and the track pointed to by "track".
932   if (!fTrackParamAtCluster || !this->fTrackParamAtCluster) return 0;
933   Int_t clustersInCommon = 0;
934   AliMUONTrackParam *trackParamAtCluster1, *trackParamAtCluster2;
935   // Loop over clusters of first track
936   trackParamAtCluster1 = (AliMUONTrackParam*) this->fTrackParamAtCluster->First();
937   while (trackParamAtCluster1) {
938     // Loop over clusters of second track
939     trackParamAtCluster2 = (AliMUONTrackParam*) track->fTrackParamAtCluster->First();
940     while (trackParamAtCluster2) {
941       // Increment "clustersInCommon" if both trackParamAtCluster1 & 2 point to the same cluster
942       if ((trackParamAtCluster1->GetClusterPtr()) == (trackParamAtCluster2->GetClusterPtr())) {
943         clustersInCommon++;
944         break;
945       }
946       trackParamAtCluster2 = (AliMUONTrackParam*) track->fTrackParamAtCluster->After(trackParamAtCluster2);
947     } // trackParamAtCluster2
948     trackParamAtCluster1 = (AliMUONTrackParam*) this->fTrackParamAtCluster->After(trackParamAtCluster1);
949   } // trackParamAtCluster1
950   return clustersInCommon;
951 }
952
953   //__________________________________________________________________________
954 Double_t AliMUONTrack::GetNormalizedChi2() const
955 {
956   /// return the chi2 value divided by the number of degrees of freedom (or 1.e10 if ndf < 0)
957   
958   Double_t numberOfDegFree = (2. * GetNClusters() - 5.);
959   if (numberOfDegFree > 0.) return fGlobalChi2 / numberOfDegFree;
960   else return fGlobalChi2; // system is under-constraint
961 }
962
963   //__________________________________________________________________________
964 Bool_t* AliMUONTrack::CompatibleTrack(AliMUONTrack *track, Double_t sigmaCut) const
965 {
966   /// for each chamber: return kTRUE (kFALSE) if clusters are compatible (not compatible)
967   AliMUONTrackParam *trackParamAtCluster1, *trackParamAtCluster2;
968   AliMUONVCluster *cluster1, *cluster2;
969   Double_t chi2, dX, dY, dZ;
970   Double_t chi2Max = sigmaCut * sigmaCut;
971   Double_t dZMax = 1.; // 1 cm
972   
973   Bool_t *compatibleCluster = new Bool_t[AliMUONConstants::NTrackingCh()]; 
974   for ( Int_t ch = 0; ch < AliMUONConstants::NTrackingCh(); ch++) compatibleCluster[ch] = kFALSE;
975
976   if (!fTrackParamAtCluster || !this->fTrackParamAtCluster) return compatibleCluster;
977   
978   // Loop over clusters of first track
979   trackParamAtCluster1 = (AliMUONTrackParam*) this->fTrackParamAtCluster->First();
980   while (trackParamAtCluster1) {
981     
982     cluster1 = trackParamAtCluster1->GetClusterPtr();
983     
984     // Loop over clusters of second track
985     trackParamAtCluster2 = (AliMUONTrackParam*) track->fTrackParamAtCluster->First();
986     while (trackParamAtCluster2) {
987       
988       cluster2 = trackParamAtCluster2->GetClusterPtr();
989       
990       //prepare next step
991       trackParamAtCluster2 = (AliMUONTrackParam*) track->fTrackParamAtCluster->After(trackParamAtCluster2);
992       
993       // z direction
994       dZ = cluster1->GetZ() - cluster2->GetZ();
995       if (dZ > dZMax) continue;
996       
997       // non bending direction
998       dX = cluster1->GetX() - cluster2->GetX();
999       chi2 = dX * dX / (cluster1->GetErrX2() + cluster2->GetErrX2());
1000       if (chi2 > chi2Max) continue;
1001       
1002       // bending direction
1003       dY = cluster1->GetY() - cluster2->GetY();
1004       chi2 = dY * dY / (cluster1->GetErrY2() + cluster2->GetErrY2());
1005       if (chi2 > chi2Max) continue;
1006       
1007       compatibleCluster[cluster1->GetChamberId()] = kTRUE;
1008       break;
1009     }
1010     
1011     trackParamAtCluster1 = (AliMUONTrackParam*) this->fTrackParamAtCluster->After(trackParamAtCluster1);
1012   }
1013   
1014   return compatibleCluster;
1015 }
1016
1017 //__________________________________________________________________________
1018 void AliMUONTrack::SetTrackParamAtVertex(const AliMUONTrackParam* trackParam)
1019 {
1020   /// set track parameters at vertex
1021   if (trackParam == 0x0) return;
1022   if (fTrackParamAtVertex) *fTrackParamAtVertex = *trackParam;
1023   else fTrackParamAtVertex = new AliMUONTrackParam(*trackParam);
1024 }
1025
1026 //__________________________________________________________________________
1027 void AliMUONTrack::RecursiveDump() const
1028 {
1029   /// Recursive dump of AliMUONTrack, i.e. with dump of trackParamAtCluster and attached clusters
1030   AliMUONTrackParam *trackParamAtCluster;
1031   AliMUONVCluster *cluster;
1032   cout << "Recursive dump of Track: " << this << endl;
1033   // Track
1034   this->Dump();
1035   for (Int_t iCluster = 0; iCluster < GetNClusters(); iCluster++) {
1036     trackParamAtCluster = (AliMUONTrackParam*) ((*fTrackParamAtCluster)[iCluster]);
1037     // trackParamAtCluster
1038     cout << "trackParamAtCluster: " << trackParamAtCluster << " (index: " << iCluster << ")" << endl;
1039     trackParamAtCluster->Dump();
1040     cluster = trackParamAtCluster->GetClusterPtr();
1041     // cluster
1042     cout << "cluster: " << cluster << endl;
1043     cluster->Print();
1044   }
1045   return;
1046 }
1047   
1048 //_____________________________________________-
1049 void AliMUONTrack::Print(Option_t*) const
1050 {
1051   /// Printing Track information 
1052
1053   cout << "<AliMUONTrack> No.Clusters=" << setw(2)   << GetNClusters() << 
1054       ", Match2Trig=" << setw(1) << GetMatchTrigger()  << 
1055       ", LoTrgNum=" << setw(3) << GetLoTrgNum()  << 
1056     ", Chi2-tracking-trigger=" << setw(8) << setprecision(5) <<  GetChi2MatchTrigger();
1057   cout << Form(" HitTriggerPattern %x",fHitsPatternInTrigCh) << endl;
1058   if (fTrackParamAtCluster) fTrackParamAtCluster->First()->Print("FULL");
1059 }
1060
1061 //__________________________________________________________________________
1062 void AliMUONTrack::SetLocalTrigger(Int_t loCirc, Int_t loStripX, Int_t loStripY, Int_t loDev, Int_t loLpt, Int_t loHpt)
1063 {
1064   /// pack the local trigger information and store
1065
1066   if (loCirc < 0) return;
1067
1068   fLocalTrigger = 0;
1069   fLocalTrigger += loCirc;
1070   fLocalTrigger += loStripX << 8;
1071   fLocalTrigger += loStripY << 13;
1072   fLocalTrigger += loDev    << 17;
1073   fLocalTrigger += loLpt    << 22;
1074   fLocalTrigger += loHpt    << 24;
1075
1076 }
1077