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