1 /**************************************************************************
2 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
4 * Author: The ALICE Off-line Project. *
5 * Contributors are mentioned in the code where appropriate. *
7 * Permission to use, copy, modify and distribute this software and its *
8 * documentation strictly for non-commercial purposes is hereby granted *
9 * without fee, provided that the above copyright notice appears in all *
10 * copies and that both the copyright notice and this permission notice *
11 * appear in the supporting documentation. The authors make no claims *
12 * about the suitability of this software for any purpose. It is *
13 * provided "as is" without express or implied warranty. *
14 **************************************************************************/
16 //====================================================================================================================================================
18 // Description of an ALICE muon forward track, combining the information of the Muon Spectrometer and the Muon Forward Tracker
20 // Contact author: antonio.uras@cern.ch
22 //====================================================================================================================================================
25 #include "AliMUONTrack.h"
26 #include "AliMFTCluster.h"
27 #include "AliMUONVCluster.h"
28 #include "AliMUONTrackParam.h"
29 #include "AliMUONTrackExtrap.h"
30 #include "TClonesArray.h"
32 #include "TParticle.h"
33 #include "AliMuonForwardTrack.h"
34 #include "AliMFTConstants.h"
35 #include "TLorentzVector.h"
36 #include "TDatabasePDG.h"
37 #include "AliMUONConstants.h"
39 ClassImp(AliMuonForwardTrack)
41 //====================================================================================================================================================
43 AliMuonForwardTrack::AliMuonForwardTrack():
48 fNWrongClustersMC(-1),
54 // default constructor
56 for (Int_t iPlane=0; iPlane<AliMFTConstants::fNMaxPlanes; iPlane++) fPlaneExists[iPlane] = kFALSE;
57 for (Int_t iParent=0; iParent<fgkNParentsMax; iParent++) {
58 fParentMCLabel[iParent] = -1;
59 fParentPDGCode[iParent] = 0;
61 fMFTClusters = new TClonesArray("AliMFTCluster");
62 fMFTClusters -> SetOwner(kTRUE);
66 //====================================================================================================================================================
68 AliMuonForwardTrack::AliMuonForwardTrack(AliMUONTrack *MUONTrack):
73 fNWrongClustersMC(-1),
79 SetMUONTrack(MUONTrack);
80 for (Int_t iPlane=0; iPlane<AliMFTConstants::fNMaxPlanes; iPlane++) fPlaneExists[iPlane] = kFALSE;
81 for (Int_t iParent=0; iParent<fgkNParentsMax; iParent++) {
82 fParentMCLabel[iParent] = -1;
83 fParentPDGCode[iParent] = 0;
85 fMFTClusters = new TClonesArray("AliMFTCluster");
86 fMFTClusters -> SetOwner(kTRUE);
90 //====================================================================================================================================================
92 AliMuonForwardTrack::AliMuonForwardTrack(const AliMuonForwardTrack& track):
97 fNWrongClustersMC(track.fNWrongClustersMC),
98 fTrackMCId(track.fTrackMCId),
100 fParamCovMatrix(track.fParamCovMatrix)
104 fMUONTrack = new AliMUONTrack(*(track.fMUONTrack));
105 if (track.fMCTrackRef) fMCTrackRef = new TParticle(*(track.fMCTrackRef));
106 fMFTClusters = new TClonesArray(*(track.fMFTClusters));
107 fMFTClusters->SetOwner(kTRUE);
108 for (Int_t iPlane=0; iPlane<AliMFTConstants::fNMaxPlanes; iPlane++) fPlaneExists[iPlane] = (track.fPlaneExists)[iPlane];
109 for (Int_t iParent=0; iParent<fgkNParentsMax; iParent++) {
110 fParentMCLabel[iParent] = (track.fParentMCLabel)[iParent];
111 fParentPDGCode[iParent] = (track.fParentPDGCode)[iParent];
116 //====================================================================================================================================================
118 AliMuonForwardTrack& AliMuonForwardTrack::operator=(const AliMuonForwardTrack& track) {
120 // Asignment operator
122 // check assignement to self
123 if (this == &track) return *this;
125 // base class assignement
126 AliMUONTrack::operator=(track);
131 fMUONTrack = new AliMUONTrack(*(track.fMUONTrack));
132 if (track.fMCTrackRef) fMCTrackRef = new TParticle(*(track.fMCTrackRef));
133 fMFTClusters = new TClonesArray(*(track.fMFTClusters));
134 fMFTClusters->SetOwner(kTRUE);
135 fNWrongClustersMC = track.fNWrongClustersMC;
136 fTrackMCId = track.fTrackMCId;
137 fKinem = track.fKinem;
138 fParamCovMatrix = track.fParamCovMatrix;
140 for (Int_t iPlane=0; iPlane<AliMFTConstants::fNMaxPlanes; iPlane++) fPlaneExists[iPlane] = (track.fPlaneExists)[iPlane];
141 for (Int_t iParent=0; iParent<fgkNParentsMax; iParent++) {
142 fParentMCLabel[iParent] = (track.fParentMCLabel)[iParent];
143 fParentPDGCode[iParent] = (track.fParentPDGCode)[iParent];
150 //====================================================================================================================================================
152 void AliMuonForwardTrack::Clear(const Option_t* /*opt*/) {
155 fMFTClusters -> Delete();
156 delete fMFTClusters; fMFTClusters = 0x0;
157 delete fMUONTrack; fMUONTrack = 0x0;
158 delete fMCTrackRef; fMCTrackRef = 0x0;
162 //====================================================================================================================================================
164 AliMuonForwardTrack::~AliMuonForwardTrack() {
168 fMFTClusters -> Delete();
173 //====================================================================================================================================================
175 void AliMuonForwardTrack::SetMUONTrack(AliMUONTrack *MUONTrack) {
178 AliInfo("fMUONTrack already exists, nothing will be done");
182 fMUONTrack = MUONTrack;
183 SetGlobalChi2(fMUONTrack->GetGlobalChi2());
187 //====================================================================================================================================================
189 void AliMuonForwardTrack::SetMCTrackRef(TParticle *MCTrackRef) {
192 AliInfo("fMCTrackRef already exists, nothing will be done");
196 fMCTrackRef = MCTrackRef;
200 //====================================================================================================================================================
202 void AliMuonForwardTrack::AddTrackParamAtMFTCluster(AliMUONTrackParam &trackParam, AliMFTCluster &mftCluster) {
204 AliDebug(1, Form("Before adding: this->fMFTClusters=%p has %d entries", this->fMFTClusters, this->fMFTClusters->GetEntries()));
205 Int_t iMFTCluster = this->fMFTClusters->GetEntries();
206 AliDebug(1, Form("mftCluster->GetX() = %f mftCluster->GetY() = %f mftCluster->GetErrX() = %f cmftCluster->GetErrY() = %f",
207 mftCluster.GetX(), mftCluster.GetY(), mftCluster.GetErrX(), mftCluster.GetErrY()));
208 AliMUONVCluster *muonCluster = (AliMUONVCluster*) mftCluster.CreateMUONCluster();
209 AliDebug(1, Form("Created MUON cluster %p", muonCluster));
210 trackParam.SetUniqueID(iMFTCluster); // we profit of this slot to store the reference to the corresponding MFTCluster
211 AliDebug(1, Form("Now adding muonCluster %p and trackParam %p",muonCluster, &trackParam));
212 AddTrackParamAtCluster(trackParam, *muonCluster, kTRUE);
213 // we pass the parameters this->GetTrackParamAtCluster()->First() to the Kalman Filter algorithm: they will be updated!!
214 Double_t chi2Kalman = RunKalmanFilter(*(AliMUONTrackParam*)(GetTrackParamAtCluster()->First()));
215 AliDebug(1, Form("Adding Kalman chi2 = %f to global chi2 = %f", chi2Kalman, GetGlobalChi2()));
216 Double_t newGlobalChi2 = GetGlobalChi2() + chi2Kalman;
217 mftCluster.SetLocalChi2(chi2Kalman);
218 mftCluster.SetTrackChi2(newGlobalChi2);
219 new ((*(this->fMFTClusters))[iMFTCluster]) AliMFTCluster(mftCluster);
220 AliDebug(1, Form("GetTrackParamAtCluster() = %p has %d entries while this->fMFTClusters=%p has %d entries",
221 GetTrackParamAtCluster(), GetTrackParamAtCluster()->GetEntries(), this->fMFTClusters, this->fMFTClusters->GetEntries()));
222 AliDebug(1, Form("muonCluster->GetZ() = %f, trackParam->GetZ() = %f",muonCluster->GetZ(), trackParam.GetZ()));
223 SetGlobalChi2(newGlobalChi2);
224 AliDebug(1, Form("New global chi2 = %f", GetGlobalChi2()));
225 ((AliMUONTrackParam*) GetTrackParamAtCluster()->First())->SetTrackChi2(newGlobalChi2);
226 for (Int_t iPar=0; iPar<GetTrackParamAtCluster()->GetEntries(); iPar++) {
227 AliDebug(1, Form("GetTrackParamAtCluster()->At(%d)->GetClusterPtr() = %p",
228 iPar, ((AliMUONTrackParam*)(GetTrackParamAtCluster()->At(iPar)))->GetClusterPtr()));
233 //====================================================================================================================================================
235 AliMUONTrackParam* AliMuonForwardTrack::GetTrackParamAtMUONCluster(Int_t iMUONCluster) {
237 if (iMUONCluster<0 || iMUONCluster>=GetNMUONClusters()) {
238 AliError("Invalid MUON cluster index. NULL pointer will be returned");
242 AliMUONTrackParam *trackParam = (AliMUONTrackParam*) fMUONTrack->GetTrackParamAtCluster()->At(iMUONCluster);
248 //====================================================================================================================================================
250 AliMUONTrackParam* AliMuonForwardTrack::GetTrackParamAtMFTCluster(Int_t iMFTCluster) {
252 if (iMFTCluster<0 || iMFTCluster>=GetNMFTClusters()) {
253 AliError("Invalid MFT cluster index. NULL pointer will be returned");
257 AliMUONTrackParam *trackParam = (AliMUONTrackParam*) GetTrackParamAtCluster()->At(iMFTCluster);
263 //====================================================================================================================================================
265 AliMUONVCluster* AliMuonForwardTrack::GetMUONCluster(Int_t iMUONCluster) {
267 if (iMUONCluster<0 || iMUONCluster>=GetNMUONClusters()) {
268 AliError("Invalid MUON cluster index. NULL pointer will be returned");
272 AliMUONTrackParam *trackParam = GetTrackParamAtMUONCluster(iMUONCluster);
273 AliMUONVCluster *muonCluster = trackParam->GetClusterPtr();
279 //====================================================================================================================================================
281 AliMFTCluster* AliMuonForwardTrack::GetMFTCluster(Int_t iMFTCluster) {
283 if (iMFTCluster<0 || iMFTCluster>=GetNMFTClusters()) {
284 AliError(Form("Invalid MFT cluster index (%d). GetNMFTClusters()=%d. NULL pointer will be returned", iMFTCluster, GetNMFTClusters()));
288 AliMUONTrackParam *trackParam = GetTrackParamAtMFTCluster(iMFTCluster);
289 AliMFTCluster *mftCluster = (AliMFTCluster*) this->fMFTClusters->At(trackParam->GetUniqueID());
295 //====================================================================================================================================================
297 Double_t AliMuonForwardTrack::RunKalmanFilter(AliMUONTrackParam &trackParamAtCluster) {
299 AliDebug(1, Form("Running Kalman filter for parameters %p (z = %f) and cluster %p (z = %f)",
300 &trackParamAtCluster, trackParamAtCluster.GetZ(), trackParamAtCluster.GetClusterPtr(), trackParamAtCluster.GetClusterPtr()->GetZ()));
302 // Compute new track parameters and their covariances including new cluster using kalman filter
303 // return the *additional* track chi2
305 // Get actual track parameters (p)
306 TMatrixD param(trackParamAtCluster.GetParameters());
308 // Get new cluster parameters (m)
309 AliMUONVCluster *cluster = trackParamAtCluster.GetClusterPtr();
310 AliDebug(1, Form("cluster->GetX() = %f cluster->GetY() = %f cluster->GetErrX() = %f cluster->GetErrY() = %f",
311 cluster->GetX(), cluster->GetY(), cluster->GetErrX(), cluster->GetErrY()));
312 TMatrixD clusterParam(5,1);
314 clusterParam(0,0) = cluster->GetX();
315 clusterParam(2,0) = cluster->GetY();
317 // Compute the current parameter weight (W)
318 TMatrixD paramWeight(trackParamAtCluster.GetCovariances());
319 if (paramWeight.Determinant() != 0) {
320 paramWeight.Invert();
322 Warning("RunKalmanFilter"," Determinant = 0");
326 // Compute the new cluster weight (U)
327 TMatrixD clusterWeight(5,5);
328 clusterWeight.Zero();
329 clusterWeight(0,0) = 1. / cluster->GetErrX2();
330 clusterWeight(2,2) = 1. / cluster->GetErrY2();
332 // Compute the new parameters covariance matrix ( (W+U)^-1 )
333 TMatrixD newParamCov(paramWeight,TMatrixD::kPlus,clusterWeight);
334 if (newParamCov.Determinant() != 0) {
335 newParamCov.Invert();
338 Warning("RunKalmanFilter"," Determinant = 0");
342 // Save the new parameters covariance matrix
343 trackParamAtCluster.SetCovariances(newParamCov);
345 // Compute the new parameters (p' = ((W+U)^-1)U(m-p) + p)
346 TMatrixD tmp(clusterParam,TMatrixD::kMinus,param);
347 TMatrixD tmp2(clusterWeight,TMatrixD::kMult,tmp); // U(m-p)
348 TMatrixD newParam(newParamCov,TMatrixD::kMult,tmp2); // ((W+U)^-1)U(m-p)
349 newParam += param; // ((W+U)^-1)U(m-p) + p
351 // Save the new parameters
352 trackParamAtCluster.SetParameters(newParam);
354 // Compute the additional chi2 (= ((p'-p)^-1)W(p'-p) + ((p'-m)^-1)U(p'-m))
355 tmp = newParam; // p'
356 tmp -= param; // (p'-p)
357 TMatrixD tmp3(paramWeight,TMatrixD::kMult,tmp); // W(p'-p)
358 TMatrixD addChi2Track(tmp,TMatrixD::kTransposeMult,tmp3); // ((p'-p)^-1)W(p'-p)
359 tmp = newParam; // p'
360 tmp -= clusterParam; // (p'-m)
361 TMatrixD tmp4(clusterWeight,TMatrixD::kMult,tmp); // U(p'-m)
362 addChi2Track += TMatrixD(tmp,TMatrixD::kTransposeMult,tmp4); // ((p'-p)^-1)W(p'-p) + ((p'-m)^-1)U(p'-m)
364 AliDebug(1,Form("Adding Kalman chi2 = %f",addChi2Track(0,0)));
366 return addChi2Track(0,0);
370 //====================================================================================================================================================
372 Double_t AliMuonForwardTrack::GetWeightedOffset(Double_t x, Double_t y, Double_t z) {
374 AliMUONTrackParam *param = GetTrackParamAtMFTCluster(0);
375 AliMUONTrackExtrap::ExtrapToZCov(param, z);
378 cov = param->GetCovariances();
380 TMatrixD covCoordinates(2,2);
381 covCoordinates(0,0) = cov(0,0);
382 covCoordinates(0,1) = cov(0,2);
383 covCoordinates(1,0) = cov(2,0);
384 covCoordinates(1,1) = cov(2,2);
386 TMatrixD covCoordinatesInverse = covCoordinates.Invert();
388 Double_t dX = param->GetNonBendingCoor() - x;
389 Double_t dY = param->GetBendingCoor() - y;
391 Double_t weightedOffset = TMath::Sqrt(0.5*(dX*dX*covCoordinatesInverse(0,0) +
392 dY*dY*covCoordinatesInverse(1,1) +
393 2.*dX*dY*covCoordinatesInverse(0,1)));
395 return weightedOffset;
399 //====================================================================================================================================================
401 Double_t AliMuonForwardTrack::GetOffsetX(Double_t x, Double_t z) {
403 AliMUONTrackParam *param = GetTrackParamAtMFTCluster(0);
404 AliMUONTrackExtrap::ExtrapToZCov(param, z);
405 Double_t dX = param->GetNonBendingCoor() - x;
410 //====================================================================================================================================================
412 Double_t AliMuonForwardTrack::GetOffsetY(Double_t y, Double_t z) {
414 AliMUONTrackParam *param = GetTrackParamAtMFTCluster(0);
415 AliMUONTrackExtrap::ExtrapToZCov(param, z);
416 Double_t dY = param->GetBendingCoor() - y;
421 //====================================================================================================================================================
423 Double_t AliMuonForwardTrack::GetOffset(Double_t x, Double_t y, Double_t z) {
425 AliMUONTrackParam *param = GetTrackParamAtMFTCluster(0);
426 AliMUONTrackExtrap::ExtrapToZCov(param, z);
427 Double_t dX = param->GetNonBendingCoor() - x;
428 Double_t dY = param->GetBendingCoor() - y;
429 return TMath::Sqrt(dX*dX + dY*dY);
433 //====================================================================================================================================================
435 Double_t AliMuonForwardTrack::GetDCA(Double_t x, Double_t y, Double_t z) {
437 // Distance of Closest Approach, according to the standard MUON terminology. Actually, the offset of the track w.r.t. the primary vertex,
438 // where the extrapolation of the track DOES NOT include the MFT information
440 AliMUONTrackParam *param = GetTrackParamAtMUONCluster(0);
441 AliMUONTrackExtrap::ExtrapToVertexWithoutBranson(param, z);
442 Double_t dX = param->GetNonBendingCoor() - x;
443 Double_t dY = param->GetBendingCoor() - y;
444 return TMath::Sqrt(dX*dX + dY*dY);
448 //====================================================================================================================================================
450 Double_t AliMuonForwardTrack::GetMomentumSpectrometer(Double_t z) {
452 // Momentum of the track at the primary vertex plane, where the extrapolation of the track DOES NOT include the MFT information
454 AliMUONTrackParam *param = GetTrackParamAtMUONCluster(0);
455 AliMUONTrackExtrap::ExtrapToVertexWithoutBranson(param, z);
460 //====================================================================================================================================================
462 Double_t AliMuonForwardTrack::GetThetaAbs() {
464 // it is the angle defined by the imaginary line goingo from the vertex to the exit point of the track at the end of the hadron absorber
466 Double_t z = AliMUONConstants::AbsZEnd();
467 AliMUONTrackParam *param = GetTrackParamAtMFTCluster(0);
468 AliMUONTrackExtrap::ExtrapToZ(param, z);
469 Double_t x = param->GetNonBendingCoor();
470 Double_t y = param->GetBendingCoor();
472 return 180. +TMath::ATan(TMath::Sqrt(x*x + y*y)/z)*TMath::RadToDeg();
476 //====================================================================================================================================================
478 Bool_t AliMuonForwardTrack::IsFromResonance() {
480 Bool_t result = kFALSE;
482 if ( GetParentPDGCode(0) == 113 ||
483 GetParentPDGCode(0) == 221 ||
484 GetParentPDGCode(0) == 223 ||
485 GetParentPDGCode(0) == 331 ||
486 GetParentPDGCode(0) == 333 ||
487 GetParentPDGCode(0) == 443 ||
488 GetParentPDGCode(0) == 100443 ||
489 GetParentPDGCode(0) == 553 ||
490 GetParentPDGCode(0) == 100553 ) result = kTRUE;
492 if (result) AliDebug(1, Form("Muon comes from a resonance %d", GetParentPDGCode(0)));
498 //====================================================================================================================================================
500 Bool_t AliMuonForwardTrack::IsFromCharm() {
502 Bool_t result = kFALSE;
504 if (IsPDGCharm(GetParentPDGCode(0)) && !IsPDGBeauty(GetParentPDGCode(1))) result = kTRUE;
506 if (result) AliDebug(1, Form("Muon comes from a charmed hadron %d", GetParentPDGCode(0)));
512 //====================================================================================================================================================
514 Bool_t AliMuonForwardTrack::IsFromBeauty() {
516 Bool_t result = kFALSE;
518 if (IsPDGBeauty(GetParentPDGCode(0))) result = kTRUE;
520 if (result) AliDebug(1, Form("Muon comes from a beauty hadron %d", GetParentPDGCode(0)));
526 //====================================================================================================================================================
528 Bool_t AliMuonForwardTrack::IsPDGCharm(Int_t pdg) {
530 Bool_t result = kFALSE;
532 if ( TMath::Abs(pdg) == 411 ||
533 TMath::Abs(pdg) == 421 ||
534 TMath::Abs(pdg) == 10411 ||
535 TMath::Abs(pdg) == 10421 ||
536 TMath::Abs(pdg) == 413 ||
537 TMath::Abs(pdg) == 423 ||
538 TMath::Abs(pdg) == 10413 ||
539 TMath::Abs(pdg) == 10423 ||
540 TMath::Abs(pdg) == 20413 ||
541 TMath::Abs(pdg) == 20423 ||
542 TMath::Abs(pdg) == 415 ||
543 TMath::Abs(pdg) == 425 ||
544 TMath::Abs(pdg) == 431 ||
545 TMath::Abs(pdg) == 10431 ||
546 TMath::Abs(pdg) == 433 ||
547 TMath::Abs(pdg) == 10433 ||
548 TMath::Abs(pdg) == 20433 ||
549 TMath::Abs(pdg) == 435 ) result = kTRUE;
555 //====================================================================================================================================================
557 Bool_t AliMuonForwardTrack::IsPDGBeauty(Int_t pdg) {
559 Bool_t result = kFALSE;
561 if ( TMath::Abs(pdg) == 511 ||
562 TMath::Abs(pdg) == 521 ||
563 TMath::Abs(pdg) == 10511 ||
564 TMath::Abs(pdg) == 10521 ||
565 TMath::Abs(pdg) == 513 ||
566 TMath::Abs(pdg) == 523 ||
567 TMath::Abs(pdg) == 10513 ||
568 TMath::Abs(pdg) == 10523 ||
569 TMath::Abs(pdg) == 20513 ||
570 TMath::Abs(pdg) == 20523 ||
571 TMath::Abs(pdg) == 515 ||
572 TMath::Abs(pdg) == 525 ||
573 TMath::Abs(pdg) == 531 ||
574 TMath::Abs(pdg) == 10531 ||
575 TMath::Abs(pdg) == 533 ||
576 TMath::Abs(pdg) == 10533 ||
577 TMath::Abs(pdg) == 20533 ||
578 TMath::Abs(pdg) == 535 ||
579 TMath::Abs(pdg) == 541 ||
580 TMath::Abs(pdg) == 10541 ||
581 TMath::Abs(pdg) == 543 ||
582 TMath::Abs(pdg) == 10543 ||
583 TMath::Abs(pdg) == 20543 ||
584 TMath::Abs(pdg) == 545 ) result = kTRUE;
590 //====================================================================================================================================================
592 Bool_t AliMuonForwardTrack::IsFromBackground() {
594 Bool_t result = kFALSE;
596 if (!IsFromResonance() && !IsFromCharm() && !IsFromBeauty()) result = kTRUE;
598 if (result) AliDebug(1, Form("Muon comes from a background source %d", GetParentPDGCode(0)));
604 //====================================================================================================================================================
606 void AliMuonForwardTrack::EvalKinem(Double_t z) {
608 AliMUONTrackParam *param = GetTrackParamAtMFTCluster(0);
609 AliMUONTrackExtrap::ExtrapToZCov(param, z);
611 Double_t mMu = TDatabasePDG::Instance()->GetParticle("mu-")->Mass();
612 Double_t energy = TMath::Sqrt(param->P()*param->P() + mMu*mMu);
613 fKinem.SetPxPyPzE(param->Px(), param->Py(), param->Pz(), energy);
616 fParamCovMatrix = param->GetCovariances();
620 //====================================================================================================================================================