]> git.uio.no Git - u/mrichter/AliRoot.git/blame_incremental - MUON/AliMUONTrack.cxx
- Replace the TClonesArray of AliMUONTrackParam by a TObjArray in
[u/mrichter/AliRoot.git] / MUON / AliMUONTrack.cxx
... / ...
CommitLineData
1/**************************************************************************
2 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
3 * *
4 * Author: The ALICE Off-line Project. *
5 * Contributors are mentioned in the code where appropriate. *
6 * *
7 * Permission to use, copy, modify and distribute this software and its *
8 * documentation strictly for non-commercial purposes is hereby granted *
9 * without fee, provided that the above copyright notice appears in all *
10 * copies and that both the copyright notice and this permission notice *
11 * appear in the supporting documentation. The authors make no claims *
12 * about the suitability of this software for any purpose. It is *
13 * provided "as is" without express or implied warranty. *
14 **************************************************************************/
15
16/* $Id$ */
17
18//-----------------------------------------------------------------------------
19// Class AliMUONTrack
20//-------------------
21// Reconstructed track in ALICE dimuon spectrometer
22//-----------------------------------------------------------------------------
23
24#include "AliMUONTrack.h"
25
26#include "AliMUONReconstructor.h"
27#include "AliMUONVCluster.h"
28#include "AliMUONVClusterStore.h"
29#include "AliMUONObjectPair.h"
30#include "AliMUONTrackExtrap.h"
31#include "AliMUONConstants.h"
32#include "AliMUONTrackParam.h"
33
34#include "AliLog.h"
35
36#include <TMath.h>
37
38#include <Riostream.h>
39
40/// \cond CLASSIMP
41ClassImp(AliMUONTrack) // Class implementation in ROOT context
42/// \endcond
43
44
45const Double_t AliMUONTrack::fgkMaxChi2 = 1.e10; ///< maximum chi2 above which the track can be considered as abnormal
46
47
48//__________________________________________________________________________
49AliMUONTrack::AliMUONTrack()
50 : TObject(),
51 fTrackParamAtCluster(0x0),
52 fFitWithVertex(kFALSE),
53 fVertexErrXY2(),
54 fFitWithMCS(kFALSE),
55 fClusterWeightsNonBending(0x0),
56 fClusterWeightsBending(0x0),
57 fGlobalChi2(-1.),
58 fImproved(kFALSE),
59 fMatchTrigger(-1),
60 fChi2MatchTrigger(0.),
61 fTrackID(-1),
62 fTrackParamAtVertex(0x0),
63 fHitsPatternInTrigCh(0),
64 fLocalTrigger(0),
65 fConnected(kFALSE)
66{
67 /// Default constructor
68 fVertexErrXY2[0] = 0.;
69 fVertexErrXY2[1] = 0.;
70}
71
72 //__________________________________________________________________________
73AliMUONTrack::AliMUONTrack(AliMUONObjectPair *segment, Double_t bendingVertexDispersion)
74 : TObject(),
75 fTrackParamAtCluster(new TObjArray(20)),
76 fFitWithVertex(kFALSE),
77 fVertexErrXY2(),
78 fFitWithMCS(kFALSE),
79 fClusterWeightsNonBending(0x0),
80 fClusterWeightsBending(0x0),
81 fGlobalChi2(0.),
82 fImproved(kFALSE),
83 fMatchTrigger(-1),
84 fChi2MatchTrigger(0.),
85 fTrackID(-1),
86 fTrackParamAtVertex(0x0),
87 fHitsPatternInTrigCh(0),
88 fLocalTrigger(0),
89 fConnected(kFALSE)
90{
91 /// Constructor from two clusters
92
93 fTrackParamAtCluster->SetOwner(kTRUE);
94
95 fVertexErrXY2[0] = 0.;
96 fVertexErrXY2[1] = 0.;
97
98 // Pointers to clusters from the segment
99 AliMUONVCluster* firstCluster = (AliMUONVCluster*) segment->First();
100 AliMUONVCluster* lastCluster = (AliMUONVCluster*) segment->Second();
101
102 // Compute track parameters
103 Double_t z1 = firstCluster->GetZ();
104 Double_t z2 = lastCluster->GetZ();
105 Double_t dZ = z1 - z2;
106 // Non bending plane
107 Double_t nonBendingCoor1 = firstCluster->GetX();
108 Double_t nonBendingCoor2 = lastCluster->GetX();
109 Double_t nonBendingSlope = (nonBendingCoor1 - nonBendingCoor2) / dZ;
110 // Bending plane
111 Double_t bendingCoor1 = firstCluster->GetY();
112 Double_t bendingCoor2 = lastCluster->GetY();
113 Double_t bendingSlope = (bendingCoor1 - bendingCoor2) / dZ;
114 // Inverse bending momentum
115 Double_t bendingImpact = bendingCoor1 - z1 * bendingSlope;
116 Double_t inverseBendingMomentum = 1. / AliMUONTrackExtrap::GetBendingMomentumFromImpactParam(bendingImpact);
117
118 // Set track parameters at first cluster
119 AliMUONTrackParam trackParamAtFirstCluster;
120 trackParamAtFirstCluster.SetZ(z1);
121 trackParamAtFirstCluster.SetNonBendingCoor(nonBendingCoor1);
122 trackParamAtFirstCluster.SetNonBendingSlope(nonBendingSlope);
123 trackParamAtFirstCluster.SetBendingCoor(bendingCoor1);
124 trackParamAtFirstCluster.SetBendingSlope(bendingSlope);
125 trackParamAtFirstCluster.SetInverseBendingMomentum(inverseBendingMomentum);
126
127 // Set track parameters at last cluster
128 AliMUONTrackParam trackParamAtLastCluster;
129 trackParamAtLastCluster.SetZ(z2);
130 trackParamAtLastCluster.SetNonBendingCoor(nonBendingCoor2);
131 trackParamAtLastCluster.SetNonBendingSlope(nonBendingSlope);
132 trackParamAtLastCluster.SetBendingCoor(bendingCoor2);
133 trackParamAtLastCluster.SetBendingSlope(bendingSlope);
134 trackParamAtLastCluster.SetInverseBendingMomentum(inverseBendingMomentum);
135
136 // Compute and set track parameters covariances at first cluster
137 TMatrixD paramCov(5,5);
138 paramCov.Zero();
139 // Non bending plane
140 paramCov(0,0) = firstCluster->GetErrX2();
141 paramCov(0,1) = firstCluster->GetErrX2() / dZ;
142 paramCov(1,0) = paramCov(0,1);
143 paramCov(1,1) = ( firstCluster->GetErrX2() + lastCluster->GetErrX2() ) / dZ / dZ;
144 // Bending plane
145 paramCov(2,2) = firstCluster->GetErrY2();
146 paramCov(2,3) = firstCluster->GetErrY2() / dZ;
147 paramCov(3,2) = paramCov(2,3);
148 paramCov(3,3) = ( firstCluster->GetErrY2() + lastCluster->GetErrY2() ) / dZ / dZ;
149 // Inverse bending momentum (vertex resolution + bending slope resolution + 10% error on dipole parameters+field)
150 if (AliMUONTrackExtrap::IsFieldON()) {
151 paramCov(4,4) = ( ( bendingVertexDispersion*bendingVertexDispersion +
152 (z1 * z1 * lastCluster->GetErrY2() + z2 * z2 * firstCluster->GetErrY2()) / dZ / dZ) /
153 bendingImpact / bendingImpact + 0.1 * 0.1) * inverseBendingMomentum * inverseBendingMomentum ;
154 paramCov(2,4) = - z2 * firstCluster->GetErrY2() * inverseBendingMomentum / bendingImpact / dZ;
155 paramCov(4,2) = paramCov(2,4);
156 paramCov(3,4) = - (z1 * lastCluster->GetErrY2() + z2 * firstCluster->GetErrY2()) * inverseBendingMomentum / bendingImpact / dZ / dZ;
157 paramCov(4,3) = paramCov(3,4);
158 } else paramCov(4,4) = inverseBendingMomentum*inverseBendingMomentum;
159 trackParamAtFirstCluster.SetCovariances(paramCov);
160
161 // Compute and set track parameters covariances at last cluster
162 // Non bending plane
163 paramCov(0,0) = lastCluster->GetErrX2();
164 paramCov(0,1) = - lastCluster->GetErrX2() / dZ;
165 paramCov(1,0) = paramCov(0,1);
166 // Bending plane
167 paramCov(2,2) = lastCluster->GetErrY2();
168 paramCov(2,3) = - lastCluster->GetErrY2() / dZ;
169 paramCov(3,2) = paramCov(2,3);
170 // Inverse bending momentum (vertex resolution + bending slope resolution + 10% error on dipole parameters+field)
171 if (AliMUONTrackExtrap::IsFieldON()) {
172 paramCov(2,4) = z1 * lastCluster->GetErrY2() * inverseBendingMomentum / bendingImpact / dZ;
173 paramCov(4,2) = paramCov(2,4);
174 }
175 trackParamAtLastCluster.SetCovariances(paramCov);
176
177 // Add track parameters at clusters
178 AddTrackParamAtCluster(trackParamAtFirstCluster,*firstCluster);
179 AddTrackParamAtCluster(trackParamAtLastCluster,*lastCluster);
180
181}
182
183//__________________________________________________________________________
184AliMUONTrack::AliMUONTrack(const AliMUONTrack& track)
185 : TObject(track),
186 fTrackParamAtCluster(0x0),
187 fFitWithVertex(track.fFitWithVertex),
188 fVertexErrXY2(),
189 fFitWithMCS(track.fFitWithMCS),
190 fClusterWeightsNonBending(0x0),
191 fClusterWeightsBending(0x0),
192 fGlobalChi2(track.fGlobalChi2),
193 fImproved(track.fImproved),
194 fMatchTrigger(track.fMatchTrigger),
195 fChi2MatchTrigger(track.fChi2MatchTrigger),
196 fTrackID(track.fTrackID),
197 fTrackParamAtVertex(0x0),
198 fHitsPatternInTrigCh(track.fHitsPatternInTrigCh),
199 fLocalTrigger(track.fLocalTrigger),
200 fConnected(track.fConnected)
201{
202 ///copy constructor
203
204 // necessary to make a copy of the objects and not only the pointers in TObjArray.
205 if (track.fTrackParamAtCluster) {
206 fTrackParamAtCluster = new TObjArray(track.fTrackParamAtCluster->GetSize());
207 fTrackParamAtCluster->SetOwner(kTRUE);
208 for (Int_t i = 0; i < track.GetNClusters(); i++)
209 fTrackParamAtCluster->AddLast(new AliMUONTrackParam(*static_cast<AliMUONTrackParam*>(track.fTrackParamAtCluster->UncheckedAt(i))));
210 }
211
212 // copy vertex resolution square used during the tracking procedure
213 fVertexErrXY2[0] = track.fVertexErrXY2[0];
214 fVertexErrXY2[1] = track.fVertexErrXY2[1];
215
216 // copy cluster weights matrices if any
217 if (track.fClusterWeightsNonBending) fClusterWeightsNonBending = new TMatrixD(*(track.fClusterWeightsNonBending));
218 if (track.fClusterWeightsBending) fClusterWeightsBending = new TMatrixD(*(track.fClusterWeightsBending));
219
220 // copy track parameters at vertex if any
221 if (track.fTrackParamAtVertex) fTrackParamAtVertex = new AliMUONTrackParam(*(track.fTrackParamAtVertex));
222
223}
224
225 //__________________________________________________________________________
226AliMUONTrack & AliMUONTrack::operator=(const AliMUONTrack& track)
227{
228 /// Asignment operator
229 // check assignement to self
230 if (this == &track)
231 return *this;
232
233 // base class assignement
234 TObject::operator=(track);
235
236 // clear memory
237 Clear();
238
239 // necessary to make a copy of the objects and not only the pointers in TObjArray
240 if (track.fTrackParamAtCluster) {
241 fTrackParamAtCluster = new TObjArray(track.fTrackParamAtCluster->GetSize());
242 fTrackParamAtCluster->SetOwner(kTRUE);
243 for (Int_t i = 0; i < track.GetNClusters(); i++)
244 fTrackParamAtCluster->AddLast(new AliMUONTrackParam(*static_cast<AliMUONTrackParam*>(track.fTrackParamAtCluster->UncheckedAt(i))));
245 }
246
247 // copy cluster weights matrix if any
248 if (track.fClusterWeightsNonBending) {
249 if (fClusterWeightsNonBending) {
250 fClusterWeightsNonBending->ResizeTo(*(track.fClusterWeightsNonBending));
251 *fClusterWeightsNonBending = *(track.fClusterWeightsNonBending);
252 } else fClusterWeightsNonBending = new TMatrixD(*(track.fClusterWeightsNonBending));
253 }
254
255 // copy cluster weights matrix if any
256 if (track.fClusterWeightsBending) {
257 if (fClusterWeightsBending) {
258 fClusterWeightsBending->ResizeTo(*(track.fClusterWeightsBending));
259 *fClusterWeightsBending = *(track.fClusterWeightsBending);
260 } else fClusterWeightsBending = new TMatrixD(*(track.fClusterWeightsBending));
261 }
262
263 // copy track parameters at vertex if any
264 if (track.fTrackParamAtVertex) {
265 if (fTrackParamAtVertex) *fTrackParamAtVertex = *(track.fTrackParamAtVertex);
266 else fTrackParamAtVertex = new AliMUONTrackParam(*(track.fTrackParamAtVertex));
267 }
268
269 fFitWithVertex = track.fFitWithVertex;
270 fVertexErrXY2[0] = track.fVertexErrXY2[0];
271 fVertexErrXY2[1] = track.fVertexErrXY2[1];
272 fFitWithMCS = track.fFitWithMCS;
273 fGlobalChi2 = track.fGlobalChi2;
274 fImproved = track.fImproved;
275 fMatchTrigger = track.fMatchTrigger;
276 fChi2MatchTrigger = track.fChi2MatchTrigger;
277 fTrackID = track.fTrackID;
278 fHitsPatternInTrigCh = track.fHitsPatternInTrigCh;
279 fLocalTrigger = track.fLocalTrigger;
280 fConnected = track.fConnected;
281
282 return *this;
283}
284
285 //__________________________________________________________________________
286AliMUONTrack::~AliMUONTrack()
287{
288 /// Destructor
289 delete fTrackParamAtCluster;
290 delete fClusterWeightsNonBending;
291 delete fClusterWeightsBending;
292 delete fTrackParamAtVertex;
293}
294
295 //__________________________________________________________________________
296void AliMUONTrack::Clear(Option_t* /*opt*/)
297{
298 /// Clear arrays
299 delete fTrackParamAtCluster; fTrackParamAtCluster = 0x0;
300 delete fClusterWeightsNonBending; fClusterWeightsNonBending = 0x0;
301 delete fClusterWeightsBending; fClusterWeightsBending = 0x0;
302 delete fTrackParamAtVertex; fTrackParamAtVertex = 0x0;
303}
304
305 //__________________________________________________________________________
306void AliMUONTrack::Reset()
307{
308 /// Reset to default values
309 SetUniqueID(0);
310 fFitWithVertex = kFALSE;
311 fVertexErrXY2[0] = 0.;
312 fVertexErrXY2[1] = 0.;
313 fFitWithMCS = kFALSE;
314 fGlobalChi2 = -1.;
315 fImproved = kFALSE;
316 fMatchTrigger = -1;
317 fChi2MatchTrigger = 0.;
318 fTrackID = -1;
319 fHitsPatternInTrigCh = 0;
320 fLocalTrigger = 0;
321 fConnected = kFALSE;
322 delete fTrackParamAtCluster; fTrackParamAtCluster = 0x0;
323 delete fClusterWeightsNonBending; fClusterWeightsNonBending = 0x0;
324 delete fClusterWeightsBending; fClusterWeightsBending = 0x0;
325 delete fTrackParamAtVertex; fTrackParamAtVertex = 0x0;
326}
327
328 //__________________________________________________________________________
329TObjArray* AliMUONTrack::GetTrackParamAtCluster() const
330{
331 /// return array of track parameters at cluster (create it if needed)
332 if (!fTrackParamAtCluster) {
333 fTrackParamAtCluster = new TObjArray(20);
334 fTrackParamAtCluster->SetOwner(kTRUE);
335 }
336 return fTrackParamAtCluster;
337}
338
339 //__________________________________________________________________________
340void AliMUONTrack::AddTrackParamAtCluster(const AliMUONTrackParam &trackParam, AliMUONVCluster &cluster, Bool_t copy)
341{
342 /// Copy given track parameters into a new TrackParamAtCluster
343 /// Link parameters with the associated cluster
344 /// If copy=kTRUE: the cluster is copied then passed the trackParam which become its owner
345 /// otherwise: make sure to do not delete the cluster until it is used by the track
346
347 // check chamber ID of the associated cluster
348 if (cluster.GetChamberId() < 0 || cluster.GetChamberId() > AliMUONConstants::NTrackingCh()) {
349 AliError(Form("Chamber ID of the associated cluster is not valid (ChamberId=%d)",cluster.GetChamberId()));
350 return;
351 }
352
353 // check whether track parameters are given at the correct cluster z position
354 if (cluster.GetZ() != trackParam.GetZ()) {
355 AliError("track parameters are given at a different z position than the one of the associated cluster");
356 return;
357 }
358
359 // add parameters to the array of track parameters
360 if (!fTrackParamAtCluster) {
361 fTrackParamAtCluster = new TObjArray(20);
362 fTrackParamAtCluster->SetOwner(kTRUE);
363 }
364 AliMUONTrackParam* trackParamAtCluster = new AliMUONTrackParam(trackParam);
365 fTrackParamAtCluster->AddLast(trackParamAtCluster);
366
367 // link parameters with the associated cluster or its copy
368 if (copy) {
369 AliMUONVCluster *clusterCopy = static_cast<AliMUONVCluster*>(cluster.Clone());
370 trackParamAtCluster->SetClusterPtr(clusterCopy, kTRUE);
371 } else trackParamAtCluster->SetClusterPtr(&cluster);
372
373 // sort the array of track parameters
374 fTrackParamAtCluster->Sort();
375}
376
377 //__________________________________________________________________________
378void AliMUONTrack::RemoveTrackParamAtCluster(AliMUONTrackParam *trackParam)
379{
380 /// Remove trackParam from the array of TrackParamAtCluster and delete it since the array is owner
381
382 if (fTrackParamAtCluster) {
383
384 AliMUONTrackParam* trackParamAtCluster = static_cast<AliMUONTrackParam*>(fTrackParamAtCluster->Remove(trackParam));
385
386 if (trackParamAtCluster) {
387
388 // clean memory
389 delete trackParamAtCluster;
390
391 // remove hole
392 fTrackParamAtCluster->Compress();
393
394 } else AliWarning("object to remove does not exist in array fTrackParamAtCluster");
395
396 } else AliWarning("array fTrackParamAtCluster does not exist");
397
398}
399
400 //__________________________________________________________________________
401Bool_t AliMUONTrack::UpdateTrackParamAtCluster()
402{
403 /// Update track parameters at each attached cluster
404 /// Return kFALSE in case of failure (i.e. extrapolation problem)
405
406 Int_t nClusters = GetNClusters();
407 if (nClusters == 0) {
408 AliWarning("no cluster attached to the track");
409 return kFALSE;
410 }
411
412 Bool_t extrapStatus = kTRUE;
413 AliMUONTrackParam* startingTrackParam = static_cast<AliMUONTrackParam*>(fTrackParamAtCluster->UncheckedAt(0));
414
415 for (Int_t i = 1; i < nClusters; i++) {
416 AliMUONTrackParam* trackParamAtCluster = static_cast<AliMUONTrackParam*>(fTrackParamAtCluster->UncheckedAt(i));
417
418 // reset track parameters and their covariances
419 trackParamAtCluster->SetParameters(startingTrackParam->GetParameters());
420 trackParamAtCluster->SetZ(startingTrackParam->GetZ());
421
422 // extrapolation to the given z
423 if (!AliMUONTrackExtrap::ExtrapToZ(trackParamAtCluster, trackParamAtCluster->GetClusterPtr()->GetZ())) extrapStatus = kFALSE;
424
425 // prepare next step
426 startingTrackParam = trackParamAtCluster;
427 }
428
429 // set global chi2 to max value in case of problem during track extrapolation
430 if (!extrapStatus) SetGlobalChi2(2.*MaxChi2());
431 return extrapStatus;
432
433}
434
435 //__________________________________________________________________________
436Bool_t AliMUONTrack::UpdateCovTrackParamAtCluster()
437{
438 /// Update track parameters and their covariances at each attached cluster
439 /// Include effects of multiple scattering in chambers
440 /// Return kFALSE in case of failure (i.e. extrapolation problem)
441
442 Int_t nClusters = GetNClusters();
443 if (nClusters == 0) {
444 AliWarning("no cluster attached to the track");
445 return kFALSE;
446 }
447
448 Bool_t extrapStatus = kTRUE;
449 AliMUONTrackParam* startingTrackParam = static_cast<AliMUONTrackParam*>(fTrackParamAtCluster->UncheckedAt(0));
450 Int_t expectedChamber = startingTrackParam->GetClusterPtr()->GetChamberId() + 1;
451 Int_t currentChamber;
452
453 for (Int_t i = 1; i < nClusters; i++) {
454 AliMUONTrackParam* trackParamAtCluster = static_cast<AliMUONTrackParam*>(fTrackParamAtCluster->UncheckedAt(i));
455
456 // reset track parameters and their covariances
457 trackParamAtCluster->SetParameters(startingTrackParam->GetParameters());
458 trackParamAtCluster->SetZ(startingTrackParam->GetZ());
459 trackParamAtCluster->SetCovariances(startingTrackParam->GetCovariances());
460
461 // add MCS effect
462 AliMUONTrackExtrap::AddMCSEffect(trackParamAtCluster,AliMUONConstants::ChamberThicknessInX0(expectedChamber-1),-1.);
463
464 // add MCS in missing chambers if any
465 currentChamber = trackParamAtCluster->GetClusterPtr()->GetChamberId();
466 while (currentChamber > expectedChamber) {
467 // extrapolation to the missing chamber
468 if (!AliMUONTrackExtrap::ExtrapToZCov(trackParamAtCluster, AliMUONConstants::DefaultChamberZ(expectedChamber))) extrapStatus = kFALSE;
469 // add MCS effect
470 AliMUONTrackExtrap::AddMCSEffect(trackParamAtCluster,AliMUONConstants::ChamberThicknessInX0(expectedChamber),-1.);
471 expectedChamber++;
472 }
473
474 // extrapolation to the z of the current cluster
475 if (!AliMUONTrackExtrap::ExtrapToZCov(trackParamAtCluster, trackParamAtCluster->GetClusterPtr()->GetZ())) extrapStatus = kFALSE;
476
477 // prepare next step
478 expectedChamber = currentChamber + 1;
479 startingTrackParam = trackParamAtCluster;
480 }
481
482 // set global chi2 to max value in case of problem during track extrapolation
483 if (!extrapStatus) SetGlobalChi2(2.*MaxChi2());
484 return extrapStatus;
485
486}
487
488 //__________________________________________________________________________
489Bool_t AliMUONTrack::IsValid(UInt_t requestedStationMask, Bool_t request2ChInSameSt45)
490{
491 /// check the validity of the current track:
492 /// at least one cluster per requested station
493 /// and at least 2 chambers in stations 4 & 5 that contain cluster(s)
494 /// + if request2ChInSameSt45 = kTRUE: 2 chambers hit in the same station (4 or 5)
495
496 Int_t nClusters = GetNClusters();
497 AliMUONTrackParam *trackParam;
498 Int_t currentCh, currentSt, previousCh = -1, nChHitInSt4 = 0, nChHitInSt5 = 0;
499 UInt_t presentStationMask(0);
500
501 // first loop over clusters
502 for (Int_t i = 0; i < nClusters; i++) {
503 trackParam = (AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(i);
504
505 currentCh = trackParam->GetClusterPtr()->GetChamberId();
506 currentSt = currentCh/2;
507
508 // build present station mask
509 presentStationMask |= ( 1 << currentSt );
510
511 // count the number of chambers hit in station 4 that contain cluster(s)
512 if (currentSt == 3 && currentCh != previousCh) {
513 nChHitInSt4++;
514 previousCh = currentCh;
515 }
516
517 // count the number of chambers hit in station 5 that contain cluster(s)
518 if (currentSt == 4 && currentCh != previousCh) {
519 nChHitInSt5++;
520 previousCh = currentCh;
521 }
522
523 }
524
525 // at least one cluster per requested station
526 if ((requestedStationMask & presentStationMask) != requestedStationMask) return kFALSE;
527
528 // 2 chambers hit in the same station (4 or 5)
529 if (request2ChInSameSt45) return (nChHitInSt4 == 2 || nChHitInSt5 == 2);
530 // or 2 chambers hit in station 4 & 5 together
531 else return (nChHitInSt4+nChHitInSt5 >= 2);
532
533}
534
535 //__________________________________________________________________________
536void AliMUONTrack::TagRemovableClusters(UInt_t requestedStationMask) {
537 /// Identify clusters that can be removed from the track,
538 /// with the only requirements to have at least 1 cluster per requested station
539 /// and at least 2 chambers over 4 in stations 4 & 5 that contain cluster(s)
540
541 Int_t nClusters = GetNClusters();
542 AliMUONTrackParam *trackParam, *nextTrackParam;
543 Int_t currentCh, nextCh, currentSt, nextSt, previousCh = -1, nChHitInSt45 = 0;
544
545 // first loop over clusters
546 for (Int_t i = 0; i < nClusters; i++) {
547 trackParam = (AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(i);
548
549 currentCh = trackParam->GetClusterPtr()->GetChamberId();
550 currentSt = currentCh/2;
551
552 // reset flags to kFALSE for all clusters in required station
553 if ((1 << currentSt) & requestedStationMask) trackParam->SetRemovable(kFALSE);
554 else trackParam->SetRemovable(kTRUE);
555
556 // count the number of chambers in station 4 & 5 that contain cluster(s)
557 if (currentCh > 5 && currentCh != previousCh) {
558 nChHitInSt45++;
559 previousCh = currentCh;
560 }
561
562 }
563
564 // second loop over clusters
565 for (Int_t i = 0; i < nClusters; i++) {
566 trackParam = (AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(i);
567
568 currentCh = trackParam->GetClusterPtr()->GetChamberId();
569 currentSt = currentCh/2;
570
571 // make sure they are more than 2 clusters in 2 different chambers of stations 4 & 5
572 // but 2 clusters in he same chamber will still be flagged as removable
573 if (nChHitInSt45 < 3 && currentSt > 2) {
574
575 if (i == nClusters-1) {
576
577 trackParam->SetRemovable(kFALSE);
578
579 } else {
580
581 nextTrackParam = (AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(i+1);
582 nextCh = nextTrackParam->GetClusterPtr()->GetChamberId();
583
584 // set clusters in the same chamber as being removable
585 if (nextCh == currentCh) {
586 trackParam->SetRemovable(kTRUE);
587 nextTrackParam->SetRemovable(kTRUE);
588 i++; // skip cluster already checked
589 } else {
590 trackParam->SetRemovable(kFALSE);
591 }
592
593 }
594
595 } else {
596
597 // skip clusters already flag as removable
598 if (trackParam->IsRemovable()) continue;
599
600 // loop over next track parameters
601 for (Int_t j = i+1; j < nClusters; j++) {
602 nextTrackParam = (AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(j);
603
604 nextCh = nextTrackParam->GetClusterPtr()->GetChamberId();
605 nextSt = nextCh/2;
606
607 // set clusters in the same station as being removable
608 if (nextSt == currentSt) {
609 trackParam->SetRemovable(kTRUE);
610 nextTrackParam->SetRemovable(kTRUE);
611 i++; // skip cluster already checked
612 }
613
614 }
615
616 }
617
618 }
619
620}
621
622 //__________________________________________________________________________
623Bool_t AliMUONTrack::ComputeLocalChi2(Bool_t accountForMCS)
624{
625 /// Compute each cluster contribution to the chi2 of the track
626 /// accounting for multiple scattering or not according to the flag
627 /// - Also recompute the weight matrices of the attached clusters if accountForMCS=kTRUE
628 /// - Assume that track parameters at each cluster are corrects
629 /// - Return kFALSE if computation failed
630 AliDebug(1,"Enter ComputeLocalChi2");
631
632 if (!fTrackParamAtCluster) {
633 AliWarning("no cluster attached to this track");
634 return kFALSE;
635 }
636
637 if (accountForMCS) { // Compute local chi2 taking into account multiple scattering effects
638
639 // Compute MCS covariance matrix only once
640 Int_t nClusters = GetNClusters();
641 TMatrixD mcsCovariances(nClusters,nClusters);
642 ComputeMCSCovariances(mcsCovariances);
643
644 // Make sure cluster weights are consistent with following calculations
645 if (!ComputeClusterWeights(&mcsCovariances)) {
646 AliWarning("cannot take into account the multiple scattering effects");
647 return ComputeLocalChi2(kFALSE);
648 }
649
650 // Compute chi2 of the track
651 Double_t globalChi2 = ComputeGlobalChi2(kTRUE);
652 if (globalChi2 < 0.) return kFALSE;
653
654 // Loop over removable clusters and compute their local chi2
655 AliMUONTrackParam* trackParamAtCluster;
656 AliMUONTrackParam* trackParamAtCluster1;
657 AliMUONVCluster *cluster, *discardedCluster;
658 Int_t iCluster1, iCluster2, iCurrentCluster1, iCurrentCluster2;
659 TMatrixD clusterWeightsNB(nClusters-1,nClusters-1);
660 TMatrixD clusterWeightsB(nClusters-1,nClusters-1);
661 Double_t *dX = new Double_t[nClusters-1];
662 Double_t *dY = new Double_t[nClusters-1];
663 Double_t globalChi2b;
664 for (Int_t iCluster = 0; iCluster < nClusters ; iCluster++) {
665 trackParamAtCluster = static_cast<AliMUONTrackParam*>(fTrackParamAtCluster->UncheckedAt(iCluster));
666
667 discardedCluster = trackParamAtCluster->GetClusterPtr();
668
669 // Recompute cluster weights without the current cluster
670 if (!ComputeClusterWeights(clusterWeightsNB, clusterWeightsB, &mcsCovariances, discardedCluster)) {
671 AliWarning("cannot take into account the multiple scattering effects");
672 delete [] dX;
673 delete [] dY;
674 return ComputeLocalChi2(kFALSE);
675 }
676
677 // Compute track chi2 without the current cluster
678 globalChi2b = 0.;
679 iCurrentCluster1 = 0;
680 for (iCluster1 = 0; iCluster1 < nClusters ; iCluster1++) {
681 trackParamAtCluster1 = (AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(iCluster1);
682 cluster = trackParamAtCluster1->GetClusterPtr();
683
684 if (cluster == discardedCluster) continue;
685
686 // Compute and save residuals
687 dX[iCurrentCluster1] = cluster->GetX() - trackParamAtCluster1->GetNonBendingCoor();
688 dY[iCurrentCluster1] = cluster->GetY() - trackParamAtCluster1->GetBendingCoor();
689
690 iCurrentCluster2 = 0;
691 for (iCluster2 = 0; iCluster2 < iCluster1; iCluster2++) {
692 cluster = ((AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(iCluster2))->GetClusterPtr();
693
694 if (cluster == discardedCluster) continue;
695
696 // Add contribution from covariances
697 globalChi2b += (clusterWeightsNB(iCurrentCluster1, iCurrentCluster2) +
698 clusterWeightsNB(iCurrentCluster2, iCurrentCluster1)) * dX[iCurrentCluster1] * dX[iCurrentCluster2] +
699 (clusterWeightsB(iCurrentCluster1, iCurrentCluster2) +
700 clusterWeightsB(iCurrentCluster2, iCurrentCluster1)) * dY[iCurrentCluster1] * dY[iCurrentCluster2];
701
702 iCurrentCluster2++;
703 }
704
705 // Add contribution from variances
706 globalChi2b += clusterWeightsNB(iCurrentCluster1, iCurrentCluster1) * dX[iCurrentCluster1] * dX[iCurrentCluster1] +
707 clusterWeightsB(iCurrentCluster1, iCurrentCluster1) * dY[iCurrentCluster1] * dY[iCurrentCluster1];
708
709 iCurrentCluster1++;
710 }
711
712 // Set local chi2
713 trackParamAtCluster->SetLocalChi2(globalChi2 - globalChi2b);
714 }
715
716 delete [] dX;
717 delete [] dY;
718
719 } else { // without multiple scattering effects
720
721 Int_t nClusters = GetNClusters();
722 AliMUONTrackParam* trackParamAtCluster;
723 AliMUONVCluster *discardedCluster;
724 Double_t dX, dY;
725 for (Int_t iCluster = 0; iCluster < nClusters ; iCluster++) {
726 trackParamAtCluster = static_cast<AliMUONTrackParam*>(fTrackParamAtCluster->UncheckedAt(iCluster));
727
728 discardedCluster = trackParamAtCluster->GetClusterPtr();
729
730 // Compute residuals
731 dX = discardedCluster->GetX() - trackParamAtCluster->GetNonBendingCoor();
732 dY = discardedCluster->GetY() - trackParamAtCluster->GetBendingCoor();
733
734 // Set local chi2
735 trackParamAtCluster->SetLocalChi2(dX * dX / discardedCluster->GetErrX2() + dY * dY / discardedCluster->GetErrY2());
736 }
737
738 }
739
740 return kTRUE;
741
742}
743
744 //__________________________________________________________________________
745Double_t AliMUONTrack::ComputeGlobalChi2(Bool_t accountForMCS)
746{
747 /// Compute the chi2 of the track accounting for multiple scattering or not according to the flag
748 /// - Assume that track parameters at each cluster are corrects
749 /// - Assume the cluster weights matrices are corrects
750 /// - Return a value of chi2 higher than the maximum allowed if computation failed
751 AliDebug(1,"Enter ComputeGlobalChi2");
752
753 if (!fTrackParamAtCluster) {
754 AliWarning("no cluster attached to this track");
755 return 2.*MaxChi2();
756 }
757
758 Double_t chi2 = 0.;
759
760 if (accountForMCS) {
761
762 // Check the weight matrices. If weight matrices are not available compute chi2 without MCS
763 if (!fClusterWeightsNonBending || !fClusterWeightsBending) {
764 AliWarning("cluster weights including multiple scattering effects are not available\n\t\t --> compute chi2 WITHOUT multiple scattering");
765 return ComputeGlobalChi2(kFALSE);
766 }
767 Int_t nClusters = GetNClusters();
768 if (fClusterWeightsNonBending->GetNrows() != nClusters || fClusterWeightsBending->GetNcols() != nClusters) {
769 AliWarning("cluster weights including multiple scattering effects are not available\n\t\t --> compute chi2 WITHOUT multiple scattering");
770 return ComputeGlobalChi2(kFALSE);
771 }
772
773 // Compute chi2
774 AliMUONVCluster *cluster;
775 Double_t *dX = new Double_t[nClusters];
776 Double_t *dY = new Double_t[nClusters];
777 AliMUONTrackParam* trackParamAtCluster;
778 for (Int_t iCluster1 = 0; iCluster1 < nClusters; iCluster1++) {
779 trackParamAtCluster = (AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(iCluster1);
780 cluster = trackParamAtCluster->GetClusterPtr();
781 dX[iCluster1] = cluster->GetX() - trackParamAtCluster->GetNonBendingCoor();
782 dY[iCluster1] = cluster->GetY() - trackParamAtCluster->GetBendingCoor();
783 for (Int_t iCluster2 = 0; iCluster2 < iCluster1; iCluster2++) {
784 chi2 += ((*fClusterWeightsNonBending)(iCluster1, iCluster2) + (*fClusterWeightsNonBending)(iCluster2, iCluster1)) * dX[iCluster1] * dX[iCluster2] +
785 ((*fClusterWeightsBending)(iCluster1, iCluster2) + (*fClusterWeightsBending)(iCluster2, iCluster1)) * dY[iCluster1] * dY[iCluster2];
786 }
787 chi2 += ((*fClusterWeightsNonBending)(iCluster1, iCluster1) * dX[iCluster1] * dX[iCluster1]) +
788 ((*fClusterWeightsBending)(iCluster1, iCluster1) * dY[iCluster1] * dY[iCluster1]);
789 }
790 delete [] dX;
791 delete [] dY;
792
793 } else {
794
795 AliMUONVCluster *cluster;
796 Double_t dX, dY;
797 AliMUONTrackParam* trackParamAtCluster;
798 Int_t nClusters = GetNClusters();
799 for (Int_t iCluster = 0; iCluster < nClusters ; iCluster++) {
800 trackParamAtCluster = (AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(iCluster);
801 cluster = trackParamAtCluster->GetClusterPtr();
802 dX = cluster->GetX() - trackParamAtCluster->GetNonBendingCoor();
803 dY = cluster->GetY() - trackParamAtCluster->GetBendingCoor();
804 chi2 += dX * dX / cluster->GetErrX2() + dY * dY / cluster->GetErrY2();
805 }
806
807 }
808
809 return chi2;
810
811}
812
813 //__________________________________________________________________________
814Bool_t AliMUONTrack::ComputeClusterWeights(TMatrixD* mcsCovariances)
815{
816 /// Compute the weight matrices of the attached clusters, in non bending and bending direction,
817 /// accounting for multiple scattering correlations and cluster resolution
818 /// - Use the provided MCS covariance matrix if any (otherwise build it temporarily)
819 /// - Assume that track parameters at each cluster are corrects
820 /// - Return kFALSE if computation failed
821 AliDebug(1,"Enter ComputeClusterWeights1");
822
823 if (!fTrackParamAtCluster) {
824 AliWarning("no cluster attached to this track");
825 return kFALSE;
826 }
827
828 // Alocate memory
829 Int_t nClusters = GetNClusters();
830 if (!fClusterWeightsNonBending) fClusterWeightsNonBending = new TMatrixD(nClusters,nClusters);
831 if (!fClusterWeightsBending) fClusterWeightsBending = new TMatrixD(nClusters,nClusters);
832
833 // Compute weights matrices
834 if (!ComputeClusterWeights(*fClusterWeightsNonBending, *fClusterWeightsBending, mcsCovariances)) return kFALSE;
835
836 return kTRUE;
837
838}
839
840 //__________________________________________________________________________
841Bool_t AliMUONTrack::ComputeClusterWeights(TMatrixD& clusterWeightsNB, TMatrixD& clusterWeightsB,
842 TMatrixD* mcsCovariances, const AliMUONVCluster* discardedCluster) const
843{
844 /// Compute the weight matrices, in non bending and bending direction,
845 /// of the other attached clusters assuming the discarded one does not exist
846 /// accounting for multiple scattering correlations and cluster resolution
847 /// - Use the provided MCS covariance matrix if any (otherwise build it temporarily)
848 /// - Return kFALSE if computation failed
849 AliDebug(1,"Enter ComputeClusterWeights2");
850
851 // Check MCS covariance matrix and recompute it if need
852 Int_t nClusters = GetNClusters();
853 Bool_t deleteMCSCov = kFALSE;
854 if (!mcsCovariances) {
855 mcsCovariances = new TMatrixD(nClusters,nClusters);
856 deleteMCSCov = kTRUE;
857 ComputeMCSCovariances(*mcsCovariances);
858 }
859
860 // Resize the weights matrices; alocate memory
861 if (discardedCluster) {
862 clusterWeightsNB.ResizeTo(nClusters-1,nClusters-1);
863 clusterWeightsB.ResizeTo(nClusters-1,nClusters-1);
864 } else {
865 clusterWeightsNB.ResizeTo(nClusters,nClusters);
866 clusterWeightsB.ResizeTo(nClusters,nClusters);
867 }
868
869 // Define variables
870 AliMUONVCluster *cluster1, *cluster2;
871 Int_t iCurrentCluster1, iCurrentCluster2;
872
873 // Compute the covariance matrices
874 iCurrentCluster1 = 0;
875 for (Int_t iCluster1 = 0; iCluster1 < nClusters; iCluster1++) {
876 cluster1 = ((AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(iCluster1))->GetClusterPtr();
877
878 if (cluster1 == discardedCluster) continue;
879
880 // Loop over next clusters
881 iCurrentCluster2 = iCurrentCluster1;
882 for (Int_t iCluster2 = iCluster1; iCluster2 < nClusters; iCluster2++) {
883 cluster2 = ((AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(iCluster2))->GetClusterPtr();
884
885 if (cluster2 == discardedCluster) continue;
886
887 // Fill with MCS covariances
888 clusterWeightsNB(iCurrentCluster1, iCurrentCluster2) = (*mcsCovariances)(iCluster1,iCluster2);
889
890 // Equal contribution from multiple scattering in non bending and bending directions
891 clusterWeightsB(iCurrentCluster1, iCurrentCluster2) = clusterWeightsNB(iCurrentCluster1, iCurrentCluster2);
892
893 // Add contribution from cluster resolution to diagonal element and symmetrize the matrix
894 if (iCurrentCluster1 == iCurrentCluster2) {
895
896 // In non bending plane
897 clusterWeightsNB(iCurrentCluster1, iCurrentCluster1) += cluster1->GetErrX2();
898 // In bending plane
899 clusterWeightsB(iCurrentCluster1, iCurrentCluster1) += cluster1->GetErrY2();
900
901 } else {
902
903 // In non bending plane
904 clusterWeightsNB(iCurrentCluster2, iCurrentCluster1) = clusterWeightsNB(iCurrentCluster1, iCurrentCluster2);
905 // In bending plane
906 clusterWeightsB(iCurrentCluster2, iCurrentCluster1) = clusterWeightsB(iCurrentCluster1, iCurrentCluster2);
907
908 }
909
910 iCurrentCluster2++;
911 }
912
913 iCurrentCluster1++;
914 }
915
916 // Inversion of covariance matrices to get the weights
917 if (clusterWeightsNB.Determinant() != 0 && clusterWeightsB.Determinant() != 0) {
918 clusterWeightsNB.Invert();
919 clusterWeightsB.Invert();
920 } else {
921 AliWarning(" Determinant = 0");
922 clusterWeightsNB.ResizeTo(0,0);
923 clusterWeightsB.ResizeTo(0,0);
924 if(deleteMCSCov) delete mcsCovariances;
925 return kFALSE;
926 }
927
928 if(deleteMCSCov) delete mcsCovariances;
929
930 return kTRUE;
931
932}
933
934 //__________________________________________________________________________
935void AliMUONTrack::ComputeMCSCovariances(TMatrixD& mcsCovariances) const
936{
937 /// Compute the multiple scattering covariance matrix
938 /// (assume that track parameters at each cluster are corrects)
939 AliDebug(1,"Enter ComputeMCSCovariances");
940
941 // Reset the size of the covariance matrix if needed
942 Int_t nClusters = GetNClusters();
943 if (mcsCovariances.GetNrows() != nClusters) mcsCovariances.ResizeTo(nClusters,nClusters);
944
945 // Define variables
946 Int_t nChambers = AliMUONConstants::NTrackingCh();
947 AliMUONTrackParam* trackParamAtCluster;
948 AliMUONTrackParam extrapTrackParam;
949 Int_t currentChamber = 0, expectedChamber = 0, size = 0;
950 Double_t *mcsAngle2 = new Double_t[2*nChambers];
951 Double_t *zMCS = new Double_t[2*nChambers];
952 Int_t *indices = new Int_t[2*nClusters];
953
954 // Compute multiple scattering dispersion angle at each chamber
955 // and save the z position where it is calculated
956 for (Int_t iCluster = 0; iCluster < nClusters; iCluster++) {
957 trackParamAtCluster = (AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(iCluster);
958
959 // look for missing chambers if any
960 currentChamber = trackParamAtCluster->GetClusterPtr()->GetChamberId();
961 while (currentChamber > expectedChamber) {
962
963 // Save the z position where MCS dispersion is calculated
964 zMCS[size] = AliMUONConstants::DefaultChamberZ(expectedChamber);
965
966 // Do not take into account MCS in chambers prior the first cluster
967 if (iCluster > 0) {
968
969 // Get track parameters at missing chamber z
970 extrapTrackParam = *trackParamAtCluster;
971 AliMUONTrackExtrap::ExtrapToZ(&extrapTrackParam, zMCS[size]);
972
973 // Save multiple scattering dispersion angle in missing chamber
974 mcsAngle2[size] = AliMUONTrackExtrap::GetMCSAngle2(extrapTrackParam,AliMUONConstants::ChamberThicknessInX0(expectedChamber),1.);
975
976 } else mcsAngle2[size] = 0.;
977
978 expectedChamber++;
979 size++;
980 }
981
982 // Save z position where MCS dispersion is calculated
983 zMCS[size] = trackParamAtCluster->GetZ();
984
985 // Save multiple scattering dispersion angle in current chamber
986 mcsAngle2[size] = AliMUONTrackExtrap::GetMCSAngle2(*trackParamAtCluster,AliMUONConstants::ChamberThicknessInX0(currentChamber),1.);
987
988 // Save indice in zMCS array corresponding to the current cluster
989 indices[iCluster] = size;
990
991 expectedChamber = currentChamber + 1;
992 size++;
993 }
994
995 // complete array of z if last cluster is on the last but one chamber
996 if (currentChamber != nChambers-1) zMCS[size++] = AliMUONConstants::DefaultChamberZ(nChambers-1);
997
998 // Compute the covariance matrix
999 for (Int_t iCluster1 = 0; iCluster1 < nClusters; iCluster1++) {
1000
1001 for (Int_t iCluster2 = iCluster1; iCluster2 < nClusters; iCluster2++) {
1002
1003 // Initialization to 0 (diagonal plus upper triangular part)
1004 mcsCovariances(iCluster1,iCluster2) = 0.;
1005
1006 // Compute contribution from multiple scattering in upstream chambers
1007 for (Int_t k = 0; k < indices[iCluster1]; k++) {
1008 mcsCovariances(iCluster1,iCluster2) += (zMCS[indices[iCluster1]] - zMCS[k]) * (zMCS[indices[iCluster2]] - zMCS[k]) * mcsAngle2[k];
1009 }
1010
1011 // Symetrize the matrix
1012 mcsCovariances(iCluster2,iCluster1) = mcsCovariances(iCluster1,iCluster2);
1013 }
1014
1015 }
1016
1017 delete [] mcsAngle2;
1018 delete [] zMCS;
1019 delete [] indices;
1020
1021}
1022
1023 //__________________________________________________________________________
1024Int_t AliMUONTrack::ClustersInCommon(AliMUONTrack* track, Int_t stMin, Int_t stMax) const
1025{
1026 /// Returns the number of clusters in common in stations [stMin, stMax]
1027 /// between the current track ("this") and the track pointed to by "track".
1028
1029 if (!track || !track->fTrackParamAtCluster || !this->fTrackParamAtCluster) return 0;
1030
1031 Int_t chMin = 2 * stMin;
1032 Int_t chMax = 2 * stMax + 1;
1033 Int_t clustersInCommon = 0;
1034
1035 // Loop over clusters of first track
1036 Int_t nCl1 = this->GetNClusters();
1037 for(Int_t iCl1 = 0; iCl1 < nCl1; iCl1++) {
1038 AliMUONVCluster* cl1 = ((AliMUONTrackParam*) this->fTrackParamAtCluster->UncheckedAt(iCl1))->GetClusterPtr();
1039
1040 Int_t chCl1 = cl1->GetChamberId();
1041 if (chCl1 < chMin || chCl1 > chMax) continue;
1042
1043 // Loop over clusters of second track
1044 Int_t nCl2 = track->GetNClusters();
1045 for(Int_t iCl2 = 0; iCl2 < nCl2; iCl2++) {
1046 AliMUONVCluster* cl2 = ((AliMUONTrackParam*) track->fTrackParamAtCluster->UncheckedAt(iCl2))->GetClusterPtr();
1047
1048 Int_t chCl2 = cl2->GetChamberId();
1049 if (chCl2 < chMin || chCl2 > chMax) continue;
1050
1051 // Increment "clustersInCommon" if both clusters have the same ID
1052 if (cl1->GetUniqueID() == cl2->GetUniqueID()) {
1053 clustersInCommon++;
1054 break;
1055 }
1056
1057 }
1058
1059 }
1060
1061 return clustersInCommon;
1062}
1063
1064 //__________________________________________________________________________
1065Int_t AliMUONTrack::GetNDF() const
1066{
1067 /// return the number of degrees of freedom
1068
1069 Int_t ndf = 2 * GetNClusters() - 5;
1070 return (ndf > 0) ? ndf : 0;
1071}
1072
1073 //__________________________________________________________________________
1074Double_t AliMUONTrack::GetNormalizedChi2() const
1075{
1076 /// return the chi2 value divided by the number of degrees of freedom (or FLT_MAX if ndf <= 0)
1077
1078 Double_t ndf = (Double_t) GetNDF();
1079 return (ndf > 0.) ? fGlobalChi2 / ndf : 2.*MaxChi2();
1080}
1081
1082 //__________________________________________________________________________
1083Int_t AliMUONTrack::FindCompatibleClusters(const AliMUONTrack &track, Double_t sigmaCut, Bool_t compatibleCluster[10]) const
1084{
1085 /// Try to match clusters from this track with clusters from the given track within the provided sigma cut:
1086 /// - Fill the array compatibleCluster[iCh] with kTRUE if a compatible cluster has been found in chamber iCh.
1087 /// - Return the number of clusters of "this" track matched with one cluster of the given track.
1088 AliMUONVCluster *cluster1, *cluster2;
1089 Double_t chi2, dX, dY;
1090 Double_t chi2Max = sigmaCut * sigmaCut;
1091
1092 // initialization
1093 Int_t nMatchClusters = 0;
1094 for ( Int_t ch = 0; ch < AliMUONConstants::NTrackingCh(); ch++) compatibleCluster[ch] = kFALSE;
1095
1096 if (!track.fTrackParamAtCluster || !this->fTrackParamAtCluster) return nMatchClusters;
1097
1098 // Loop over clusters of first track
1099 Int_t nCl1 = this->GetNClusters();
1100 for(Int_t iCl1 = 0; iCl1 < nCl1; iCl1++) {
1101 cluster1 = static_cast<AliMUONTrackParam*>(this->fTrackParamAtCluster->UncheckedAt(iCl1))->GetClusterPtr();
1102
1103 // Loop over clusters of second track
1104 Int_t nCl2 = track.GetNClusters();
1105 for(Int_t iCl2 = 0; iCl2 < nCl2; iCl2++) {
1106 cluster2 = static_cast<AliMUONTrackParam*>(track.fTrackParamAtCluster->UncheckedAt(iCl2))->GetClusterPtr();
1107
1108 // check DE Id
1109 if (cluster1->GetDetElemId() != cluster2->GetDetElemId()) continue;
1110
1111 // check local chi2
1112 dX = cluster1->GetX() - cluster2->GetX();
1113 dY = cluster1->GetY() - cluster2->GetY();
1114 chi2 = dX * dX / (cluster1->GetErrX2() + cluster2->GetErrX2()) + dY * dY / (cluster1->GetErrY2() + cluster2->GetErrY2());
1115 if (chi2 > 2. * chi2Max) continue; // 2 because 2 quantities in chi2
1116
1117 compatibleCluster[cluster1->GetChamberId()] = kTRUE;
1118 nMatchClusters++;
1119 break;
1120 }
1121
1122 }
1123
1124 return nMatchClusters;
1125}
1126
1127//__________________________________________________________________________
1128Bool_t AliMUONTrack::Match(AliMUONTrack &track, Double_t sigmaCut, Int_t &nMatchClusters) const
1129{
1130 /// Try to match this track with the given track. Matching conditions:
1131 /// - more than 50% of clusters from this track matched with clusters from the given track
1132 /// - at least 1 cluster matched before and 1 cluster matched after the dipole
1133
1134 Bool_t compTrack[10];
1135 nMatchClusters = FindCompatibleClusters(track, sigmaCut, compTrack);
1136
1137 if ((compTrack[0] || compTrack[1] || compTrack[2] || compTrack[3]) && // at least 1 cluster matched in st 1 & 2
1138 (compTrack[6] || compTrack[7] || compTrack[8] || compTrack[9]) && // at least 1 cluster matched in st 4 & 5
1139 2 * nMatchClusters > GetNClusters()) return kTRUE; // more than 50% of clusters matched
1140 else return kFALSE;
1141
1142}
1143
1144//__________________________________________________________________________
1145void AliMUONTrack::SetTrackParamAtVertex(const AliMUONTrackParam* trackParam)
1146{
1147 /// set track parameters at vertex
1148 if (trackParam == 0x0) return;
1149 if (fTrackParamAtVertex) *fTrackParamAtVertex = *trackParam;
1150 else fTrackParamAtVertex = new AliMUONTrackParam(*trackParam);
1151}
1152
1153//__________________________________________________________________________
1154void AliMUONTrack::RecursiveDump() const
1155{
1156 /// Recursive dump of AliMUONTrack, i.e. with dump of trackParamAtCluster and attached clusters
1157 AliMUONTrackParam *trackParamAtCluster;
1158 AliMUONVCluster *cluster;
1159 cout << "Recursive dump of Track: " << this << endl;
1160 // Track
1161 this->Dump();
1162 for (Int_t iCluster = 0; iCluster < GetNClusters(); iCluster++) {
1163 trackParamAtCluster = (AliMUONTrackParam*) ((*fTrackParamAtCluster)[iCluster]);
1164 // trackParamAtCluster
1165 cout << "trackParamAtCluster: " << trackParamAtCluster << " (index: " << iCluster << ")" << endl;
1166 trackParamAtCluster->Dump();
1167 cluster = trackParamAtCluster->GetClusterPtr();
1168 // cluster
1169 cout << "cluster: " << cluster << endl;
1170 cluster->Print();
1171 }
1172 return;
1173}
1174
1175//_____________________________________________-
1176void AliMUONTrack::Print(Option_t*) const
1177{
1178 /// Printing Track information
1179
1180 streamsize curW = cout.width();
1181 streamsize curPrecision = cout.precision();
1182 cout << "<AliMUONTrack> No.Clusters=" << setw(2) << GetNClusters() <<
1183 ", Match2Trig=" << setw(1) << GetMatchTrigger() <<
1184 ", LoTrgNum=" << setw(3) << LoCircuit() <<
1185 ", Chi2-tracking-trigger=" << setw(8) << setprecision(5) << GetChi2MatchTrigger();
1186 cout << Form(" HitTriggerPattern %x",fHitsPatternInTrigCh);
1187 cout << Form(" MClabel=%d",fTrackID) << endl;
1188 if (fTrackParamAtCluster) fTrackParamAtCluster->First()->Print("FULL");
1189 cout.width(curW);
1190 cout.precision(curPrecision);
1191}
1192
1193//__________________________________________________________________________
1194void AliMUONTrack::SetLocalTrigger(Int_t loCirc, Int_t loStripX, Int_t loStripY, Int_t loDev, Int_t loLpt, Int_t loHpt, UChar_t respWithoutChamber)
1195{
1196 /// pack the local trigger information and store
1197
1198 if (loCirc < 0) return;
1199
1200 fLocalTrigger = 0;
1201 fLocalTrigger += loCirc;
1202 fLocalTrigger += loStripX << 8;
1203 fLocalTrigger += loStripY << 13;
1204 fLocalTrigger += loDev << 17;
1205 fLocalTrigger += loLpt << 22;
1206 fLocalTrigger += loHpt << 24;
1207 fLocalTrigger += respWithoutChamber << 26;
1208
1209}
1210
1211//__________________________________________________________________________
1212void AliMUONTrack::FindMCLabel()
1213{
1214 /// Determine the MC label from the label of the attached clusters and fill fMCLabel data member:
1215 /// More than 50% of clusters, including 1 before and 1 after the dipole, must share the same label
1216
1217 Int_t nClusters = GetNClusters();
1218 Int_t halfCluster = nClusters/2;
1219
1220 // reset MC label
1221 fTrackID = -1;
1222
1223 // loop over first clusters (if nClusters left < (nClusters-halfCluster) the conditions cannot be fulfilled)
1224 for (Int_t iCluster1 = 0; iCluster1 < nClusters-halfCluster; iCluster1++) {
1225 AliMUONVCluster* cluster1 = ((AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(iCluster1))->GetClusterPtr();
1226
1227 // if the first cluster is not on station 1 or 2 the conditions cannot be fulfilled
1228 if (cluster1->GetChamberId() > 3) return;
1229
1230 Int_t label1 = cluster1->GetMCLabel();
1231 if (label1 < 0) continue;
1232
1233 Int_t nIdenticalLabel = 1;
1234
1235 // Loop over next clusters
1236 for (Int_t iCluster2 = iCluster1+1; iCluster2 < nClusters; iCluster2++) {
1237 AliMUONVCluster* cluster2 = ((AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(iCluster2))->GetClusterPtr();
1238
1239 if (cluster2->GetMCLabel() != label1) continue;
1240
1241 nIdenticalLabel++;
1242
1243 // stop as soon as conditions are fulfilled
1244 if (nIdenticalLabel > halfCluster && cluster2->GetChamberId() > 5) {
1245 fTrackID = label1;
1246 return;
1247 }
1248
1249 }
1250
1251 }
1252
1253}
1254