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