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