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