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