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 "AliMUONTrackParam.h"
27 #include "AliMUONRawClusterV2.h"
28 #include "AliMUONObjectPair.h"
29 #include "AliMUONConstants.h"
30 #include "AliMUONTrackExtrap.h"
33 #include "AliESDMuonTrack.h"
34 #include "AliESDMuonCluster.h"
39 #include <Riostream.h>
42 ClassImp(AliMUONTrack) // Class implementation in ROOT context
45 //__________________________________________________________________________
46 AliMUONTrack::AliMUONTrack()
48 fTrackParamAtCluster(new TClonesArray("AliMUONTrackParam",10)),
49 fFitWithVertex(kFALSE),
52 fClusterWeightsNonBending(0x0),
53 fClusterWeightsBending(0x0),
58 fChi2MatchTrigger(0.),
60 fTrackParamAtVertex(0x0),
61 fHitsPatternInTrigCh(0),
64 /// Default constructor
65 fTrackParamAtCluster->SetOwner(kTRUE);
66 fVertexErrXY2[0] = 0.;
67 fVertexErrXY2[1] = 0.;
70 //__________________________________________________________________________
71 AliMUONTrack::AliMUONTrack(AliMUONObjectPair *segment)
73 fTrackParamAtCluster(new TClonesArray("AliMUONTrackParam",10)),
74 fFitWithVertex(kFALSE),
77 fClusterWeightsNonBending(0x0),
78 fClusterWeightsBending(0x0),
83 fChi2MatchTrigger(0.),
85 fTrackParamAtVertex(0x0),
86 fHitsPatternInTrigCh(0),
89 /// Constructor from two clusters
90 fTrackParamAtCluster->SetOwner(kTRUE);
92 fVertexErrXY2[0] = 0.;
93 fVertexErrXY2[1] = 0.;
95 // Pointers to clusters from the segment
96 AliMUONVCluster* cluster1 = (AliMUONVCluster*) segment->First();
97 AliMUONVCluster* cluster2 = (AliMUONVCluster*) segment->Second();
99 // check sorting in -Z (spectro z<0)
100 if (cluster1->GetZ() < cluster2->GetZ()) {
102 cluster2 = (AliMUONVCluster*) segment->First();
105 // order the clusters into the track according to the station the segment belong to
106 //(the cluster first attached is the one from which we will start the tracking procedure)
107 AliMUONVCluster *firstCluster, *lastCluster;
108 if (cluster1->GetChamberId() == 8) {
109 firstCluster = cluster1;
110 lastCluster = cluster2;
112 firstCluster = cluster2;
113 lastCluster = cluster1;
116 // Compute track parameters
117 Double_t z1 = firstCluster->GetZ();
118 Double_t z2 = lastCluster->GetZ();
119 Double_t dZ = z1 - z2;
121 Double_t nonBendingCoor1 = firstCluster->GetX();
122 Double_t nonBendingCoor2 = lastCluster->GetX();
123 Double_t nonBendingSlope = (nonBendingCoor1 - nonBendingCoor2) / dZ;
125 Double_t bendingCoor1 = firstCluster->GetY();
126 Double_t bendingCoor2 = lastCluster->GetY();
127 Double_t bendingSlope = (bendingCoor1 - bendingCoor2) / dZ;
128 // Inverse bending momentum
129 Double_t bendingImpact = bendingCoor1 - z1 * bendingSlope;
130 Double_t inverseBendingMomentum = 1. / AliMUONTrackExtrap::GetBendingMomentumFromImpactParam(bendingImpact);
133 // Set track parameters at first cluster
134 AliMUONTrackParam trackParamAtFirstCluster;
135 trackParamAtFirstCluster.SetZ(z1);
136 trackParamAtFirstCluster.SetNonBendingCoor(nonBendingCoor1);
137 trackParamAtFirstCluster.SetNonBendingSlope(nonBendingSlope);
138 trackParamAtFirstCluster.SetBendingCoor(bendingCoor1);
139 trackParamAtFirstCluster.SetBendingSlope(bendingSlope);
140 trackParamAtFirstCluster.SetInverseBendingMomentum(inverseBendingMomentum);
143 // Set track parameters at last cluster
144 AliMUONTrackParam trackParamAtLastCluster;
145 trackParamAtLastCluster.SetZ(z2);
146 trackParamAtLastCluster.SetNonBendingCoor(nonBendingCoor2);
147 trackParamAtLastCluster.SetNonBendingSlope(nonBendingSlope);
148 trackParamAtLastCluster.SetBendingCoor(bendingCoor2);
149 trackParamAtLastCluster.SetBendingSlope(bendingSlope);
150 trackParamAtLastCluster.SetInverseBendingMomentum(inverseBendingMomentum);
153 // Compute and set track parameters covariances at first cluster
154 TMatrixD paramCov1(5,5);
157 paramCov1(0,0) = firstCluster->GetErrX2();
158 paramCov1(0,1) = firstCluster->GetErrX2() / dZ;
159 paramCov1(1,0) = paramCov1(0,1);
160 paramCov1(1,1) = ( firstCluster->GetErrX2() + lastCluster->GetErrX2() ) / dZ / dZ;
162 paramCov1(2,2) = firstCluster->GetErrY2();
163 paramCov1(2,3) = firstCluster->GetErrY2() / dZ;
164 paramCov1(3,2) = paramCov1(2,3);
165 paramCov1(3,3) = ( firstCluster->GetErrY2() + lastCluster->GetErrY2() ) / dZ / dZ;
166 // Inverse bending momentum (50% error)
167 paramCov1(4,4) = 0.5*inverseBendingMomentum * 0.5*inverseBendingMomentum;
169 trackParamAtFirstCluster.SetCovariances(paramCov1);
172 // Compute and set track parameters covariances at last cluster (as if the first cluster did not exist)
173 TMatrixD paramCov2(5,5);
176 paramCov2(0,0) = paramCov1(0,0);
177 paramCov2(1,1) = 100.*paramCov1(1,1);
179 paramCov2(2,2) = paramCov1(2,2);
180 paramCov2(3,3) = 100.*paramCov1(3,3);
181 // Inverse bending momentum
182 paramCov2(4,4) = paramCov1(4,4);
184 trackParamAtLastCluster.SetCovariances(paramCov2);
186 // Flag clusters as being removable
187 trackParamAtFirstCluster.SetRemovable(kTRUE);
188 trackParamAtLastCluster.SetRemovable(kTRUE);
190 // Add track parameters at clusters
191 AddTrackParamAtCluster(trackParamAtFirstCluster,*firstCluster);
192 AddTrackParamAtCluster(trackParamAtLastCluster,*lastCluster);
196 //__________________________________________________________________________
197 AliMUONTrack::AliMUONTrack(AliESDMuonTrack &esdTrack)
199 fTrackParamAtCluster(new TClonesArray("AliMUONTrackParam",10)),
200 fFitWithVertex(kFALSE),
203 fClusterWeightsNonBending(0x0),
204 fClusterWeightsBending(0x0),
205 fGlobalChi2(esdTrack.GetChi2()),
207 fMatchTrigger(esdTrack.GetMatchTrigger()),
209 fChi2MatchTrigger(esdTrack.GetChi2MatchTrigger()),
211 fTrackParamAtVertex(new AliMUONTrackParam()),
212 fHitsPatternInTrigCh(esdTrack.GetHitsPatternInTrigCh()),
215 /// Constructor from ESD muon track
216 /// Compute track parameters and covariances at each cluster if available
217 /// or store parameters and covariances at first (fake) cluster only if not
219 fTrackParamAtCluster->SetOwner(kTRUE);
221 fVertexErrXY2[0] = 0.;
222 fVertexErrXY2[1] = 0.;
225 SetLocalTrigger(esdTrack.LoCircuit(), esdTrack.LoStripX(), esdTrack.LoStripY(),
226 esdTrack.LoDev(), esdTrack.LoLpt(), esdTrack.LoHpt());
228 // track parameters at vertex
229 fTrackParamAtVertex->GetParamFrom(esdTrack);
231 // track parameters at first cluster
232 AliMUONTrackParam param;
233 param.GetParamFromUncorrected(esdTrack);
234 param.GetCovFrom(esdTrack);
236 // fill fTrackParamAtCluster with track parameters at each cluster if available
237 if(esdTrack.ClustersStored()) {
239 AliMUONRawClusterV2 cluster;
241 // loop over ESD clusters
242 AliESDMuonCluster *esdCluster = (AliESDMuonCluster*) esdTrack.GetClusters().First();
245 // copy cluster information
246 cluster.SetUniqueID(esdCluster->GetUniqueID());
247 cluster.SetXYZ(esdCluster->GetX(), esdCluster->GetY(), esdCluster->GetZ());
248 cluster.SetErrXY(esdCluster->GetErrX(), esdCluster->GetErrY());
250 // only set the Z parameter to avoid error in the AddTrackParamAtCluster(...) method
251 param.SetZ(cluster.GetZ());
253 // add common track parameters at current cluster
254 AddTrackParamAtCluster(param, cluster, kTRUE);
256 esdCluster = (AliESDMuonCluster*) esdTrack.GetClusters().After(esdCluster);
259 // sort array of track parameters at clusters
260 fTrackParamAtCluster->Sort();
262 // check that parameters stored in ESD are parameters at the most upstream cluster
263 // (convert Z position values to Float_t because of Double32_t in ESD track)
264 AliMUONTrackParam *firstTrackParam = (AliMUONTrackParam*) fTrackParamAtCluster->First();
265 if (((Float_t)firstTrackParam->GetZ()) != ((Float_t)esdTrack.GetZUncorrected())) {
267 AliError("track parameters are not given at the most upstream stored cluster");
268 fTrackParamAtCluster->Clear("C");
272 // Compute track parameters and covariances at each cluster from info at the first one
273 UpdateCovTrackParamAtCluster();
279 // fill fTrackParamAtCluster with track parameters at first (fake) cluster
280 // if first cluster not found or clusters not available
281 if (GetNClusters() == 0) {
283 // get number of the first hit chamber (according to the MUONClusterMap if not empty)
285 if (esdTrack.GetMuonClusterMap() != 0) while (!esdTrack.IsInMuonClusterMap(firstCh)) firstCh++;
286 else firstCh = AliMUONConstants::ChamberNumber(param.GetZ());
288 // produce fake cluster at this chamber
289 AliMUONRawClusterV2 fakeCluster(firstCh, 0, 0);
290 fakeCluster.SetXYZ(param.GetNonBendingCoor(), param.GetBendingCoor(), param.GetZ());
291 fakeCluster.SetErrXY(0., 0.);
293 // add track parameters at first (fake) cluster
294 AddTrackParamAtCluster(param, fakeCluster, kTRUE);
300 //__________________________________________________________________________
301 AliMUONTrack::AliMUONTrack(const AliMUONTrack& track)
303 fTrackParamAtCluster(new TClonesArray("AliMUONTrackParam",10)),
304 fFitWithVertex(track.fFitWithVertex),
306 fFitWithMCS(track.fFitWithMCS),
307 fClusterWeightsNonBending(0x0),
308 fClusterWeightsBending(0x0),
309 fGlobalChi2(track.fGlobalChi2),
310 fImproved(track.fImproved),
311 fMatchTrigger(track.fMatchTrigger),
312 floTrgNum(track.floTrgNum),
313 fChi2MatchTrigger(track.fChi2MatchTrigger),
314 fTrackID(track.fTrackID),
315 fTrackParamAtVertex(0x0),
316 fHitsPatternInTrigCh(track.fHitsPatternInTrigCh),
317 fLocalTrigger(track.fLocalTrigger)
321 // necessary to make a copy of the objects and not only the pointers in TClonesArray.
322 AliMUONTrackParam *trackParamAtCluster = (AliMUONTrackParam*) track.fTrackParamAtCluster->First();
323 while (trackParamAtCluster) {
324 new ((*fTrackParamAtCluster)[GetNClusters()]) AliMUONTrackParam(*trackParamAtCluster);
325 trackParamAtCluster = (AliMUONTrackParam*) track.fTrackParamAtCluster->After(trackParamAtCluster);
328 // copy vertex resolution square used during the tracking procedure
329 fVertexErrXY2[0] = track.fVertexErrXY2[0];
330 fVertexErrXY2[1] = track.fVertexErrXY2[1];
332 // copy cluster weights matrices if any
333 if (track.fClusterWeightsNonBending) fClusterWeightsNonBending = new TMatrixD(*(track.fClusterWeightsNonBending));
334 if (track.fClusterWeightsBending) fClusterWeightsBending = new TMatrixD(*(track.fClusterWeightsBending));
336 // copy track parameters at vertex if any
337 if (track.fTrackParamAtVertex) fTrackParamAtVertex = new AliMUONTrackParam(*(track.fTrackParamAtVertex));
341 //__________________________________________________________________________
342 AliMUONTrack & AliMUONTrack::operator=(const AliMUONTrack& track)
344 /// Asignment operator
345 // check assignement to self
349 // base class assignement
350 TObject::operator=(track);
352 // necessary to make a copy of the objects and not only the pointers in TClonesArray.
353 fTrackParamAtCluster = new TClonesArray("AliMUONTrackParam",10);
354 AliMUONTrackParam *trackParamAtCluster = (AliMUONTrackParam*) track.fTrackParamAtCluster->First();
355 while (trackParamAtCluster) {
356 new ((*fTrackParamAtCluster)[GetNClusters()]) AliMUONTrackParam(*trackParamAtCluster);
357 trackParamAtCluster = (AliMUONTrackParam*) track.fTrackParamAtCluster->After(trackParamAtCluster);
360 // copy cluster weights matrix if any
361 if (track.fClusterWeightsNonBending) {
362 if (fClusterWeightsNonBending) {
363 fClusterWeightsNonBending->ResizeTo(*(track.fClusterWeightsNonBending));
364 *fClusterWeightsNonBending = *(track.fClusterWeightsNonBending);
365 } else fClusterWeightsNonBending = new TMatrixD(*(track.fClusterWeightsNonBending));
366 } else if (fClusterWeightsNonBending) {
367 delete fClusterWeightsNonBending;
368 fClusterWeightsNonBending = 0x0;
371 // copy cluster weights matrix if any
372 if (track.fClusterWeightsBending) {
373 if (fClusterWeightsBending) {
374 fClusterWeightsBending->ResizeTo(*(track.fClusterWeightsBending));
375 *fClusterWeightsBending = *(track.fClusterWeightsBending);
376 } else fClusterWeightsBending = new TMatrixD(*(track.fClusterWeightsBending));
377 } else if (fClusterWeightsBending) {
378 delete fClusterWeightsBending;
379 fClusterWeightsBending = 0x0;
382 // copy track parameters at vertex if any
383 if (track.fTrackParamAtVertex) {
384 if (fTrackParamAtVertex) *fTrackParamAtVertex = *(track.fTrackParamAtVertex);
385 else fTrackParamAtVertex = new AliMUONTrackParam(*(track.fTrackParamAtVertex));
386 } else if (fTrackParamAtVertex) {
387 delete fTrackParamAtVertex;
388 fTrackParamAtVertex = 0x0;
391 fFitWithVertex = track.fFitWithVertex;
392 fVertexErrXY2[0] = track.fVertexErrXY2[0];
393 fVertexErrXY2[1] = track.fVertexErrXY2[1];
394 fFitWithMCS = track.fFitWithMCS;
395 fGlobalChi2 = track.fGlobalChi2;
396 fImproved = track.fImproved;
397 fMatchTrigger = track.fMatchTrigger;
398 floTrgNum = track.floTrgNum;
399 fChi2MatchTrigger = track.fChi2MatchTrigger;
400 fTrackID = track.fTrackID;
401 fHitsPatternInTrigCh = track.fHitsPatternInTrigCh;
402 fLocalTrigger = track.fLocalTrigger;
407 //__________________________________________________________________________
408 AliMUONTrack::~AliMUONTrack()
411 delete fTrackParamAtCluster;
412 delete fClusterWeightsNonBending;
413 delete fClusterWeightsBending;
414 delete fTrackParamAtVertex;
417 //__________________________________________________________________________
418 void AliMUONTrack::Clear(Option_t* opt)
421 fTrackParamAtCluster->Clear(opt);
422 delete fClusterWeightsNonBending; fClusterWeightsNonBending = 0x0;
423 delete fClusterWeightsBending; fClusterWeightsBending = 0x0;
424 delete fTrackParamAtVertex; fTrackParamAtVertex = 0x0;
427 //__________________________________________________________________________
428 void AliMUONTrack::AddTrackParamAtCluster(const AliMUONTrackParam &trackParam, AliMUONVCluster &cluster, Bool_t copy)
430 /// Copy given track parameters into a new TrackParamAtCluster
431 /// Link parameters with the associated cluster
432 /// If copy=kTRUE: the cluster is copied then passed the trackParam which become its owner
433 /// otherwise: make sure to do not delete the cluster until it is used by the track
435 // check chamber ID of the associated cluster
436 if (cluster.GetChamberId() < 0 || cluster.GetChamberId() > AliMUONConstants::NTrackingCh()) {
437 AliError(Form("Chamber ID of the associated cluster is not valid (ChamberId=%d)",cluster.GetChamberId()));
441 // check whether track parameters are given at the correct cluster z position
442 if (cluster.GetZ() != trackParam.GetZ()) {
443 AliError("track parameters are given at a different z position than the one of the associated cluster");
447 // add parameters to the array of track parameters
448 AliMUONTrackParam* trackParamAtCluster = new ((*fTrackParamAtCluster)[GetNClusters()]) AliMUONTrackParam(trackParam);
450 // link parameters with the associated cluster or its copy
452 AliMUONVCluster *clusterCopy = static_cast<AliMUONVCluster*>(cluster.Clone());
453 trackParamAtCluster->SetClusterPtr(clusterCopy, kTRUE);
454 } else trackParamAtCluster->SetClusterPtr(&cluster);
457 //__________________________________________________________________________
458 void AliMUONTrack::RemoveTrackParamAtCluster(AliMUONTrackParam *trackParam)
460 /// Remove trackParam from the array of TrackParamAtCluster
461 if (!fTrackParamAtCluster->Remove(trackParam)) {
462 AliWarning("object to remove does not exist in array fTrackParamAtCluster");
466 fTrackParamAtCluster->Compress();
469 //__________________________________________________________________________
470 void AliMUONTrack::UpdateTrackParamAtCluster()
472 /// Update track parameters at each attached cluster
474 if (GetNClusters() == 0) {
475 AliWarning("no cluster attached to the track");
479 AliMUONTrackParam* startingTrackParam = (AliMUONTrackParam*) fTrackParamAtCluster->First();
480 AliMUONTrackParam* trackParamAtCluster = (AliMUONTrackParam*) fTrackParamAtCluster->After(startingTrackParam);
481 while (trackParamAtCluster) {
483 // reset track parameters and their covariances
484 trackParamAtCluster->SetParameters(startingTrackParam->GetParameters());
485 trackParamAtCluster->SetZ(startingTrackParam->GetZ());
487 // extrapolation to the given z
488 AliMUONTrackExtrap::ExtrapToZ(trackParamAtCluster, trackParamAtCluster->GetClusterPtr()->GetZ());
491 startingTrackParam = trackParamAtCluster;
492 trackParamAtCluster = (AliMUONTrackParam*) (fTrackParamAtCluster->After(trackParamAtCluster));
497 //__________________________________________________________________________
498 void AliMUONTrack::UpdateCovTrackParamAtCluster()
500 /// Update track parameters and their covariances at each attached cluster
501 /// Include effects of multiple scattering in chambers
503 if (GetNClusters() == 0) {
504 AliWarning("no cluster attached to the track");
508 AliMUONTrackParam* startingTrackParam = (AliMUONTrackParam*) fTrackParamAtCluster->First();
509 AliMUONTrackParam* trackParamAtCluster = (AliMUONTrackParam*) fTrackParamAtCluster->After(startingTrackParam);
510 Int_t expectedChamber = startingTrackParam->GetClusterPtr()->GetChamberId() + 1;
511 Int_t currentChamber;
512 while (trackParamAtCluster) {
514 // reset track parameters and their covariances
515 trackParamAtCluster->SetParameters(startingTrackParam->GetParameters());
516 trackParamAtCluster->SetZ(startingTrackParam->GetZ());
517 trackParamAtCluster->SetCovariances(startingTrackParam->GetCovariances());
520 AliMUONTrackExtrap::AddMCSEffect(trackParamAtCluster,AliMUONConstants::ChamberThicknessInX0(),1.);
522 // add MCS in missing chambers if any
523 currentChamber = trackParamAtCluster->GetClusterPtr()->GetChamberId();
524 while (currentChamber > expectedChamber) {
525 // extrapolation to the missing chamber
526 AliMUONTrackExtrap::ExtrapToZCov(trackParamAtCluster, AliMUONConstants::DefaultChamberZ(expectedChamber));
528 AliMUONTrackExtrap::AddMCSEffect(trackParamAtCluster,AliMUONConstants::ChamberThicknessInX0(),1.);
532 // extrapolation to the z of the current cluster
533 AliMUONTrackExtrap::ExtrapToZCov(trackParamAtCluster, trackParamAtCluster->GetClusterPtr()->GetZ());
536 expectedChamber = currentChamber + 1;
537 startingTrackParam = trackParamAtCluster;
538 trackParamAtCluster = (AliMUONTrackParam*) (fTrackParamAtCluster->After(trackParamAtCluster));
543 //__________________________________________________________________________
544 Bool_t AliMUONTrack::ComputeLocalChi2(Bool_t accountForMCS)
546 /// Compute each cluster contribution to the chi2 of the track
547 /// accounting for multiple scattering or not according to the flag
548 /// - Also recompute the weight matrices of the attached clusters if accountForMCS=kTRUE
549 /// - Assume that track parameters at each cluster are corrects
550 /// - Return kFALSE if computation failed
552 if (accountForMCS) { // Compute local chi2 taking into account multiple scattering effects
554 // Compute MCS covariance matrix only once
555 Int_t nClusters = GetNClusters();
556 TMatrixD mcsCovariances(nClusters,nClusters);
557 ComputeMCSCovariances(mcsCovariances);
559 // Make sure cluster weights are consistent with following calculations
560 if (!ComputeClusterWeights(&mcsCovariances)) {
561 AliWarning("cannot take into account the multiple scattering effects");
562 return ComputeLocalChi2(kFALSE);
565 // Compute chi2 of the track
566 Double_t globalChi2 = ComputeGlobalChi2(kTRUE);
567 if (globalChi2 < 0.) return kFALSE;
569 // Loop over removable clusters and compute their local chi2
570 AliMUONTrackParam* trackParamAtCluster1;
571 AliMUONVCluster *cluster, *discardedCluster;
572 Int_t iCluster1, iCluster2, iCurrentCluster1, iCurrentCluster2;
573 TMatrixD clusterWeightsNB(nClusters-1,nClusters-1);
574 TMatrixD clusterWeightsB(nClusters-1,nClusters-1);
575 Double_t *dX = new Double_t[nClusters-1];
576 Double_t *dY = new Double_t[nClusters-1];
577 Double_t globalChi2b;
578 AliMUONTrackParam* trackParamAtCluster = (AliMUONTrackParam*) fTrackParamAtCluster->First();
579 while (trackParamAtCluster) {
581 discardedCluster = trackParamAtCluster->GetClusterPtr();
583 // Recompute cluster weights without the current cluster
584 if (!ComputeClusterWeights(clusterWeightsNB, clusterWeightsB, &mcsCovariances, discardedCluster)) {
585 AliWarning("cannot take into account the multiple scattering effects");
588 return ComputeLocalChi2(kFALSE);
591 // Compute track chi2 without the current cluster
593 iCurrentCluster1 = 0;
594 for (iCluster1 = 0; iCluster1 < nClusters ; iCluster1++) {
595 trackParamAtCluster1 = (AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(iCluster1);
596 cluster = trackParamAtCluster1->GetClusterPtr();
598 if (cluster == discardedCluster) continue;
600 // Compute and save residuals
601 dX[iCurrentCluster1] = cluster->GetX() - trackParamAtCluster1->GetNonBendingCoor();
602 dY[iCurrentCluster1] = cluster->GetY() - trackParamAtCluster1->GetBendingCoor();
604 iCurrentCluster2 = 0;
605 for (iCluster2 = 0; iCluster2 < iCluster1; iCluster2++) {
606 cluster = ((AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(iCluster2))->GetClusterPtr();
608 if (cluster == discardedCluster) continue;
610 // Add contribution from covariances
611 globalChi2b += (clusterWeightsNB(iCurrentCluster1, iCurrentCluster2) +
612 clusterWeightsNB(iCurrentCluster2, iCurrentCluster1)) * dX[iCurrentCluster1] * dX[iCurrentCluster2] +
613 (clusterWeightsB(iCurrentCluster1, iCurrentCluster2) +
614 clusterWeightsB(iCurrentCluster2, iCurrentCluster1)) * dY[iCurrentCluster1] * dY[iCurrentCluster2];
619 // Add contribution from variances
620 globalChi2b += clusterWeightsNB(iCurrentCluster1, iCurrentCluster1) * dX[iCurrentCluster1] * dX[iCurrentCluster1] +
621 clusterWeightsB(iCurrentCluster1, iCurrentCluster1) * dY[iCurrentCluster1] * dY[iCurrentCluster1];
627 trackParamAtCluster->SetLocalChi2(globalChi2 - globalChi2b);
629 trackParamAtCluster = (AliMUONTrackParam*) fTrackParamAtCluster->After(trackParamAtCluster);
635 } else { // without multiple scattering effects
637 AliMUONVCluster *discardedCluster;
639 AliMUONTrackParam* trackParamAtCluster = (AliMUONTrackParam*) fTrackParamAtCluster->First();
640 while (trackParamAtCluster) {
642 discardedCluster = trackParamAtCluster->GetClusterPtr();
645 dX = discardedCluster->GetX() - trackParamAtCluster->GetNonBendingCoor();
646 dY = discardedCluster->GetY() - trackParamAtCluster->GetBendingCoor();
649 trackParamAtCluster->SetLocalChi2(dX * dX / discardedCluster->GetErrX2() + dY * dY / discardedCluster->GetErrY2());
651 trackParamAtCluster = (AliMUONTrackParam*) fTrackParamAtCluster->After(trackParamAtCluster);
660 //__________________________________________________________________________
661 Double_t AliMUONTrack::ComputeGlobalChi2(Bool_t accountForMCS)
663 /// Compute the chi2 of the track accounting for multiple scattering or not according to the flag
664 /// - Assume that track parameters at each cluster are corrects
665 /// - Assume the cluster weights matrices are corrects
666 /// - Return negative value if chi2 computation failed
672 // Check the weight matrices. If weight matrices are not available compute chi2 without MCS
673 if (!fClusterWeightsNonBending || !fClusterWeightsBending) {
674 AliWarning("cluster weights including multiple scattering effects are not available\n\t\t --> compute chi2 WITHOUT multiple scattering");
675 return ComputeGlobalChi2(kFALSE);
677 Int_t nClusters = GetNClusters();
678 if (fClusterWeightsNonBending->GetNrows() != nClusters || fClusterWeightsBending->GetNcols() != nClusters) {
679 AliWarning("cluster weights including multiple scattering effects are not available\n\t\t --> compute chi2 WITHOUT multiple scattering");
680 return ComputeGlobalChi2(kFALSE);
684 AliMUONVCluster *cluster;
685 Double_t *dX = new Double_t[nClusters];
686 Double_t *dY = new Double_t[nClusters];
687 AliMUONTrackParam* trackParamAtCluster;
688 for (Int_t iCluster1 = 0; iCluster1 < nClusters; iCluster1++) {
689 trackParamAtCluster = (AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(iCluster1);
690 cluster = trackParamAtCluster->GetClusterPtr();
691 dX[iCluster1] = cluster->GetX() - trackParamAtCluster->GetNonBendingCoor();
692 dY[iCluster1] = cluster->GetY() - trackParamAtCluster->GetBendingCoor();
693 for (Int_t iCluster2 = 0; iCluster2 < iCluster1; iCluster2++) {
694 chi2 += ((*fClusterWeightsNonBending)(iCluster1, iCluster2) + (*fClusterWeightsNonBending)(iCluster2, iCluster1)) * dX[iCluster1] * dX[iCluster2] +
695 ((*fClusterWeightsBending)(iCluster1, iCluster2) + (*fClusterWeightsBending)(iCluster2, iCluster1)) * dY[iCluster1] * dY[iCluster2];
697 chi2 += ((*fClusterWeightsNonBending)(iCluster1, iCluster1) * dX[iCluster1] * dX[iCluster1]) +
698 ((*fClusterWeightsBending)(iCluster1, iCluster1) * dY[iCluster1] * dY[iCluster1]);
705 AliMUONVCluster *cluster;
707 AliMUONTrackParam* trackParamAtCluster;
708 Int_t nClusters = GetNClusters();
709 for (Int_t iCluster = 0; iCluster < nClusters ; iCluster++) {
710 trackParamAtCluster = (AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(iCluster);
711 cluster = trackParamAtCluster->GetClusterPtr();
712 dX = cluster->GetX() - trackParamAtCluster->GetNonBendingCoor();
713 dY = cluster->GetY() - trackParamAtCluster->GetBendingCoor();
714 chi2 += dX * dX / cluster->GetErrX2() + dY * dY / cluster->GetErrY2();
723 //__________________________________________________________________________
724 Bool_t AliMUONTrack::ComputeClusterWeights(TMatrixD* mcsCovariances)
726 /// Compute the weight matrices of the attached clusters, in non bending and bending direction,
727 /// accounting for multiple scattering correlations and cluster resolution
728 /// - Use the provided MCS covariance matrix if any (otherwise build it temporarily)
729 /// - Assume that track parameters at each cluster are corrects
730 /// - Return kFALSE if computation failed
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
754 // Check MCS covariance matrix and recompute it if need
755 Int_t nClusters = GetNClusters();
756 Bool_t deleteMCSCov = kFALSE;
757 if (!mcsCovariances) {
758 mcsCovariances = new TMatrixD(nClusters,nClusters);
759 deleteMCSCov = kTRUE;
760 ComputeMCSCovariances(*mcsCovariances);
763 // Resize the weights matrices; alocate memory
764 if (discardedCluster) {
765 clusterWeightsNB.ResizeTo(nClusters-1,nClusters-1);
766 clusterWeightsB.ResizeTo(nClusters-1,nClusters-1);
768 clusterWeightsNB.ResizeTo(nClusters,nClusters);
769 clusterWeightsB.ResizeTo(nClusters,nClusters);
773 AliMUONVCluster *cluster1, *cluster2;
774 Int_t iCurrentCluster1, iCurrentCluster2;
776 // Compute the covariance matrices
777 iCurrentCluster1 = 0;
778 for (Int_t iCluster1 = 0; iCluster1 < nClusters; iCluster1++) {
779 cluster1 = ((AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(iCluster1))->GetClusterPtr();
781 if (cluster1 == discardedCluster) continue;
783 // Loop over next clusters
784 iCurrentCluster2 = iCurrentCluster1;
785 for (Int_t iCluster2 = iCluster1; iCluster2 < nClusters; iCluster2++) {
786 cluster2 = ((AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(iCluster2))->GetClusterPtr();
788 if (cluster2 == discardedCluster) continue;
790 // Fill with MCS covariances
791 clusterWeightsNB(iCurrentCluster1, iCurrentCluster2) = (*mcsCovariances)(iCluster1,iCluster2);
793 // Equal contribution from multiple scattering in non bending and bending directions
794 clusterWeightsB(iCurrentCluster1, iCurrentCluster2) = clusterWeightsNB(iCurrentCluster1, iCurrentCluster2);
796 // Add contribution from cluster resolution to diagonal element and symmetrize the matrix
797 if (iCurrentCluster1 == iCurrentCluster2) {
799 // In non bending plane
800 clusterWeightsNB(iCurrentCluster1, iCurrentCluster1) += cluster1->GetErrX2();
802 clusterWeightsB(iCurrentCluster1, iCurrentCluster1) += cluster1->GetErrY2();
806 // In non bending plane
807 clusterWeightsNB(iCurrentCluster2, iCurrentCluster1) = clusterWeightsNB(iCurrentCluster1, iCurrentCluster2);
809 clusterWeightsB(iCurrentCluster2, iCurrentCluster1) = clusterWeightsB(iCurrentCluster1, iCurrentCluster2);
819 // Inversion of covariance matrices to get the weights
820 if (clusterWeightsNB.Determinant() != 0 && clusterWeightsB.Determinant() != 0) {
821 clusterWeightsNB.Invert();
822 clusterWeightsB.Invert();
824 AliWarning(" Determinant = 0");
825 clusterWeightsNB.ResizeTo(0,0);
826 clusterWeightsB.ResizeTo(0,0);
827 if(deleteMCSCov) delete mcsCovariances;
831 if(deleteMCSCov) delete mcsCovariances;
837 //__________________________________________________________________________
838 void AliMUONTrack::ComputeMCSCovariances(TMatrixD& mcsCovariances) const
840 /// Compute the multiple scattering covariance matrix
841 /// (assume that track parameters at each cluster are corrects)
843 // Reset the size of the covariance matrix if needed
844 Int_t nClusters = GetNClusters();
845 if (mcsCovariances.GetNrows() != nClusters) mcsCovariances.ResizeTo(nClusters,nClusters);
848 Int_t nChambers = AliMUONConstants::NTrackingCh();
849 AliMUONTrackParam* trackParamAtCluster;
850 AliMUONTrackParam extrapTrackParam;
851 Int_t currentChamber = 0, expectedChamber = 0, size = 0;
852 Double_t *mcsAngle2 = new Double_t[2*nChambers];
853 Double_t *zMCS = new Double_t[2*nChambers];
854 Int_t *indices = new Int_t[2*nClusters];
856 // Compute multiple scattering dispersion angle at each chamber
857 // and save the z position where it is calculated
858 for (Int_t iCluster = 0; iCluster < nClusters; iCluster++) {
859 trackParamAtCluster = (AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(iCluster);
861 // look for missing chambers if any
862 currentChamber = trackParamAtCluster->GetClusterPtr()->GetChamberId();
863 while (currentChamber > expectedChamber) {
865 // Save the z position where MCS dispersion is calculated
866 zMCS[size] = AliMUONConstants::DefaultChamberZ(expectedChamber);
868 // Do not take into account MCS in chambers prior the first cluster
871 // Get track parameters at missing chamber z
872 extrapTrackParam = *trackParamAtCluster;
873 AliMUONTrackExtrap::ExtrapToZ(&extrapTrackParam, zMCS[size]);
875 // Save multiple scattering dispersion angle in missing chamber
876 mcsAngle2[size] = AliMUONTrackExtrap::GetMCSAngle2(extrapTrackParam,AliMUONConstants::ChamberThicknessInX0(),1.);
878 } else mcsAngle2[size] = 0.;
884 // Save z position where MCS dispersion is calculated
885 zMCS[size] = trackParamAtCluster->GetZ();
887 // Save multiple scattering dispersion angle in current chamber
888 mcsAngle2[size] = AliMUONTrackExtrap::GetMCSAngle2(*trackParamAtCluster,AliMUONConstants::ChamberThicknessInX0(),1.);
890 // Save indice in zMCS array corresponding to the current cluster
891 indices[iCluster] = size;
893 expectedChamber = currentChamber + 1;
897 // complete array of z if last cluster is on the last but one chamber
898 if (currentChamber != nChambers-1) zMCS[size++] = AliMUONConstants::DefaultChamberZ(nChambers-1);
900 // Compute the covariance matrix
901 for (Int_t iCluster1 = 0; iCluster1 < nClusters; iCluster1++) {
903 for (Int_t iCluster2 = iCluster1; iCluster2 < nClusters; iCluster2++) {
905 // Initialization to 0 (diagonal plus upper triangular part)
906 mcsCovariances(iCluster1,iCluster2) = 0.;
908 // Compute contribution from multiple scattering in upstream chambers
909 for (Int_t k = 0; k < indices[iCluster1]; k++) {
910 mcsCovariances(iCluster1,iCluster2) += (zMCS[indices[iCluster1]] - zMCS[k]) * (zMCS[indices[iCluster2]] - zMCS[k]) * mcsAngle2[k];
913 // Symetrize the matrix
914 mcsCovariances(iCluster2,iCluster1) = mcsCovariances(iCluster1,iCluster2);
925 //__________________________________________________________________________
926 Int_t AliMUONTrack::ClustersInCommon(AliMUONTrack* track) const
928 /// Returns the number of clusters in common between the current track ("this")
929 /// and the track pointed to by "track".
930 Int_t clustersInCommon = 0;
931 AliMUONTrackParam *trackParamAtCluster1, *trackParamAtCluster2;
932 // Loop over clusters of first track
933 trackParamAtCluster1 = (AliMUONTrackParam*) this->fTrackParamAtCluster->First();
934 while (trackParamAtCluster1) {
935 // Loop over clusters of second track
936 trackParamAtCluster2 = (AliMUONTrackParam*) track->fTrackParamAtCluster->First();
937 while (trackParamAtCluster2) {
938 // Increment "clustersInCommon" if both trackParamAtCluster1 & 2 point to the same cluster
939 if ((trackParamAtCluster1->GetClusterPtr()) == (trackParamAtCluster2->GetClusterPtr())) {
943 trackParamAtCluster2 = (AliMUONTrackParam*) track->fTrackParamAtCluster->After(trackParamAtCluster2);
944 } // trackParamAtCluster2
945 trackParamAtCluster1 = (AliMUONTrackParam*) this->fTrackParamAtCluster->After(trackParamAtCluster1);
946 } // trackParamAtCluster1
947 return clustersInCommon;
950 //__________________________________________________________________________
951 Double_t AliMUONTrack::GetNormalizedChi2() const
953 /// return the chi2 value divided by the number of degrees of freedom (or 1.e10 if ndf < 0)
955 Double_t numberOfDegFree = (2. * GetNClusters() - 5.);
956 if (numberOfDegFree > 0.) return fGlobalChi2 / numberOfDegFree;
960 //__________________________________________________________________________
961 Bool_t* AliMUONTrack::CompatibleTrack(AliMUONTrack *track, Double_t sigmaCut) const
963 /// for each chamber: return kTRUE (kFALSE) if clusters are compatible (not compatible)
964 AliMUONTrackParam *trackParamAtCluster1, *trackParamAtCluster2;
965 AliMUONVCluster *cluster1, *cluster2;
966 Double_t chi2, dX, dY, dZ;
967 Double_t chi2Max = sigmaCut * sigmaCut;
968 Double_t dZMax = 1.; // 1 cm
970 Bool_t *compatibleCluster = new Bool_t[AliMUONConstants::NTrackingCh()];
971 for ( Int_t ch = 0; ch < AliMUONConstants::NTrackingCh(); ch++) compatibleCluster[ch] = kFALSE;
973 // Loop over clusters of first track
974 trackParamAtCluster1 = (AliMUONTrackParam*) this->fTrackParamAtCluster->First();
975 while (trackParamAtCluster1) {
977 cluster1 = trackParamAtCluster1->GetClusterPtr();
979 // Loop over clusters of second track
980 trackParamAtCluster2 = (AliMUONTrackParam*) track->fTrackParamAtCluster->First();
981 while (trackParamAtCluster2) {
983 cluster2 = trackParamAtCluster2->GetClusterPtr();
986 trackParamAtCluster2 = (AliMUONTrackParam*) track->fTrackParamAtCluster->After(trackParamAtCluster2);
989 dZ = cluster1->GetZ() - cluster2->GetZ();
990 if (dZ > dZMax) continue;
992 // non bending direction
993 dX = cluster1->GetX() - cluster2->GetX();
994 chi2 = dX * dX / (cluster1->GetErrX2() + cluster2->GetErrX2());
995 if (chi2 > chi2Max) continue;
998 dY = cluster1->GetY() - cluster2->GetY();
999 chi2 = dY * dY / (cluster1->GetErrY2() + cluster2->GetErrY2());
1000 if (chi2 > chi2Max) continue;
1002 compatibleCluster[cluster1->GetChamberId()] = kTRUE;
1006 trackParamAtCluster1 = (AliMUONTrackParam*) this->fTrackParamAtCluster->After(trackParamAtCluster1);
1009 return compatibleCluster;
1012 //__________________________________________________________________________
1013 void AliMUONTrack::SetTrackParamAtVertex(const AliMUONTrackParam* trackParam)
1015 /// set track parameters at vertex
1016 if (trackParam == 0x0) return;
1017 if (fTrackParamAtVertex) *fTrackParamAtVertex = *trackParam;
1018 else fTrackParamAtVertex = new AliMUONTrackParam(*trackParam);
1021 //__________________________________________________________________________
1022 void AliMUONTrack::RecursiveDump() const
1024 /// Recursive dump of AliMUONTrack, i.e. with dump of trackParamAtCluster and attached clusters
1025 AliMUONTrackParam *trackParamAtCluster;
1026 AliMUONVCluster *cluster;
1027 cout << "Recursive dump of Track: " << this << endl;
1030 for (Int_t iCluster = 0; iCluster < GetNClusters(); iCluster++) {
1031 trackParamAtCluster = (AliMUONTrackParam*) ((*fTrackParamAtCluster)[iCluster]);
1032 // trackParamAtCluster
1033 cout << "trackParamAtCluster: " << trackParamAtCluster << " (index: " << iCluster << ")" << endl;
1034 trackParamAtCluster->Dump();
1035 cluster = trackParamAtCluster->GetClusterPtr();
1037 cout << "cluster: " << cluster << endl;
1043 //_____________________________________________-
1044 void AliMUONTrack::Print(Option_t*) const
1046 /// Printing Track information
1048 cout << "<AliMUONTrack> No.Clusters=" << setw(2) << GetNClusters() <<
1049 ", Match2Trig=" << setw(1) << GetMatchTrigger() <<
1050 ", LoTrgNum=" << setw(3) << GetLoTrgNum() <<
1051 ", Chi2-tracking-trigger=" << setw(8) << setprecision(5) << GetChi2MatchTrigger();
1052 cout << Form(" HitTriggerPattern %x",fHitsPatternInTrigCh) << endl;
1053 fTrackParamAtCluster->First()->Print("FULL");
1056 //__________________________________________________________________________
1057 void AliMUONTrack::SetLocalTrigger(Int_t loCirc, Int_t loStripX, Int_t loStripY, Int_t loDev, Int_t loLpt, Int_t loHpt)
1059 /// pack the local trigger information and store
1061 if (loCirc < 0) return;
1064 fLocalTrigger += loCirc;
1065 fLocalTrigger += loStripX << 8;
1066 fLocalTrigger += loStripY << 13;
1067 fLocalTrigger += loDev << 17;
1068 fLocalTrigger += loLpt << 22;
1069 fLocalTrigger += loHpt << 24;