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 "AliMUONReconstructor.h"
27 #include "AliMUONRecoParam.h"
28 #include "AliMUONVCluster.h"
29 #include "AliMUONVClusterStore.h"
30 #include "AliMUONObjectPair.h"
31 #include "AliMUONConstants.h"
32 #include "AliMUONTrackExtrap.h"
39 #include <Riostream.h>
42 ClassImp(AliMUONTrack) // Class implementation in ROOT context
45 //__________________________________________________________________________
46 AliMUONTrack::AliMUONTrack()
48 fTrackParamAtCluster(0x0),
49 fFitWithVertex(kFALSE),
52 fClusterWeightsNonBending(0x0),
53 fClusterWeightsBending(0x0),
58 fChi2MatchTrigger(0.),
60 fTrackParamAtVertex(0x0),
61 fHitsPatternInTrigCh(0),
64 /// Default constructor
65 fVertexErrXY2[0] = 0.;
66 fVertexErrXY2[1] = 0.;
69 //__________________________________________________________________________
70 AliMUONTrack::AliMUONTrack(AliMUONObjectPair *segment)
72 fTrackParamAtCluster(new TClonesArray("AliMUONTrackParam",10)),
73 fFitWithVertex(kFALSE),
76 fClusterWeightsNonBending(0x0),
77 fClusterWeightsBending(0x0),
82 fChi2MatchTrigger(0.),
84 fTrackParamAtVertex(0x0),
85 fHitsPatternInTrigCh(0),
88 /// Constructor from two clusters
90 fVertexErrXY2[0] = 0.;
91 fVertexErrXY2[1] = 0.;
93 // Pointers to clusters from the segment
94 AliMUONVCluster* firstCluster = (AliMUONVCluster*) segment->First();
95 AliMUONVCluster* lastCluster = (AliMUONVCluster*) segment->Second();
97 // Compute track parameters
98 Double_t z1 = firstCluster->GetZ();
99 Double_t z2 = lastCluster->GetZ();
100 Double_t dZ = z1 - z2;
102 Double_t nonBendingCoor1 = firstCluster->GetX();
103 Double_t nonBendingCoor2 = lastCluster->GetX();
104 Double_t nonBendingSlope = (nonBendingCoor1 - nonBendingCoor2) / dZ;
106 Double_t bendingCoor1 = firstCluster->GetY();
107 Double_t bendingCoor2 = lastCluster->GetY();
108 Double_t bendingSlope = (bendingCoor1 - bendingCoor2) / dZ;
109 // Inverse bending momentum
110 Double_t bendingImpact = bendingCoor1 - z1 * bendingSlope;
111 Double_t inverseBendingMomentum = 1. / AliMUONTrackExtrap::GetBendingMomentumFromImpactParam(bendingImpact);
113 // Set track parameters at first cluster
114 AliMUONTrackParam trackParamAtFirstCluster;
115 trackParamAtFirstCluster.SetZ(z1);
116 trackParamAtFirstCluster.SetNonBendingCoor(nonBendingCoor1);
117 trackParamAtFirstCluster.SetNonBendingSlope(nonBendingSlope);
118 trackParamAtFirstCluster.SetBendingCoor(bendingCoor1);
119 trackParamAtFirstCluster.SetBendingSlope(bendingSlope);
120 trackParamAtFirstCluster.SetInverseBendingMomentum(inverseBendingMomentum);
122 // Set track parameters at last cluster
123 AliMUONTrackParam trackParamAtLastCluster;
124 trackParamAtLastCluster.SetZ(z2);
125 trackParamAtLastCluster.SetNonBendingCoor(nonBendingCoor2);
126 trackParamAtLastCluster.SetNonBendingSlope(nonBendingSlope);
127 trackParamAtLastCluster.SetBendingCoor(bendingCoor2);
128 trackParamAtLastCluster.SetBendingSlope(bendingSlope);
129 trackParamAtLastCluster.SetInverseBendingMomentum(inverseBendingMomentum);
131 // Compute and set track parameters covariances at first cluster
132 TMatrixD paramCov(5,5);
135 paramCov(0,0) = firstCluster->GetErrX2();
136 paramCov(0,1) = firstCluster->GetErrX2() / dZ;
137 paramCov(1,0) = paramCov(0,1);
138 paramCov(1,1) = ( firstCluster->GetErrX2() + lastCluster->GetErrX2() ) / dZ / dZ;
140 paramCov(2,2) = firstCluster->GetErrY2();
141 paramCov(2,3) = firstCluster->GetErrY2() / dZ;
142 paramCov(3,2) = paramCov(2,3);
143 paramCov(3,3) = ( firstCluster->GetErrY2() + lastCluster->GetErrY2() ) / dZ / dZ;
144 // Inverse bending momentum (vertex resolution + bending slope resolution + 10% error on dipole parameters+field)
145 paramCov(4,4) = ((AliMUONReconstructor::GetRecoParam()->GetBendingVertexDispersion() *
146 AliMUONReconstructor::GetRecoParam()->GetBendingVertexDispersion() +
147 (z1 * z1 * lastCluster->GetErrY2() + z2 * z2 * firstCluster->GetErrY2()) / dZ / dZ) /
148 bendingImpact / bendingImpact + 0.1 * 0.1) * inverseBendingMomentum * inverseBendingMomentum;
149 paramCov(2,4) = - z2 * firstCluster->GetErrY2() * inverseBendingMomentum / bendingImpact / dZ;
150 paramCov(4,2) = paramCov(2,4);
151 paramCov(3,4) = - (z1 * lastCluster->GetErrY2() + z2 * firstCluster->GetErrY2()) * inverseBendingMomentum / bendingImpact / dZ / dZ;
152 paramCov(4,3) = paramCov(3,4);
155 trackParamAtFirstCluster.SetCovariances(paramCov);
157 // Compute and set track parameters covariances at last cluster
158 paramCov(1,0) = - paramCov(1,0);
159 paramCov(0,1) = - paramCov(0,1);
160 paramCov(3,2) = - paramCov(3,2);
161 paramCov(2,3) = - paramCov(2,3);
162 paramCov(2,4) = z1 * lastCluster->GetErrY2() * inverseBendingMomentum / bendingImpact / dZ;
163 paramCov(4,2) = paramCov(2,4);
164 trackParamAtLastCluster.SetCovariances(paramCov);
166 // Add track parameters at clusters
167 AddTrackParamAtCluster(trackParamAtFirstCluster,*firstCluster);
168 AddTrackParamAtCluster(trackParamAtLastCluster,*lastCluster);
172 //__________________________________________________________________________
173 AliMUONTrack::AliMUONTrack(const AliMUONTrack& track)
175 fTrackParamAtCluster(0x0),
176 fFitWithVertex(track.fFitWithVertex),
178 fFitWithMCS(track.fFitWithMCS),
179 fClusterWeightsNonBending(0x0),
180 fClusterWeightsBending(0x0),
181 fGlobalChi2(track.fGlobalChi2),
182 fImproved(track.fImproved),
183 fMatchTrigger(track.fMatchTrigger),
184 floTrgNum(track.floTrgNum),
185 fChi2MatchTrigger(track.fChi2MatchTrigger),
186 fTrackID(track.fTrackID),
187 fTrackParamAtVertex(0x0),
188 fHitsPatternInTrigCh(track.fHitsPatternInTrigCh),
189 fLocalTrigger(track.fLocalTrigger)
193 // necessary to make a copy of the objects and not only the pointers in TClonesArray.
194 if (track.fTrackParamAtCluster) {
195 fTrackParamAtCluster = new TClonesArray("AliMUONTrackParam",10);
196 AliMUONTrackParam *trackParamAtCluster = (AliMUONTrackParam*) track.fTrackParamAtCluster->First();
197 while (trackParamAtCluster) {
198 new ((*fTrackParamAtCluster)[GetNClusters()]) AliMUONTrackParam(*trackParamAtCluster);
199 trackParamAtCluster = (AliMUONTrackParam*) track.fTrackParamAtCluster->After(trackParamAtCluster);
203 // copy vertex resolution square used during the tracking procedure
204 fVertexErrXY2[0] = track.fVertexErrXY2[0];
205 fVertexErrXY2[1] = track.fVertexErrXY2[1];
207 // copy cluster weights matrices if any
208 if (track.fClusterWeightsNonBending) fClusterWeightsNonBending = new TMatrixD(*(track.fClusterWeightsNonBending));
209 if (track.fClusterWeightsBending) fClusterWeightsBending = new TMatrixD(*(track.fClusterWeightsBending));
211 // copy track parameters at vertex if any
212 if (track.fTrackParamAtVertex) fTrackParamAtVertex = new AliMUONTrackParam(*(track.fTrackParamAtVertex));
216 //__________________________________________________________________________
217 AliMUONTrack & AliMUONTrack::operator=(const AliMUONTrack& track)
219 /// Asignment operator
220 // check assignement to self
224 // base class assignement
225 TObject::operator=(track);
230 // necessary to make a copy of the objects and not only the pointers in TClonesArray
231 if (track.fTrackParamAtCluster) {
232 fTrackParamAtCluster = new TClonesArray("AliMUONTrackParam",10);
233 AliMUONTrackParam *trackParamAtCluster = (AliMUONTrackParam*) track.fTrackParamAtCluster->First();
234 while (trackParamAtCluster) {
235 new ((*fTrackParamAtCluster)[GetNClusters()]) AliMUONTrackParam(*trackParamAtCluster);
236 trackParamAtCluster = (AliMUONTrackParam*) track.fTrackParamAtCluster->After(trackParamAtCluster);
240 // copy cluster weights matrix if any
241 if (track.fClusterWeightsNonBending) {
242 if (fClusterWeightsNonBending) {
243 fClusterWeightsNonBending->ResizeTo(*(track.fClusterWeightsNonBending));
244 *fClusterWeightsNonBending = *(track.fClusterWeightsNonBending);
245 } else fClusterWeightsNonBending = new TMatrixD(*(track.fClusterWeightsNonBending));
248 // copy cluster weights matrix if any
249 if (track.fClusterWeightsBending) {
250 if (fClusterWeightsBending) {
251 fClusterWeightsBending->ResizeTo(*(track.fClusterWeightsBending));
252 *fClusterWeightsBending = *(track.fClusterWeightsBending);
253 } else fClusterWeightsBending = new TMatrixD(*(track.fClusterWeightsBending));
256 // copy track parameters at vertex if any
257 if (track.fTrackParamAtVertex) {
258 if (fTrackParamAtVertex) *fTrackParamAtVertex = *(track.fTrackParamAtVertex);
259 else fTrackParamAtVertex = new AliMUONTrackParam(*(track.fTrackParamAtVertex));
262 fFitWithVertex = track.fFitWithVertex;
263 fVertexErrXY2[0] = track.fVertexErrXY2[0];
264 fVertexErrXY2[1] = track.fVertexErrXY2[1];
265 fFitWithMCS = track.fFitWithMCS;
266 fGlobalChi2 = track.fGlobalChi2;
267 fImproved = track.fImproved;
268 fMatchTrigger = track.fMatchTrigger;
269 floTrgNum = track.floTrgNum;
270 fChi2MatchTrigger = track.fChi2MatchTrigger;
271 fTrackID = track.fTrackID;
272 fHitsPatternInTrigCh = track.fHitsPatternInTrigCh;
273 fLocalTrigger = track.fLocalTrigger;
278 //__________________________________________________________________________
279 AliMUONTrack::~AliMUONTrack()
282 delete fTrackParamAtCluster;
283 delete fClusterWeightsNonBending;
284 delete fClusterWeightsBending;
285 delete fTrackParamAtVertex;
288 //__________________________________________________________________________
289 void AliMUONTrack::Clear(Option_t* opt)
292 if (opt && opt[0] == 'C' && fTrackParamAtCluster) fTrackParamAtCluster->Clear("C");
294 delete fTrackParamAtCluster;
295 fTrackParamAtCluster = 0x0;
297 delete fClusterWeightsNonBending; fClusterWeightsNonBending = 0x0;
298 delete fClusterWeightsBending; fClusterWeightsBending = 0x0;
299 delete fTrackParamAtVertex; fTrackParamAtVertex = 0x0;
302 //__________________________________________________________________________
303 void AliMUONTrack::Reset()
305 /// Reset to default values
307 fFitWithVertex = kFALSE;
308 fVertexErrXY2[0] = 0.;
309 fVertexErrXY2[1] = 0.;
310 fFitWithMCS = kFALSE;
315 fChi2MatchTrigger = 0.;
317 fHitsPatternInTrigCh = 0;
319 delete fTrackParamAtCluster; fTrackParamAtCluster = 0x0;
320 delete fClusterWeightsNonBending; fClusterWeightsNonBending = 0x0;
321 delete fClusterWeightsBending; fClusterWeightsBending = 0x0;
322 delete fTrackParamAtVertex; fTrackParamAtVertex = 0x0;
325 //__________________________________________________________________________
326 TClonesArray* AliMUONTrack::GetTrackParamAtCluster() const
328 /// return array of track parameters at cluster (create it if needed)
329 if (!fTrackParamAtCluster) fTrackParamAtCluster = new TClonesArray("AliMUONTrackParam",10);
330 return fTrackParamAtCluster;
333 //__________________________________________________________________________
334 void AliMUONTrack::AddTrackParamAtCluster(const AliMUONTrackParam &trackParam, AliMUONVCluster &cluster, Bool_t copy)
336 /// Copy given track parameters into a new TrackParamAtCluster
337 /// Link parameters with the associated cluster
338 /// If copy=kTRUE: the cluster is copied then passed the trackParam which become its owner
339 /// otherwise: make sure to do not delete the cluster until it is used by the track
341 // check chamber ID of the associated cluster
342 if (cluster.GetChamberId() < 0 || cluster.GetChamberId() > AliMUONConstants::NTrackingCh()) {
343 AliError(Form("Chamber ID of the associated cluster is not valid (ChamberId=%d)",cluster.GetChamberId()));
347 // check whether track parameters are given at the correct cluster z position
348 if (cluster.GetZ() != trackParam.GetZ()) {
349 AliError("track parameters are given at a different z position than the one of the associated cluster");
353 // add parameters to the array of track parameters
354 if (!fTrackParamAtCluster) fTrackParamAtCluster = new TClonesArray("AliMUONTrackParam",10);
355 AliMUONTrackParam* trackParamAtCluster = new ((*fTrackParamAtCluster)[GetNClusters()]) AliMUONTrackParam(trackParam);
357 // link parameters with the associated cluster or its copy
359 AliMUONVCluster *clusterCopy = static_cast<AliMUONVCluster*>(cluster.Clone());
360 trackParamAtCluster->SetClusterPtr(clusterCopy, kTRUE);
361 } else trackParamAtCluster->SetClusterPtr(&cluster);
363 // sort the array of track parameters
364 fTrackParamAtCluster->Sort();
367 //__________________________________________________________________________
368 void AliMUONTrack::RemoveTrackParamAtCluster(AliMUONTrackParam *trackParam)
370 /// Remove trackParam from the array of TrackParamAtCluster
371 if (!fTrackParamAtCluster || !fTrackParamAtCluster->Remove(trackParam)) {
372 AliWarning("object to remove does not exist in array fTrackParamAtCluster");
376 fTrackParamAtCluster->Compress();
379 //__________________________________________________________________________
380 void AliMUONTrack::UpdateTrackParamAtCluster()
382 /// Update track parameters at each attached cluster
384 if (GetNClusters() == 0) {
385 AliWarning("no cluster attached to the track");
389 AliMUONTrackParam* startingTrackParam = (AliMUONTrackParam*) fTrackParamAtCluster->First();
390 AliMUONTrackParam* trackParamAtCluster = (AliMUONTrackParam*) fTrackParamAtCluster->After(startingTrackParam);
391 while (trackParamAtCluster) {
393 // reset track parameters and their covariances
394 trackParamAtCluster->SetParameters(startingTrackParam->GetParameters());
395 trackParamAtCluster->SetZ(startingTrackParam->GetZ());
397 // extrapolation to the given z
398 AliMUONTrackExtrap::ExtrapToZ(trackParamAtCluster, trackParamAtCluster->GetClusterPtr()->GetZ());
401 startingTrackParam = trackParamAtCluster;
402 trackParamAtCluster = (AliMUONTrackParam*) (fTrackParamAtCluster->After(trackParamAtCluster));
407 //__________________________________________________________________________
408 void AliMUONTrack::UpdateCovTrackParamAtCluster()
410 /// Update track parameters and their covariances at each attached cluster
411 /// Include effects of multiple scattering in chambers
413 if (GetNClusters() == 0) {
414 AliWarning("no cluster attached to the track");
418 AliMUONTrackParam* startingTrackParam = (AliMUONTrackParam*) fTrackParamAtCluster->First();
419 AliMUONTrackParam* trackParamAtCluster = (AliMUONTrackParam*) fTrackParamAtCluster->After(startingTrackParam);
420 Int_t expectedChamber = startingTrackParam->GetClusterPtr()->GetChamberId() + 1;
421 Int_t currentChamber;
422 while (trackParamAtCluster) {
424 // reset track parameters and their covariances
425 trackParamAtCluster->SetParameters(startingTrackParam->GetParameters());
426 trackParamAtCluster->SetZ(startingTrackParam->GetZ());
427 trackParamAtCluster->SetCovariances(startingTrackParam->GetCovariances());
430 AliMUONTrackExtrap::AddMCSEffect(trackParamAtCluster,AliMUONConstants::ChamberThicknessInX0(),1.);
432 // add MCS in missing chambers if any
433 currentChamber = trackParamAtCluster->GetClusterPtr()->GetChamberId();
434 while (currentChamber > expectedChamber) {
435 // extrapolation to the missing chamber
436 AliMUONTrackExtrap::ExtrapToZCov(trackParamAtCluster, AliMUONConstants::DefaultChamberZ(expectedChamber));
438 AliMUONTrackExtrap::AddMCSEffect(trackParamAtCluster,AliMUONConstants::ChamberThicknessInX0(),1.);
442 // extrapolation to the z of the current cluster
443 AliMUONTrackExtrap::ExtrapToZCov(trackParamAtCluster, trackParamAtCluster->GetClusterPtr()->GetZ());
446 expectedChamber = currentChamber + 1;
447 startingTrackParam = trackParamAtCluster;
448 trackParamAtCluster = (AliMUONTrackParam*) (fTrackParamAtCluster->After(trackParamAtCluster));
453 //__________________________________________________________________________
454 Bool_t AliMUONTrack::IsValid()
456 /// check the validity of the current track (at least one cluster per requested station)
458 Int_t nClusters = GetNClusters();
459 AliMUONTrackParam *trackParam;
460 Int_t currentStation = 0, expectedStation = 0;
462 for (Int_t i = 0; i < nClusters; i++) {
463 trackParam = (AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(i);
465 // skip unrequested stations
466 while (expectedStation < AliMUONConstants::NTrackingSt() &&
467 !AliMUONReconstructor::GetRecoParam()->RequestStation(expectedStation)) expectedStation++;
469 currentStation = trackParam->GetClusterPtr()->GetChamberId()/2;
472 if (currentStation > expectedStation) return kFALSE;
474 // found station --> look for next one
475 if (currentStation == expectedStation) expectedStation++;
479 return expectedStation == AliMUONConstants::NTrackingSt();
483 //__________________________________________________________________________
484 void AliMUONTrack::TagRemovableClusters() {
485 /// Identify clusters that can be removed from the track,
486 /// with the only requirement to have at least 1 cluster per requested station
488 Int_t nClusters = GetNClusters();
489 AliMUONTrackParam *trackParam, *nextTrackParam;
490 Int_t currentCh, nextCh;
492 // reset flags to kFALSE for all clusters in required station
493 for (Int_t i = 0; i < nClusters; i++) {
494 trackParam = (AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(i);
495 if (AliMUONReconstructor::GetRecoParam()->RequestStation(trackParam->GetClusterPtr()->GetChamberId()/2))
496 trackParam->SetRemovable(kFALSE);
497 else trackParam->SetRemovable(kTRUE);
500 // loop over track parameters
501 for (Int_t i = 0; i < nClusters; i++) {
502 trackParam = (AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(i);
504 currentCh = trackParam->GetClusterPtr()->GetChamberId();
506 // loop over next track parameters
507 for (Int_t j = i+1; j < nClusters; j++) {
508 nextTrackParam = (AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(j);
510 nextCh = nextTrackParam->GetClusterPtr()->GetChamberId();
512 // check if the 2 clusters are on the same station
513 if (nextCh/2 != currentCh/2) break;
515 // set clusters in the same station as being removable
516 trackParam->SetRemovable(kTRUE);
517 nextTrackParam->SetRemovable(kTRUE);
525 //__________________________________________________________________________
526 Bool_t AliMUONTrack::ComputeLocalChi2(Bool_t accountForMCS)
528 /// Compute each cluster contribution to the chi2 of the track
529 /// accounting for multiple scattering or not according to the flag
530 /// - Also recompute the weight matrices of the attached clusters if accountForMCS=kTRUE
531 /// - Assume that track parameters at each cluster are corrects
532 /// - Return kFALSE if computation failed
533 AliDebug(1,"Enter ComputeLocalChi2");
535 if (!fTrackParamAtCluster) {
536 AliWarning("no cluster attached to this track");
540 if (accountForMCS) { // Compute local chi2 taking into account multiple scattering effects
542 // Compute MCS covariance matrix only once
543 Int_t nClusters = GetNClusters();
544 TMatrixD mcsCovariances(nClusters,nClusters);
545 ComputeMCSCovariances(mcsCovariances);
547 // Make sure cluster weights are consistent with following calculations
548 if (!ComputeClusterWeights(&mcsCovariances)) {
549 AliWarning("cannot take into account the multiple scattering effects");
550 return ComputeLocalChi2(kFALSE);
553 // Compute chi2 of the track
554 Double_t globalChi2 = ComputeGlobalChi2(kTRUE);
555 if (globalChi2 < 0.) return kFALSE;
557 // Loop over removable clusters and compute their local chi2
558 AliMUONTrackParam* trackParamAtCluster1;
559 AliMUONVCluster *cluster, *discardedCluster;
560 Int_t iCluster1, iCluster2, iCurrentCluster1, iCurrentCluster2;
561 TMatrixD clusterWeightsNB(nClusters-1,nClusters-1);
562 TMatrixD clusterWeightsB(nClusters-1,nClusters-1);
563 Double_t *dX = new Double_t[nClusters-1];
564 Double_t *dY = new Double_t[nClusters-1];
565 Double_t globalChi2b;
566 AliMUONTrackParam* trackParamAtCluster = (AliMUONTrackParam*) fTrackParamAtCluster->First();
567 while (trackParamAtCluster) {
569 discardedCluster = trackParamAtCluster->GetClusterPtr();
571 // Recompute cluster weights without the current cluster
572 if (!ComputeClusterWeights(clusterWeightsNB, clusterWeightsB, &mcsCovariances, discardedCluster)) {
573 AliWarning("cannot take into account the multiple scattering effects");
576 return ComputeLocalChi2(kFALSE);
579 // Compute track chi2 without the current cluster
581 iCurrentCluster1 = 0;
582 for (iCluster1 = 0; iCluster1 < nClusters ; iCluster1++) {
583 trackParamAtCluster1 = (AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(iCluster1);
584 cluster = trackParamAtCluster1->GetClusterPtr();
586 if (cluster == discardedCluster) continue;
588 // Compute and save residuals
589 dX[iCurrentCluster1] = cluster->GetX() - trackParamAtCluster1->GetNonBendingCoor();
590 dY[iCurrentCluster1] = cluster->GetY() - trackParamAtCluster1->GetBendingCoor();
592 iCurrentCluster2 = 0;
593 for (iCluster2 = 0; iCluster2 < iCluster1; iCluster2++) {
594 cluster = ((AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(iCluster2))->GetClusterPtr();
596 if (cluster == discardedCluster) continue;
598 // Add contribution from covariances
599 globalChi2b += (clusterWeightsNB(iCurrentCluster1, iCurrentCluster2) +
600 clusterWeightsNB(iCurrentCluster2, iCurrentCluster1)) * dX[iCurrentCluster1] * dX[iCurrentCluster2] +
601 (clusterWeightsB(iCurrentCluster1, iCurrentCluster2) +
602 clusterWeightsB(iCurrentCluster2, iCurrentCluster1)) * dY[iCurrentCluster1] * dY[iCurrentCluster2];
607 // Add contribution from variances
608 globalChi2b += clusterWeightsNB(iCurrentCluster1, iCurrentCluster1) * dX[iCurrentCluster1] * dX[iCurrentCluster1] +
609 clusterWeightsB(iCurrentCluster1, iCurrentCluster1) * dY[iCurrentCluster1] * dY[iCurrentCluster1];
615 trackParamAtCluster->SetLocalChi2(globalChi2 - globalChi2b);
617 trackParamAtCluster = (AliMUONTrackParam*) fTrackParamAtCluster->After(trackParamAtCluster);
623 } else { // without multiple scattering effects
625 AliMUONVCluster *discardedCluster;
627 AliMUONTrackParam* trackParamAtCluster = (AliMUONTrackParam*) fTrackParamAtCluster->First();
628 while (trackParamAtCluster) {
630 discardedCluster = trackParamAtCluster->GetClusterPtr();
633 dX = discardedCluster->GetX() - trackParamAtCluster->GetNonBendingCoor();
634 dY = discardedCluster->GetY() - trackParamAtCluster->GetBendingCoor();
637 trackParamAtCluster->SetLocalChi2(dX * dX / discardedCluster->GetErrX2() + dY * dY / discardedCluster->GetErrY2());
639 trackParamAtCluster = (AliMUONTrackParam*) fTrackParamAtCluster->After(trackParamAtCluster);
648 //__________________________________________________________________________
649 Double_t AliMUONTrack::ComputeGlobalChi2(Bool_t accountForMCS)
651 /// Compute the chi2 of the track accounting for multiple scattering or not according to the flag
652 /// - Assume that track parameters at each cluster are corrects
653 /// - Assume the cluster weights matrices are corrects
654 /// - Return negative value if chi2 computation failed
655 AliDebug(1,"Enter ComputeGlobalChi2");
657 if (!fTrackParamAtCluster) {
658 AliWarning("no cluster attached to this track");
666 // Check the weight matrices. If weight matrices are not available compute chi2 without MCS
667 if (!fClusterWeightsNonBending || !fClusterWeightsBending) {
668 AliWarning("cluster weights including multiple scattering effects are not available\n\t\t --> compute chi2 WITHOUT multiple scattering");
669 return ComputeGlobalChi2(kFALSE);
671 Int_t nClusters = GetNClusters();
672 if (fClusterWeightsNonBending->GetNrows() != nClusters || fClusterWeightsBending->GetNcols() != nClusters) {
673 AliWarning("cluster weights including multiple scattering effects are not available\n\t\t --> compute chi2 WITHOUT multiple scattering");
674 return ComputeGlobalChi2(kFALSE);
678 AliMUONVCluster *cluster;
679 Double_t *dX = new Double_t[nClusters];
680 Double_t *dY = new Double_t[nClusters];
681 AliMUONTrackParam* trackParamAtCluster;
682 for (Int_t iCluster1 = 0; iCluster1 < nClusters; iCluster1++) {
683 trackParamAtCluster = (AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(iCluster1);
684 cluster = trackParamAtCluster->GetClusterPtr();
685 dX[iCluster1] = cluster->GetX() - trackParamAtCluster->GetNonBendingCoor();
686 dY[iCluster1] = cluster->GetY() - trackParamAtCluster->GetBendingCoor();
687 for (Int_t iCluster2 = 0; iCluster2 < iCluster1; iCluster2++) {
688 chi2 += ((*fClusterWeightsNonBending)(iCluster1, iCluster2) + (*fClusterWeightsNonBending)(iCluster2, iCluster1)) * dX[iCluster1] * dX[iCluster2] +
689 ((*fClusterWeightsBending)(iCluster1, iCluster2) + (*fClusterWeightsBending)(iCluster2, iCluster1)) * dY[iCluster1] * dY[iCluster2];
691 chi2 += ((*fClusterWeightsNonBending)(iCluster1, iCluster1) * dX[iCluster1] * dX[iCluster1]) +
692 ((*fClusterWeightsBending)(iCluster1, iCluster1) * dY[iCluster1] * dY[iCluster1]);
699 AliMUONVCluster *cluster;
701 AliMUONTrackParam* trackParamAtCluster;
702 Int_t nClusters = GetNClusters();
703 for (Int_t iCluster = 0; iCluster < nClusters ; iCluster++) {
704 trackParamAtCluster = (AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(iCluster);
705 cluster = trackParamAtCluster->GetClusterPtr();
706 dX = cluster->GetX() - trackParamAtCluster->GetNonBendingCoor();
707 dY = cluster->GetY() - trackParamAtCluster->GetBendingCoor();
708 chi2 += dX * dX / cluster->GetErrX2() + dY * dY / cluster->GetErrY2();
717 //__________________________________________________________________________
718 Bool_t AliMUONTrack::ComputeClusterWeights(TMatrixD* mcsCovariances)
720 /// Compute the weight matrices of the attached clusters, in non bending and bending direction,
721 /// accounting for multiple scattering correlations and cluster resolution
722 /// - Use the provided MCS covariance matrix if any (otherwise build it temporarily)
723 /// - Assume that track parameters at each cluster are corrects
724 /// - Return kFALSE if computation failed
725 AliDebug(1,"Enter ComputeClusterWeights1");
727 if (!fTrackParamAtCluster) {
728 AliWarning("no cluster attached to this track");
733 Int_t nClusters = GetNClusters();
734 if (!fClusterWeightsNonBending) fClusterWeightsNonBending = new TMatrixD(nClusters,nClusters);
735 if (!fClusterWeightsBending) fClusterWeightsBending = new TMatrixD(nClusters,nClusters);
737 // Compute weights matrices
738 if (!ComputeClusterWeights(*fClusterWeightsNonBending, *fClusterWeightsBending, mcsCovariances)) return kFALSE;
744 //__________________________________________________________________________
745 Bool_t AliMUONTrack::ComputeClusterWeights(TMatrixD& clusterWeightsNB, TMatrixD& clusterWeightsB,
746 TMatrixD* mcsCovariances, AliMUONVCluster* discardedCluster) const
748 /// Compute the weight matrices, in non bending and bending direction,
749 /// of the other attached clusters assuming the discarded one does not exist
750 /// accounting for multiple scattering correlations and cluster resolution
751 /// - Use the provided MCS covariance matrix if any (otherwise build it temporarily)
752 /// - Return kFALSE if computation failed
753 AliDebug(1,"Enter ComputeClusterWeights2");
755 // Check MCS covariance matrix and recompute it if need
756 Int_t nClusters = GetNClusters();
757 Bool_t deleteMCSCov = kFALSE;
758 if (!mcsCovariances) {
759 mcsCovariances = new TMatrixD(nClusters,nClusters);
760 deleteMCSCov = kTRUE;
761 ComputeMCSCovariances(*mcsCovariances);
764 // Resize the weights matrices; alocate memory
765 if (discardedCluster) {
766 clusterWeightsNB.ResizeTo(nClusters-1,nClusters-1);
767 clusterWeightsB.ResizeTo(nClusters-1,nClusters-1);
769 clusterWeightsNB.ResizeTo(nClusters,nClusters);
770 clusterWeightsB.ResizeTo(nClusters,nClusters);
774 AliMUONVCluster *cluster1, *cluster2;
775 Int_t iCurrentCluster1, iCurrentCluster2;
777 // Compute the covariance matrices
778 iCurrentCluster1 = 0;
779 for (Int_t iCluster1 = 0; iCluster1 < nClusters; iCluster1++) {
780 cluster1 = ((AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(iCluster1))->GetClusterPtr();
782 if (cluster1 == discardedCluster) continue;
784 // Loop over next clusters
785 iCurrentCluster2 = iCurrentCluster1;
786 for (Int_t iCluster2 = iCluster1; iCluster2 < nClusters; iCluster2++) {
787 cluster2 = ((AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(iCluster2))->GetClusterPtr();
789 if (cluster2 == discardedCluster) continue;
791 // Fill with MCS covariances
792 clusterWeightsNB(iCurrentCluster1, iCurrentCluster2) = (*mcsCovariances)(iCluster1,iCluster2);
794 // Equal contribution from multiple scattering in non bending and bending directions
795 clusterWeightsB(iCurrentCluster1, iCurrentCluster2) = clusterWeightsNB(iCurrentCluster1, iCurrentCluster2);
797 // Add contribution from cluster resolution to diagonal element and symmetrize the matrix
798 if (iCurrentCluster1 == iCurrentCluster2) {
800 // In non bending plane
801 clusterWeightsNB(iCurrentCluster1, iCurrentCluster1) += cluster1->GetErrX2();
803 clusterWeightsB(iCurrentCluster1, iCurrentCluster1) += cluster1->GetErrY2();
807 // In non bending plane
808 clusterWeightsNB(iCurrentCluster2, iCurrentCluster1) = clusterWeightsNB(iCurrentCluster1, iCurrentCluster2);
810 clusterWeightsB(iCurrentCluster2, iCurrentCluster1) = clusterWeightsB(iCurrentCluster1, iCurrentCluster2);
820 // Inversion of covariance matrices to get the weights
821 if (clusterWeightsNB.Determinant() != 0 && clusterWeightsB.Determinant() != 0) {
822 clusterWeightsNB.Invert();
823 clusterWeightsB.Invert();
825 AliWarning(" Determinant = 0");
826 clusterWeightsNB.ResizeTo(0,0);
827 clusterWeightsB.ResizeTo(0,0);
828 if(deleteMCSCov) delete mcsCovariances;
832 if(deleteMCSCov) delete mcsCovariances;
838 //__________________________________________________________________________
839 void AliMUONTrack::ComputeMCSCovariances(TMatrixD& mcsCovariances) const
841 /// Compute the multiple scattering covariance matrix
842 /// (assume that track parameters at each cluster are corrects)
843 AliDebug(1,"Enter ComputeMCSCovariances");
845 // Reset the size of the covariance matrix if needed
846 Int_t nClusters = GetNClusters();
847 if (mcsCovariances.GetNrows() != nClusters) mcsCovariances.ResizeTo(nClusters,nClusters);
850 Int_t nChambers = AliMUONConstants::NTrackingCh();
851 AliMUONTrackParam* trackParamAtCluster;
852 AliMUONTrackParam extrapTrackParam;
853 Int_t currentChamber = 0, expectedChamber = 0, size = 0;
854 Double_t *mcsAngle2 = new Double_t[2*nChambers];
855 Double_t *zMCS = new Double_t[2*nChambers];
856 Int_t *indices = new Int_t[2*nClusters];
858 // Compute multiple scattering dispersion angle at each chamber
859 // and save the z position where it is calculated
860 for (Int_t iCluster = 0; iCluster < nClusters; iCluster++) {
861 trackParamAtCluster = (AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(iCluster);
863 // look for missing chambers if any
864 currentChamber = trackParamAtCluster->GetClusterPtr()->GetChamberId();
865 while (currentChamber > expectedChamber) {
867 // Save the z position where MCS dispersion is calculated
868 zMCS[size] = AliMUONConstants::DefaultChamberZ(expectedChamber);
870 // Do not take into account MCS in chambers prior the first cluster
873 // Get track parameters at missing chamber z
874 extrapTrackParam = *trackParamAtCluster;
875 AliMUONTrackExtrap::ExtrapToZ(&extrapTrackParam, zMCS[size]);
877 // Save multiple scattering dispersion angle in missing chamber
878 mcsAngle2[size] = AliMUONTrackExtrap::GetMCSAngle2(extrapTrackParam,AliMUONConstants::ChamberThicknessInX0(),1.);
880 } else mcsAngle2[size] = 0.;
886 // Save z position where MCS dispersion is calculated
887 zMCS[size] = trackParamAtCluster->GetZ();
889 // Save multiple scattering dispersion angle in current chamber
890 mcsAngle2[size] = AliMUONTrackExtrap::GetMCSAngle2(*trackParamAtCluster,AliMUONConstants::ChamberThicknessInX0(),1.);
892 // Save indice in zMCS array corresponding to the current cluster
893 indices[iCluster] = size;
895 expectedChamber = currentChamber + 1;
899 // complete array of z if last cluster is on the last but one chamber
900 if (currentChamber != nChambers-1) zMCS[size++] = AliMUONConstants::DefaultChamberZ(nChambers-1);
902 // Compute the covariance matrix
903 for (Int_t iCluster1 = 0; iCluster1 < nClusters; iCluster1++) {
905 for (Int_t iCluster2 = iCluster1; iCluster2 < nClusters; iCluster2++) {
907 // Initialization to 0 (diagonal plus upper triangular part)
908 mcsCovariances(iCluster1,iCluster2) = 0.;
910 // Compute contribution from multiple scattering in upstream chambers
911 for (Int_t k = 0; k < indices[iCluster1]; k++) {
912 mcsCovariances(iCluster1,iCluster2) += (zMCS[indices[iCluster1]] - zMCS[k]) * (zMCS[indices[iCluster2]] - zMCS[k]) * mcsAngle2[k];
915 // Symetrize the matrix
916 mcsCovariances(iCluster2,iCluster1) = mcsCovariances(iCluster1,iCluster2);
927 //__________________________________________________________________________
928 Int_t AliMUONTrack::ClustersInCommon(AliMUONTrack* track) const
930 /// Returns the number of clusters in common between the current track ("this")
931 /// and the track pointed to by "track".
932 if (!fTrackParamAtCluster || !this->fTrackParamAtCluster) return 0;
933 Int_t clustersInCommon = 0;
934 AliMUONTrackParam *trackParamAtCluster1, *trackParamAtCluster2;
935 // Loop over clusters of first track
936 trackParamAtCluster1 = (AliMUONTrackParam*) this->fTrackParamAtCluster->First();
937 while (trackParamAtCluster1) {
938 // Loop over clusters of second track
939 trackParamAtCluster2 = (AliMUONTrackParam*) track->fTrackParamAtCluster->First();
940 while (trackParamAtCluster2) {
941 // Increment "clustersInCommon" if both trackParamAtCluster1 & 2 point to the same cluster
942 if ((trackParamAtCluster1->GetClusterPtr()) == (trackParamAtCluster2->GetClusterPtr())) {
946 trackParamAtCluster2 = (AliMUONTrackParam*) track->fTrackParamAtCluster->After(trackParamAtCluster2);
947 } // trackParamAtCluster2
948 trackParamAtCluster1 = (AliMUONTrackParam*) this->fTrackParamAtCluster->After(trackParamAtCluster1);
949 } // trackParamAtCluster1
950 return clustersInCommon;
953 //__________________________________________________________________________
954 Double_t AliMUONTrack::GetNormalizedChi2() const
956 /// return the chi2 value divided by the number of degrees of freedom (or 1.e10 if ndf < 0)
958 Double_t numberOfDegFree = (2. * GetNClusters() - 5.);
959 if (numberOfDegFree > 0.) return fGlobalChi2 / numberOfDegFree;
960 else return fGlobalChi2; // system is under-constraint
963 //__________________________________________________________________________
964 Bool_t* AliMUONTrack::CompatibleTrack(AliMUONTrack *track, Double_t sigmaCut) const
966 /// for each chamber: return kTRUE (kFALSE) if clusters are compatible (not compatible)
967 AliMUONTrackParam *trackParamAtCluster1, *trackParamAtCluster2;
968 AliMUONVCluster *cluster1, *cluster2;
969 Double_t chi2, dX, dY, dZ;
970 Double_t chi2Max = sigmaCut * sigmaCut;
971 Double_t dZMax = 1.; // 1 cm
973 Bool_t *compatibleCluster = new Bool_t[AliMUONConstants::NTrackingCh()];
974 for ( Int_t ch = 0; ch < AliMUONConstants::NTrackingCh(); ch++) compatibleCluster[ch] = kFALSE;
976 if (!fTrackParamAtCluster || !this->fTrackParamAtCluster) return compatibleCluster;
978 // Loop over clusters of first track
979 trackParamAtCluster1 = (AliMUONTrackParam*) this->fTrackParamAtCluster->First();
980 while (trackParamAtCluster1) {
982 cluster1 = trackParamAtCluster1->GetClusterPtr();
984 // Loop over clusters of second track
985 trackParamAtCluster2 = (AliMUONTrackParam*) track->fTrackParamAtCluster->First();
986 while (trackParamAtCluster2) {
988 cluster2 = trackParamAtCluster2->GetClusterPtr();
991 trackParamAtCluster2 = (AliMUONTrackParam*) track->fTrackParamAtCluster->After(trackParamAtCluster2);
994 dZ = cluster1->GetZ() - cluster2->GetZ();
995 if (dZ > dZMax) continue;
997 // non bending direction
998 dX = cluster1->GetX() - cluster2->GetX();
999 chi2 = dX * dX / (cluster1->GetErrX2() + cluster2->GetErrX2());
1000 if (chi2 > chi2Max) continue;
1002 // bending direction
1003 dY = cluster1->GetY() - cluster2->GetY();
1004 chi2 = dY * dY / (cluster1->GetErrY2() + cluster2->GetErrY2());
1005 if (chi2 > chi2Max) continue;
1007 compatibleCluster[cluster1->GetChamberId()] = kTRUE;
1011 trackParamAtCluster1 = (AliMUONTrackParam*) this->fTrackParamAtCluster->After(trackParamAtCluster1);
1014 return compatibleCluster;
1017 //__________________________________________________________________________
1018 void AliMUONTrack::SetTrackParamAtVertex(const AliMUONTrackParam* trackParam)
1020 /// set track parameters at vertex
1021 if (trackParam == 0x0) return;
1022 if (fTrackParamAtVertex) *fTrackParamAtVertex = *trackParam;
1023 else fTrackParamAtVertex = new AliMUONTrackParam(*trackParam);
1026 //__________________________________________________________________________
1027 void AliMUONTrack::RecursiveDump() const
1029 /// Recursive dump of AliMUONTrack, i.e. with dump of trackParamAtCluster and attached clusters
1030 AliMUONTrackParam *trackParamAtCluster;
1031 AliMUONVCluster *cluster;
1032 cout << "Recursive dump of Track: " << this << endl;
1035 for (Int_t iCluster = 0; iCluster < GetNClusters(); iCluster++) {
1036 trackParamAtCluster = (AliMUONTrackParam*) ((*fTrackParamAtCluster)[iCluster]);
1037 // trackParamAtCluster
1038 cout << "trackParamAtCluster: " << trackParamAtCluster << " (index: " << iCluster << ")" << endl;
1039 trackParamAtCluster->Dump();
1040 cluster = trackParamAtCluster->GetClusterPtr();
1042 cout << "cluster: " << cluster << endl;
1048 //_____________________________________________-
1049 void AliMUONTrack::Print(Option_t*) const
1051 /// Printing Track information
1053 cout << "<AliMUONTrack> No.Clusters=" << setw(2) << GetNClusters() <<
1054 ", Match2Trig=" << setw(1) << GetMatchTrigger() <<
1055 ", LoTrgNum=" << setw(3) << GetLoTrgNum() <<
1056 ", Chi2-tracking-trigger=" << setw(8) << setprecision(5) << GetChi2MatchTrigger();
1057 cout << Form(" HitTriggerPattern %x",fHitsPatternInTrigCh) << endl;
1058 if (fTrackParamAtCluster) fTrackParamAtCluster->First()->Print("FULL");
1061 //__________________________________________________________________________
1062 void AliMUONTrack::SetLocalTrigger(Int_t loCirc, Int_t loStripX, Int_t loStripY, Int_t loDev, Int_t loLpt, Int_t loHpt)
1064 /// pack the local trigger information and store
1066 if (loCirc < 0) return;
1069 fLocalTrigger += loCirc;
1070 fLocalTrigger += loStripX << 8;
1071 fLocalTrigger += loStripY << 13;
1072 fLocalTrigger += loDev << 17;
1073 fLocalTrigger += loLpt << 22;
1074 fLocalTrigger += loHpt << 24;