1 /**************************************************************************
2 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
3 * SigmaEffect_thetadegrees *
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 purpeateose. It is *
13 * provided "as is" without express or implied warranty. *
14 **************************************************************************/
18 //-----------------------------------------------------------------------------
19 // Compact information for the muon generated tracks in the MUON arm
20 // useful at the last stage of the analysis chain
21 // provides a link between the reconstructed track and the generated particle
22 // stores kinematical information at gen. and rec. level and
23 // the decay history of the muon, allowing the identification of the
26 // To be used together with AliMUONPairLight
28 // This class was prepared by INFN Cagliari, July 2006
29 // (authors: H.Woehri, A.de Falco)
30 //-----------------------------------------------------------------------------
33 // Added a temporary fix to FindRefTrack to be able to handle reconstructed tracks
34 // generated from ESD muon track information. The problem is that the ESD data at
35 // the moment only contains the first hit on chamber 1. Hopefully in the near future
36 // this will be fixed and all hit information will be available.
37 // - Artur Szostak <artursz@iafrica.com>
39 #include "AliMUONTrackLight.h"
40 #include "AliMUONTrack.h"
41 #include "AliMUONConstants.h"
42 #include "AliMUONVTrackStore.h"
43 #include "AliMUONTrackExtrap.h"
45 #include "AliESDMuonTrack.h"
46 #include "AliRunLoader.h"
48 #include "AliHeader.h"
50 #include "TDatabasePDG.h"
51 #include "TParticle.h"
54 ClassImp(AliMUONTrackLight)
56 //===================================================================
58 AliMUONTrackLight::AliMUONTrackLight()
66 fTrackPythiaLine(-999),
72 /// default constructor
73 fPgen.SetPxPyPzE(0.,0.,0.,0.);
74 fPrec.SetPxPyPzE(0.,0.,0.,0.);
75 for (Int_t i=0; i<3; i++) fXYZ[i]=-999;
76 for (Int_t npar = 0; npar < fgkNParentsMax; npar++){
77 fParentPDGCode[npar] = -1;
78 fParentPythiaLine[npar] = -1;
80 for (Int_t i = 0; i < 4; i++){
81 fQuarkPDGCode[i] = -1;
82 fQuarkPythiaLine[i] = -1;
86 //============================================
87 AliMUONTrackLight::AliMUONTrackLight(const AliMUONTrackLight &muonCopy)
89 fPrec(muonCopy.fPrec),
90 fIsTriggered(muonCopy.fIsTriggered),
91 fCharge(muonCopy.fCharge),
92 fChi2(muonCopy.fChi2),
93 fCentr(muonCopy.fCentr),
94 fPgen(muonCopy.fPgen),
95 fTrackPythiaLine(muonCopy.fTrackPythiaLine),
96 fTrackPDGCode(muonCopy.fTrackPDGCode),
97 fOscillation(muonCopy.fOscillation),
98 fNParents(muonCopy.fNParents),
99 fWeight(muonCopy.fWeight)
102 for (Int_t i=0; i<3; i++) fXYZ[i]=muonCopy.fXYZ[i];
103 for (Int_t npar = 0; npar < fgkNParentsMax; npar++){
104 fParentPDGCode[npar] = muonCopy.fParentPDGCode[npar];
105 fParentPythiaLine[npar] = muonCopy.fParentPythiaLine[npar];
107 for (Int_t i = 0; i < 4; i++){
108 fQuarkPDGCode[i] = muonCopy.fQuarkPDGCode[i];
109 fQuarkPythiaLine[i] = muonCopy.fQuarkPythiaLine[i];
113 //============================================
114 AliMUONTrackLight::AliMUONTrackLight(AliESDMuonTrack* muonTrack)
117 fIsTriggered(kFALSE),
122 fTrackPythiaLine(-999),
124 fOscillation(kFALSE),
129 //AliMUONTrackLight();
130 FillFromESD(muonTrack);
133 //============================================
134 AliMUONTrackLight::~AliMUONTrackLight()
139 //============================================
141 void AliMUONTrackLight::FillFromAliMUONTrack(AliMUONTrack *trackReco,Double_t zvert){
142 /// this method sets the muon reconstructed momentum according to the value given by AliMUONTrack
143 AliMUONTrackParam trPar(*((AliMUONTrackParam*) (trackReco->GetTrackParamAtCluster()->First())));
144 // AliMUONTrackParam *trPar = trackReco->GetTrackParamAtVertex();
145 AliMUONTrackExtrap::ExtrapToVertex(&trPar,0.,0.,0.,0.,0.);
146 this->SetCharge(Int_t(TMath::Sign(1.,trPar.GetInverseBendingMomentum())));
147 this->SetPxPyPz(trPar.Px(),trPar.Py(), trPar.Pz());
148 this->SetTriggered(trackReco->GetMatchTrigger());
150 Double_t xyz[3] = { trPar.GetNonBendingCoor(),
151 trPar.GetBendingCoor(),
153 this->SetVertex(xyz);
156 //============================================
157 void AliMUONTrackLight::FillFromESD(AliESDMuonTrack* muonTrack,Double_t zvert){
158 /// computes prec and charge from ESD track
159 Double_t mumass = TDatabasePDG::Instance()->GetParticle(13)->Mass();
160 Double_t thetaX = muonTrack->GetThetaX();
161 Double_t thetaY = muonTrack->GetThetaY();
162 Double_t tanthx = TMath::Tan(thetaX);
163 Double_t tanthy = TMath::Tan(thetaY);
164 Double_t pYZ = 1./TMath::Abs(muonTrack->GetInverseBendingMomentum());
165 Double_t pz = - pYZ / TMath::Sqrt(1.0 + tanthy * tanthy);
166 Double_t px = pz * tanthx;
167 Double_t py = pz * tanthy;
168 fCharge = Int_t(TMath::Sign(1.,muonTrack->GetInverseBendingMomentum()));
169 Double_t energy = TMath::Sqrt(mumass * mumass + px*px + py*py + pz*pz);
170 fPrec.SetPxPyPzE(px,py,pz,energy);
172 fXYZ[0] = muonTrack->GetNonBendingCoor();
173 fXYZ[1] = muonTrack->GetBendingCoor();
174 if (zvert==-9999) fXYZ[2] = muonTrack->GetZ();
175 else fXYZ[2] = zvert;
176 // get the chi2 per d.o.f.
177 fChi2 = muonTrack->GetChi2()/ (2.0 * muonTrack->GetNHit() - 5);
178 fIsTriggered = muonTrack->GetMatchTrigger();
181 //============================================
182 void AliMUONTrackLight::SetPxPyPz(Double_t px, Double_t py, Double_t pz){
183 /// set the reconstructed 4-momentum, assuming the particle is a muon
184 Double_t mumass = TDatabasePDG::Instance()->GetParticle(13)->Mass();
185 Double_t energy = TMath::Sqrt(mumass * mumass + px*px + py*py + pz*pz);
186 fPrec.SetPxPyPzE(px,py,pz,energy);
189 //============================================
190 TParticle* AliMUONTrackLight::FindRefTrack(
191 AliMUONTrack* trackReco, AliMUONVTrackStore* trackRefArray,
192 AliStack* stack, Bool_t tempfix
195 /// Find the Monte Carlo (MC) particle that corresponds to a given reconstructed track.
196 /// @param trackReco This is the reconstructed track for which we want to find a
197 /// corresponding MC particle.
198 /// @param trackRefArray The list of MC reference tracks as generated by
199 /// AliMUONRecoCheck::ReconstructedTracks for example.
200 /// @param stack The MC stack of simulated particles.
201 /// @param tempfix This specifies if a temporary fix should be applied, where we only
202 /// check if the first hit on chamber 1, the vertex momentum, the X-Y vertex
203 /// coordinate and X-Y slope match between 'trackReco' and a MC reference
204 /// track in 'trackRefArray'.
205 /// This temporary fix is necessary while AliMUONTrack objects are no longer
206 /// stored after reconstruction and the hit information is not completely
207 /// stored in the ESD data.
210 const Double_t kSigma2Cut = 16; // 4 sigmas cut, kSigma2Cut = 4*4
212 TIter next(trackRefArray->CreateIterator());
213 AliMUONTrack* trackRef;
214 while ( (trackRef = static_cast<AliMUONTrack*>(next())) ) {
215 // check if trackRef is compatible with trackReco:
216 //routine returns for each chamber a yes/no information if the
217 //hit of rec. track and hit of referenced track are compatible
218 Bool_t *compTrack = trackRef->CompatibleTrack(trackReco,kSigma2Cut);
222 // All we can check with this temporary fix is that the first hit on chamber 1
223 // is the same and that the particles momentum, slope and vertex X and Y are
224 // compatible within resolution.
225 if (compTrack[0]) iTrack++;
226 AliMUONTrackParam* paramA = trackRef->GetTrackParamAtVertex();
227 AliMUONTrackParam* paramB = trackReco->GetTrackParamAtVertex();
228 if (paramA != NULL and paramB != NULL)
230 // Fetch the variances.
231 Double_t varX = paramA->GetCovariances()[0][0] + paramB->GetCovariances()[0][0];
232 Double_t varSlopeX = paramA->GetCovariances()[1][1] + paramB->GetCovariances()[1][1];
233 Double_t varY = paramA->GetCovariances()[2][2] + paramB->GetCovariances()[2][2];
234 Double_t varSlopeY = paramA->GetCovariances()[3][3] + paramB->GetCovariances()[3][3];
235 Double_t varInvP = paramA->GetCovariances()[4][4] + paramB->GetCovariances()[4][4];
236 // We might have to fill these variances with defaults.
237 if (varX == 0) varX = AliMUONConstants::DefaultNonBendingReso2();
238 if (varSlopeX == 0) varSlopeX = AliMUONConstants::DefaultNonBendingReso2();
239 if (varY == 0) varY = AliMUONConstants::DefaultBendingReso2();
240 if (varSlopeY == 0) varSlopeY = AliMUONConstants::DefaultBendingReso2();
243 // Use ~10% resolution for momentum.
244 Double_t sigmaA = 0.1 * paramA->GetInverseBendingMomentum();
245 Double_t sigmaB = 0.1 * paramB->GetInverseBendingMomentum();
246 varInvP = sigmaA*sigmaA + sigmaB*sigmaB;
248 // Calculate the differences between parameters.
249 Double_t diffX = paramA->GetNonBendingCoor() - paramB->GetNonBendingCoor();
250 Double_t diffSlopeX = paramA->GetNonBendingSlope() - paramB->GetNonBendingSlope();
251 Double_t diffY = paramA->GetBendingCoor() - paramB->GetBendingCoor();
252 Double_t diffSlopeY = paramA->GetBendingSlope() - paramB->GetBendingSlope();
253 Double_t diffInvP = paramA->GetInverseBendingMomentum() - paramB->GetInverseBendingMomentum();
254 // Check that all the parameters are within kSigma2Cut limit.
255 if (diffX*diffX / varX < kSigma2Cut and diffY*diffY / varY < kSigma2Cut) iTrack++;
256 if (diffSlopeX*diffSlopeX / varSlopeX < kSigma2Cut and diffSlopeY*diffSlopeY / varSlopeY < kSigma2Cut) iTrack++;
257 if (diffInvP*diffInvP / varInvP < kSigma2Cut) iTrack++;
261 iTrack = this->TrackCheck(compTrack); //returns number of validated conditions
265 Int_t trackID = trackRef->GetTrackID();
266 this->SetTrackPythiaLine(trackID);
267 part = stack->Particle(trackID);
268 fTrackPDGCode = part->GetPdgCode();
272 AliFatal("More than one particle compatible with the reconstructed track.");
277 //============================================
278 Int_t AliMUONTrackLight::TrackCheck(Bool_t *compTrack){
279 /// Apply reconstruction requirements
280 /// Return number of validated conditions
281 /// If all the tests are verified then TrackCheck = 4 (good track)
284 Int_t hitsInLastStations = 0;
286 // apply reconstruction requirements
287 if (compTrack[0] || compTrack[1]) iTrack++; // at least one hit in st. 0
288 if (compTrack[2] || compTrack[3]) iTrack++; // at least one hit in st. 1
289 if (compTrack[4] || compTrack[5]) iTrack++; // at least one hit in st. 2
290 for (Int_t ch = 6; ch < AliMUONConstants::NTrackingCh(); ch++) {
291 if (compTrack[ch]) hitsInLastStations++;
293 if (hitsInLastStations > 2) iTrack++; // at least 3 hits in st. 3 & 4
297 //============================================
298 void AliMUONTrackLight::FillMuonHistory(AliStack *stack, TParticle *part){
299 /// scans the muon history to determine parents pdg code and pythia line
301 Int_t parents[10], parLine[10];
302 Int_t lineM = part->GetFirstMother();//line in the Pythia output of the particle's mother
305 Int_t status=-1, pdg=-1;
308 mother = stack->Particle(lineM); //direct mother of rec. track
309 pdg = mother->GetPdgCode();//store PDG code of first mother
310 // break if a string, gluon, quark or diquark is found
311 if(pdg == 92 || pdg == 21 || TMath::Abs(pdg) < 10 || IsDiquark(pdg)) break;
312 parents[++countP] = pdg;
313 parLine[countP] = lineM;
314 status = mother->GetStatusCode();//get its status code to check if oscillation occured
315 if(IsB0(parents[countP]) && status == 12) this->SetOscillation(kTRUE);
316 lineM = mother->GetFirstMother();
318 //store all the fragmented parents in an array:
319 for(int i = 0; i <= countP; i++){
320 this->SetParentPDGCode(i,parents[countP-i]);
321 this->SetParentPythiaLine(i,parLine[countP-i]);
323 fNParents = countP+1;
326 //and store the lines of the string and further quarks in another array:
328 mother = stack->Particle(lineM);
329 pdg = mother->GetPdgCode();
330 //now, get information before the fragmentation
331 this->SetQuarkPythiaLine(++countP, lineM);//store the line of the string in index 0
332 this->SetQuarkPDGCode(countP, pdg);//store the pdg of the quarks in index 1,2
333 lineM = mother->GetFirstMother();
336 //check if in case of HF production, the string points to the correct end
337 //and correct it in case of need:
339 for(int par = 0; par < 4; par++){
340 if(TMath::Abs(this->GetQuarkPDGCode(par)) < 6){
341 countP = par; //get the quark just before hadronisation
345 if(this->GetQuarkPythiaLine(countP) > -1 && (this->GetParentFlavour(0)==4 || this->GetParentFlavour(0)==5)){
346 if(this->GetParentFlavour(0) != TMath::Abs(this->GetQuarkPDGCode(countP))){
348 AliWarning(Form("quark flavour of parent and that of quark do not correspond: %d %d --> correcting\n",
349 this->GetParentFlavour(0), TMath::Abs(this->GetQuarkPDGCode(countP)))
352 Int_t pdg = this->GetQuarkPDGCode(countP), line = this->GetQuarkPythiaLine(countP);
353 this->ResetQuarkInfo();
354 while(TMath::Abs(pdg) != this->GetParentFlavour(0)){//pdg of q,g in Pythia listing following the wrong string end
355 //must coincide with the flavour of the last fragmented mother
357 pdg = stack->Particle(++line)->GetPdgCode();
359 //now, we have the correct string end and the correct line
360 //continue to fill again all parents and corresponding lines
362 mother = stack->Particle(line);//get again the mother
363 pdg = mother->GetPdgCode();
364 this->SetQuarkPythiaLine(countP, line);
365 this->SetQuarkPDGCode(countP++, pdg);
366 line = mother->GetFirstMother();
368 this->PrintInfo("h");
373 //====================================
374 void AliMUONTrackLight::ResetQuarkInfo(){
375 /// resets parton information
376 for(int pos = 1; pos < 4; pos++){//[0] is the string
377 this->SetQuarkPDGCode(pos,-1);
378 this->SetQuarkPythiaLine(pos,-1);
382 //====================================
383 Bool_t AliMUONTrackLight::IsB0(Int_t intTest) const {
384 /// checks if the particle is a B0
385 Int_t bMes0[2] = {511,531};//flavour code of B0d and B0s
386 Bool_t answer = kFALSE;
387 for(int i = 0; i < 2; i++){
388 if(TMath::Abs(intTest) == bMes0[i]){
395 //====================================
396 Bool_t AliMUONTrackLight::IsMotherAResonance(Int_t index) const {
397 /// checks if mother is a resonance
398 Int_t intTest = GetParentPDGCode(index);
399 // the resonance pdg code is built this way
400 // x00ffn where x=0,1,.. (1S,2S... states), f=quark flavour
401 Int_t id=intTest%100000;
402 return (!((id-id%10)%110));
404 //====================================
405 Int_t AliMUONTrackLight::GetParentFlavour(Int_t idParent) const {
406 /// returns the flavour of parent idParent (idParent=0 is the oldest
407 /// hadronized parent)
408 Int_t pdg = GetParentPDGCode(idParent);
409 Int_t quark = TMath::Abs(pdg/100);
410 if(quark > 9) quark = quark/10;
414 //====================================
415 void AliMUONTrackLight::PrintInfo(Option_t* opt){
416 /// prints information about the track:
417 /// - "H" muon's decay history
418 /// - "K" muon kinematics
419 /// - "A" all variables
420 TString options(opt);
423 if(options.Contains("H") || options.Contains("A")){ //muon decay history
424 char *name= new char[100];
425 TString pdg = "", line = "";
426 for(int i = 3; i >= 0; i--){
427 if(this->GetQuarkPythiaLine(i)>= 0){
428 sprintf(name, "%4d --> ", this->GetQuarkPythiaLine(i));
430 sprintf(name, "%4d --> ", this->GetQuarkPDGCode(i));
434 for(int i = 0; i < fNParents; i++){
435 if(this->GetParentPythiaLine(i)>= 0){
436 sprintf(name, "%7d --> ", this->GetParentPythiaLine(i));
438 sprintf(name, "%7d --> ", this->GetParentPDGCode(i));
442 sprintf(name, "%4d", this->GetTrackPythiaLine()); line += name;
443 sprintf(name, "%4d", this->GetTrackPDGCode()); pdg += name;
445 printf("\nmuon's decay history:\n");
446 printf(" PDG: %s\n", pdg.Data());
447 printf("line: %s\n", line.Data());
449 if(options.Contains("K") || options.Contains("A")){ //muon kinematic
451 Int_t charge = this->GetCharge();
452 Double_t *vtx = this->GetVertex();
453 TLorentzVector momRec = this->GetPRec();
454 TLorentzVector momGen = this->GetPGen();
455 printf("the track's charge is %d\n", charge);
456 printf("Primary vertex: Vx = %1.3f, Vy = %1.3f, Vz = %1.3f\n", vtx[0], vtx[1], vtx[2]);
457 printf("Generated: Px = %1.3f, Py = %1.3f, Pz = %1.3f\n", momGen.Px(), momGen.Py(), momGen.Pz());
458 printf("Reconstructed: Px = %1.3f, Py = %1.3f, Pz = %1.3f\n", momRec.Px(), momRec.Py(), momRec.Pz());
459 printf("Rec. variables: pT %1.3f, pseudo-rapidity %1.3f, theta %1.3f (%1.3f degree), phi %1.3f (%1.3f degree)\n",
460 momRec.Pt(), momRec.Eta(), momRec.Theta(), 180./TMath::Pi() * momRec.Theta(),
461 momRec.Phi(), 180./TMath::Pi() * momRec.Phi());
464 //====================================
465 Bool_t AliMUONTrackLight::IsParentPionOrKaon(Int_t idparent){
466 /// checks if a muon comes from a pion or kaon or a particle that decays into one of these two
467 Int_t pdg = this->GetParentPDGCode(idparent);
468 if (TMath::Abs(pdg)==211 || //pi+
469 TMath::Abs(pdg)==321 || //K+
470 TMath::Abs(pdg)==213 || //rho+
471 TMath::Abs(pdg)==311 || //K0
472 TMath::Abs(pdg)==313 || //K*0
473 TMath::Abs(pdg)==323 //K*+
479 //====================================
480 Bool_t AliMUONTrackLight::IsDiquark(Int_t pdg){
481 /// check if the provided pdg code corresponds to a diquark
482 pdg = TMath::Abs(pdg);
483 if((pdg > 1000) && (pdg%100 < 10)) return kTRUE;