1 /**************************************************************************
2 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
4 * Author: The ALICE Off-line Project. *
5 * Contributors are mentioned in the code where appropriate. *
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 **************************************************************************/
18 //-----------------------------------------------------------------------------
21 // Reconstructed track in ALICE dimuon spectrometer
22 //-----------------------------------------------------------------------------
24 #include "AliMUONTrack.h"
26 #include "AliMUONVCluster.h"
27 #include "AliMUONVClusterStore.h"
28 #include "AliMUONObjectPair.h"
29 #include "AliMUONConstants.h"
30 #include "AliMUONTrackExtrap.h"
37 #include <Riostream.h>
40 ClassImp(AliMUONTrack) // Class implementation in ROOT context
43 //__________________________________________________________________________
44 AliMUONTrack::AliMUONTrack()
46 fTrackParamAtCluster(0x0),
47 fFitWithVertex(kFALSE),
50 fClusterWeightsNonBending(0x0),
51 fClusterWeightsBending(0x0),
56 fChi2MatchTrigger(0.),
58 fTrackParamAtVertex(0x0),
59 fHitsPatternInTrigCh(0),
62 /// Default constructor
63 fVertexErrXY2[0] = 0.;
64 fVertexErrXY2[1] = 0.;
67 //__________________________________________________________________________
68 AliMUONTrack::AliMUONTrack(AliMUONObjectPair *segment)
70 fTrackParamAtCluster(new TClonesArray("AliMUONTrackParam",10)),
71 fFitWithVertex(kFALSE),
74 fClusterWeightsNonBending(0x0),
75 fClusterWeightsBending(0x0),
80 fChi2MatchTrigger(0.),
82 fTrackParamAtVertex(0x0),
83 fHitsPatternInTrigCh(0),
86 /// Constructor from two clusters
88 fVertexErrXY2[0] = 0.;
89 fVertexErrXY2[1] = 0.;
91 // Pointers to clusters from the segment
92 AliMUONVCluster* cluster1 = (AliMUONVCluster*) segment->First();
93 AliMUONVCluster* cluster2 = (AliMUONVCluster*) segment->Second();
95 // check sorting in -Z (spectro z<0)
96 if (cluster1->GetZ() < cluster2->GetZ()) {
98 cluster2 = (AliMUONVCluster*) segment->First();
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;
109 firstCluster = cluster2;
110 lastCluster = cluster1;
113 // Compute track parameters
114 Double_t z1 = firstCluster->GetZ();
115 Double_t z2 = lastCluster->GetZ();
116 Double_t dZ = z1 - z2;
118 Double_t nonBendingCoor1 = firstCluster->GetX();
119 Double_t nonBendingCoor2 = lastCluster->GetX();
120 Double_t nonBendingSlope = (nonBendingCoor1 - nonBendingCoor2) / dZ;
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);
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);
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);
150 // Compute and set track parameters covariances at first cluster (needed by any tracking algorithm)
151 TMatrixD paramCov1(5,5);
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;
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;
166 trackParamAtFirstCluster.SetCovariances(paramCov1);
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);
173 paramCov2(0,0) = paramCov1(0,0);
174 paramCov2(1,1) = 100.*paramCov1(1,1);
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);
181 trackParamAtLastCluster.SetCovariances(paramCov2);
183 // Flag clusters as being removable
184 trackParamAtFirstCluster.SetRemovable(kTRUE);
185 trackParamAtLastCluster.SetRemovable(kTRUE);
187 // Add track parameters at clusters
188 AddTrackParamAtCluster(trackParamAtFirstCluster,*firstCluster);
189 AddTrackParamAtCluster(trackParamAtLastCluster,*lastCluster);
193 //__________________________________________________________________________
194 AliMUONTrack::AliMUONTrack(const AliMUONTrack& track)
196 fTrackParamAtCluster(0x0),
197 fFitWithVertex(track.fFitWithVertex),
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)
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);
224 // copy vertex resolution square used during the tracking procedure
225 fVertexErrXY2[0] = track.fVertexErrXY2[0];
226 fVertexErrXY2[1] = track.fVertexErrXY2[1];
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));
232 // copy track parameters at vertex if any
233 if (track.fTrackParamAtVertex) fTrackParamAtVertex = new AliMUONTrackParam(*(track.fTrackParamAtVertex));
237 //__________________________________________________________________________
238 AliMUONTrack & AliMUONTrack::operator=(const AliMUONTrack& track)
240 /// Asignment operator
241 // check assignement to self
245 // base class assignement
246 TObject::operator=(track);
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);
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));
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));
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));
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;
299 //__________________________________________________________________________
300 AliMUONTrack::~AliMUONTrack()
303 delete fTrackParamAtCluster;
304 delete fClusterWeightsNonBending;
305 delete fClusterWeightsBending;
306 delete fTrackParamAtVertex;
309 //__________________________________________________________________________
310 void AliMUONTrack::Clear(Option_t* opt)
313 if (opt && opt[0] == 'C' && fTrackParamAtCluster) fTrackParamAtCluster->Clear("C");
315 delete fTrackParamAtCluster;
316 fTrackParamAtCluster = 0x0;
318 delete fClusterWeightsNonBending; fClusterWeightsNonBending = 0x0;
319 delete fClusterWeightsBending; fClusterWeightsBending = 0x0;
320 delete fTrackParamAtVertex; fTrackParamAtVertex = 0x0;
323 //__________________________________________________________________________
324 TClonesArray* AliMUONTrack::GetTrackParamAtCluster() const
326 /// return array of track parameters at cluster (create it if needed)
327 if (!fTrackParamAtCluster) fTrackParamAtCluster = new TClonesArray("AliMUONTrackParam",10);
328 return fTrackParamAtCluster;
331 //__________________________________________________________________________
332 void AliMUONTrack::AddTrackParamAtCluster(const AliMUONTrackParam &trackParam, AliMUONVCluster &cluster, Bool_t copy)
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
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()));
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");
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);
355 // link parameters with the associated cluster or its copy
357 AliMUONVCluster *clusterCopy = static_cast<AliMUONVCluster*>(cluster.Clone());
358 trackParamAtCluster->SetClusterPtr(clusterCopy, kTRUE);
359 } else trackParamAtCluster->SetClusterPtr(&cluster);
361 // sort the array of track parameters
362 fTrackParamAtCluster->Sort();
365 //__________________________________________________________________________
366 void AliMUONTrack::RemoveTrackParamAtCluster(AliMUONTrackParam *trackParam)
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");
374 fTrackParamAtCluster->Compress();
377 //__________________________________________________________________________
378 void AliMUONTrack::UpdateTrackParamAtCluster()
380 /// Update track parameters at each attached cluster
382 if (GetNClusters() == 0) {
383 AliWarning("no cluster attached to the track");
387 AliMUONTrackParam* startingTrackParam = (AliMUONTrackParam*) fTrackParamAtCluster->First();
388 AliMUONTrackParam* trackParamAtCluster = (AliMUONTrackParam*) fTrackParamAtCluster->After(startingTrackParam);
389 while (trackParamAtCluster) {
391 // reset track parameters and their covariances
392 trackParamAtCluster->SetParameters(startingTrackParam->GetParameters());
393 trackParamAtCluster->SetZ(startingTrackParam->GetZ());
395 // extrapolation to the given z
396 AliMUONTrackExtrap::ExtrapToZ(trackParamAtCluster, trackParamAtCluster->GetClusterPtr()->GetZ());
399 startingTrackParam = trackParamAtCluster;
400 trackParamAtCluster = (AliMUONTrackParam*) (fTrackParamAtCluster->After(trackParamAtCluster));
405 //__________________________________________________________________________
406 void AliMUONTrack::UpdateCovTrackParamAtCluster()
408 /// Update track parameters and their covariances at each attached cluster
409 /// Include effects of multiple scattering in chambers
411 if (GetNClusters() == 0) {
412 AliWarning("no cluster attached to the track");
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) {
422 // reset track parameters and their covariances
423 trackParamAtCluster->SetParameters(startingTrackParam->GetParameters());
424 trackParamAtCluster->SetZ(startingTrackParam->GetZ());
425 trackParamAtCluster->SetCovariances(startingTrackParam->GetCovariances());
428 AliMUONTrackExtrap::AddMCSEffect(trackParamAtCluster,AliMUONConstants::ChamberThicknessInX0(),1.);
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));
436 AliMUONTrackExtrap::AddMCSEffect(trackParamAtCluster,AliMUONConstants::ChamberThicknessInX0(),1.);
440 // extrapolation to the z of the current cluster
441 AliMUONTrackExtrap::ExtrapToZCov(trackParamAtCluster, trackParamAtCluster->GetClusterPtr()->GetZ());
444 expectedChamber = currentChamber + 1;
445 startingTrackParam = trackParamAtCluster;
446 trackParamAtCluster = (AliMUONTrackParam*) (fTrackParamAtCluster->After(trackParamAtCluster));
451 //__________________________________________________________________________
452 Bool_t AliMUONTrack::IsValid()
454 /// check the validity of the current track (at least one cluster per station)
456 Int_t nClusters = GetNClusters();
457 AliMUONTrackParam *trackParam;
458 Int_t currentStation = 0, expectedStation = 0;
460 for (Int_t i = 0; i < nClusters; i++) {
461 trackParam = (AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(i);
463 currentStation = trackParam->GetClusterPtr()->GetChamberId()/2;
466 if (currentStation > expectedStation) return kFALSE;
468 // found station --> look for next one
469 if (currentStation == expectedStation) expectedStation++;
473 return currentStation == AliMUONConstants::NTrackingSt() - 1;
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
482 Int_t nClusters = GetNClusters();
483 AliMUONTrackParam *trackParam, *nextTrackParam;
484 Int_t currentCh, nextCh;
486 // reset flags to default
487 for (Int_t i = 0; i < nClusters; i++) {
488 trackParam = (AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(i);
489 trackParam->SetRemovable(kFALSE);
492 // loop over track parameters
493 for (Int_t i = 0; i < nClusters; i++) {
494 trackParam = (AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(i);
496 currentCh = trackParam->GetClusterPtr()->GetChamberId();
498 // loop over next track parameters
499 for (Int_t j = i+1; j < nClusters; j++) {
500 nextTrackParam = (AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(j);
502 nextCh = nextTrackParam->GetClusterPtr()->GetChamberId();
504 // check if the 2 clusters are on the same station
505 if (nextCh/2 != currentCh/2) break;
507 // set clusters in the same station as being removable
508 trackParam->SetRemovable(kTRUE);
509 nextTrackParam->SetRemovable(kTRUE);
517 //__________________________________________________________________________
518 Bool_t AliMUONTrack::ComputeLocalChi2(Bool_t accountForMCS)
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");
527 if (!fTrackParamAtCluster) {
528 AliWarning("no cluster attached to this track");
532 if (accountForMCS) { // Compute local chi2 taking into account multiple scattering effects
534 // Compute MCS covariance matrix only once
535 Int_t nClusters = GetNClusters();
536 TMatrixD mcsCovariances(nClusters,nClusters);
537 ComputeMCSCovariances(mcsCovariances);
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);
545 // Compute chi2 of the track
546 Double_t globalChi2 = ComputeGlobalChi2(kTRUE);
547 if (globalChi2 < 0.) return kFALSE;
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) {
561 discardedCluster = trackParamAtCluster->GetClusterPtr();
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");
568 return ComputeLocalChi2(kFALSE);
571 // Compute track chi2 without the current cluster
573 iCurrentCluster1 = 0;
574 for (iCluster1 = 0; iCluster1 < nClusters ; iCluster1++) {
575 trackParamAtCluster1 = (AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(iCluster1);
576 cluster = trackParamAtCluster1->GetClusterPtr();
578 if (cluster == discardedCluster) continue;
580 // Compute and save residuals
581 dX[iCurrentCluster1] = cluster->GetX() - trackParamAtCluster1->GetNonBendingCoor();
582 dY[iCurrentCluster1] = cluster->GetY() - trackParamAtCluster1->GetBendingCoor();
584 iCurrentCluster2 = 0;
585 for (iCluster2 = 0; iCluster2 < iCluster1; iCluster2++) {
586 cluster = ((AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(iCluster2))->GetClusterPtr();
588 if (cluster == discardedCluster) continue;
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];
599 // Add contribution from variances
600 globalChi2b += clusterWeightsNB(iCurrentCluster1, iCurrentCluster1) * dX[iCurrentCluster1] * dX[iCurrentCluster1] +
601 clusterWeightsB(iCurrentCluster1, iCurrentCluster1) * dY[iCurrentCluster1] * dY[iCurrentCluster1];
607 trackParamAtCluster->SetLocalChi2(globalChi2 - globalChi2b);
609 trackParamAtCluster = (AliMUONTrackParam*) fTrackParamAtCluster->After(trackParamAtCluster);
615 } else { // without multiple scattering effects
617 AliMUONVCluster *discardedCluster;
619 AliMUONTrackParam* trackParamAtCluster = (AliMUONTrackParam*) fTrackParamAtCluster->First();
620 while (trackParamAtCluster) {
622 discardedCluster = trackParamAtCluster->GetClusterPtr();
625 dX = discardedCluster->GetX() - trackParamAtCluster->GetNonBendingCoor();
626 dY = discardedCluster->GetY() - trackParamAtCluster->GetBendingCoor();
629 trackParamAtCluster->SetLocalChi2(dX * dX / discardedCluster->GetErrX2() + dY * dY / discardedCluster->GetErrY2());
631 trackParamAtCluster = (AliMUONTrackParam*) fTrackParamAtCluster->After(trackParamAtCluster);
640 //__________________________________________________________________________
641 Double_t AliMUONTrack::ComputeGlobalChi2(Bool_t accountForMCS)
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");
649 if (!fTrackParamAtCluster) {
650 AliWarning("no cluster attached to this track");
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);
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);
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];
683 chi2 += ((*fClusterWeightsNonBending)(iCluster1, iCluster1) * dX[iCluster1] * dX[iCluster1]) +
684 ((*fClusterWeightsBending)(iCluster1, iCluster1) * dY[iCluster1] * dY[iCluster1]);
691 AliMUONVCluster *cluster;
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();
709 //__________________________________________________________________________
710 Bool_t AliMUONTrack::ComputeClusterWeights(TMatrixD* mcsCovariances)
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");
719 if (!fTrackParamAtCluster) {
720 AliWarning("no cluster attached to this track");
725 Int_t nClusters = GetNClusters();
726 if (!fClusterWeightsNonBending) fClusterWeightsNonBending = new TMatrixD(nClusters,nClusters);
727 if (!fClusterWeightsBending) fClusterWeightsBending = new TMatrixD(nClusters,nClusters);
729 // Compute weights matrices
730 if (!ComputeClusterWeights(*fClusterWeightsNonBending, *fClusterWeightsBending, mcsCovariances)) return kFALSE;
736 //__________________________________________________________________________
737 Bool_t AliMUONTrack::ComputeClusterWeights(TMatrixD& clusterWeightsNB, TMatrixD& clusterWeightsB,
738 TMatrixD* mcsCovariances, AliMUONVCluster* discardedCluster) const
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");
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);
756 // Resize the weights matrices; alocate memory
757 if (discardedCluster) {
758 clusterWeightsNB.ResizeTo(nClusters-1,nClusters-1);
759 clusterWeightsB.ResizeTo(nClusters-1,nClusters-1);
761 clusterWeightsNB.ResizeTo(nClusters,nClusters);
762 clusterWeightsB.ResizeTo(nClusters,nClusters);
766 AliMUONVCluster *cluster1, *cluster2;
767 Int_t iCurrentCluster1, iCurrentCluster2;
769 // Compute the covariance matrices
770 iCurrentCluster1 = 0;
771 for (Int_t iCluster1 = 0; iCluster1 < nClusters; iCluster1++) {
772 cluster1 = ((AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(iCluster1))->GetClusterPtr();
774 if (cluster1 == discardedCluster) continue;
776 // Loop over next clusters
777 iCurrentCluster2 = iCurrentCluster1;
778 for (Int_t iCluster2 = iCluster1; iCluster2 < nClusters; iCluster2++) {
779 cluster2 = ((AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(iCluster2))->GetClusterPtr();
781 if (cluster2 == discardedCluster) continue;
783 // Fill with MCS covariances
784 clusterWeightsNB(iCurrentCluster1, iCurrentCluster2) = (*mcsCovariances)(iCluster1,iCluster2);
786 // Equal contribution from multiple scattering in non bending and bending directions
787 clusterWeightsB(iCurrentCluster1, iCurrentCluster2) = clusterWeightsNB(iCurrentCluster1, iCurrentCluster2);
789 // Add contribution from cluster resolution to diagonal element and symmetrize the matrix
790 if (iCurrentCluster1 == iCurrentCluster2) {
792 // In non bending plane
793 clusterWeightsNB(iCurrentCluster1, iCurrentCluster1) += cluster1->GetErrX2();
795 clusterWeightsB(iCurrentCluster1, iCurrentCluster1) += cluster1->GetErrY2();
799 // In non bending plane
800 clusterWeightsNB(iCurrentCluster2, iCurrentCluster1) = clusterWeightsNB(iCurrentCluster1, iCurrentCluster2);
802 clusterWeightsB(iCurrentCluster2, iCurrentCluster1) = clusterWeightsB(iCurrentCluster1, iCurrentCluster2);
812 // Inversion of covariance matrices to get the weights
813 if (clusterWeightsNB.Determinant() != 0 && clusterWeightsB.Determinant() != 0) {
814 clusterWeightsNB.Invert();
815 clusterWeightsB.Invert();
817 AliWarning(" Determinant = 0");
818 clusterWeightsNB.ResizeTo(0,0);
819 clusterWeightsB.ResizeTo(0,0);
820 if(deleteMCSCov) delete mcsCovariances;
824 if(deleteMCSCov) delete mcsCovariances;
830 //__________________________________________________________________________
831 void AliMUONTrack::ComputeMCSCovariances(TMatrixD& mcsCovariances) const
833 /// Compute the multiple scattering covariance matrix
834 /// (assume that track parameters at each cluster are corrects)
835 AliDebug(1,"Enter ComputeMCSCovariances");
837 // Reset the size of the covariance matrix if needed
838 Int_t nClusters = GetNClusters();
839 if (mcsCovariances.GetNrows() != nClusters) mcsCovariances.ResizeTo(nClusters,nClusters);
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];
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);
855 // look for missing chambers if any
856 currentChamber = trackParamAtCluster->GetClusterPtr()->GetChamberId();
857 while (currentChamber > expectedChamber) {
859 // Save the z position where MCS dispersion is calculated
860 zMCS[size] = AliMUONConstants::DefaultChamberZ(expectedChamber);
862 // Do not take into account MCS in chambers prior the first cluster
865 // Get track parameters at missing chamber z
866 extrapTrackParam = *trackParamAtCluster;
867 AliMUONTrackExtrap::ExtrapToZ(&extrapTrackParam, zMCS[size]);
869 // Save multiple scattering dispersion angle in missing chamber
870 mcsAngle2[size] = AliMUONTrackExtrap::GetMCSAngle2(extrapTrackParam,AliMUONConstants::ChamberThicknessInX0(),1.);
872 } else mcsAngle2[size] = 0.;
878 // Save z position where MCS dispersion is calculated
879 zMCS[size] = trackParamAtCluster->GetZ();
881 // Save multiple scattering dispersion angle in current chamber
882 mcsAngle2[size] = AliMUONTrackExtrap::GetMCSAngle2(*trackParamAtCluster,AliMUONConstants::ChamberThicknessInX0(),1.);
884 // Save indice in zMCS array corresponding to the current cluster
885 indices[iCluster] = size;
887 expectedChamber = currentChamber + 1;
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);
894 // Compute the covariance matrix
895 for (Int_t iCluster1 = 0; iCluster1 < nClusters; iCluster1++) {
897 for (Int_t iCluster2 = iCluster1; iCluster2 < nClusters; iCluster2++) {
899 // Initialization to 0 (diagonal plus upper triangular part)
900 mcsCovariances(iCluster1,iCluster2) = 0.;
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];
907 // Symetrize the matrix
908 mcsCovariances(iCluster2,iCluster1) = mcsCovariances(iCluster1,iCluster2);
919 //__________________________________________________________________________
920 Int_t AliMUONTrack::ClustersInCommon(AliMUONTrack* track) const
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())) {
938 trackParamAtCluster2 = (AliMUONTrackParam*) track->fTrackParamAtCluster->After(trackParamAtCluster2);
939 } // trackParamAtCluster2
940 trackParamAtCluster1 = (AliMUONTrackParam*) this->fTrackParamAtCluster->After(trackParamAtCluster1);
941 } // trackParamAtCluster1
942 return clustersInCommon;
945 //__________________________________________________________________________
946 Double_t AliMUONTrack::GetNormalizedChi2() const
948 /// return the chi2 value divided by the number of degrees of freedom (or 1.e10 if ndf < 0)
950 Double_t numberOfDegFree = (2. * GetNClusters() - 5.);
951 if (numberOfDegFree > 0.) return fGlobalChi2 / numberOfDegFree;
955 //__________________________________________________________________________
956 Bool_t* AliMUONTrack::CompatibleTrack(AliMUONTrack *track, Double_t sigmaCut) const
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
965 Bool_t *compatibleCluster = new Bool_t[AliMUONConstants::NTrackingCh()];
966 for ( Int_t ch = 0; ch < AliMUONConstants::NTrackingCh(); ch++) compatibleCluster[ch] = kFALSE;
968 if (!fTrackParamAtCluster || !this->fTrackParamAtCluster) return compatibleCluster;
970 // Loop over clusters of first track
971 trackParamAtCluster1 = (AliMUONTrackParam*) this->fTrackParamAtCluster->First();
972 while (trackParamAtCluster1) {
974 cluster1 = trackParamAtCluster1->GetClusterPtr();
976 // Loop over clusters of second track
977 trackParamAtCluster2 = (AliMUONTrackParam*) track->fTrackParamAtCluster->First();
978 while (trackParamAtCluster2) {
980 cluster2 = trackParamAtCluster2->GetClusterPtr();
983 trackParamAtCluster2 = (AliMUONTrackParam*) track->fTrackParamAtCluster->After(trackParamAtCluster2);
986 dZ = cluster1->GetZ() - cluster2->GetZ();
987 if (dZ > dZMax) continue;
989 // non bending direction
990 dX = cluster1->GetX() - cluster2->GetX();
991 chi2 = dX * dX / (cluster1->GetErrX2() + cluster2->GetErrX2());
992 if (chi2 > chi2Max) continue;
995 dY = cluster1->GetY() - cluster2->GetY();
996 chi2 = dY * dY / (cluster1->GetErrY2() + cluster2->GetErrY2());
997 if (chi2 > chi2Max) continue;
999 compatibleCluster[cluster1->GetChamberId()] = kTRUE;
1003 trackParamAtCluster1 = (AliMUONTrackParam*) this->fTrackParamAtCluster->After(trackParamAtCluster1);
1006 return compatibleCluster;
1009 //__________________________________________________________________________
1010 void AliMUONTrack::SetTrackParamAtVertex(const AliMUONTrackParam* trackParam)
1012 /// set track parameters at vertex
1013 if (trackParam == 0x0) return;
1014 if (fTrackParamAtVertex) *fTrackParamAtVertex = *trackParam;
1015 else fTrackParamAtVertex = new AliMUONTrackParam(*trackParam);
1018 //__________________________________________________________________________
1019 void AliMUONTrack::RecursiveDump() const
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;
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();
1034 cout << "cluster: " << cluster << endl;
1040 //_____________________________________________-
1041 void AliMUONTrack::Print(Option_t*) const
1043 /// Printing Track information
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");
1053 //__________________________________________________________________________
1054 void AliMUONTrack::SetLocalTrigger(Int_t loCirc, Int_t loStripX, Int_t loStripY, Int_t loDev, Int_t loLpt, Int_t loHpt)
1056 /// pack the local trigger information and store
1058 if (loCirc < 0) return;
1061 fLocalTrigger += loCirc;
1062 fLocalTrigger += loStripX << 8;
1063 fLocalTrigger += loStripY << 13;
1064 fLocalTrigger += loDev << 17;
1065 fLocalTrigger += loLpt << 22;
1066 fLocalTrigger += loHpt << 24;