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 **************************************************************************/
18 ///////////////////////////////////////////////////////////////////////////////
20 // AliGenAfterBurnerFlow is a After Burner event generator applying flow.
21 // The generator changes Phi coordinate of the particle momentum.
22 // Flow (directed and elliptical) can be defined on particle type level
25 // Sylwester Radomski, 2002
26 // Martin Poghosyan, 2008
27 // Constantin Loizides, 2010
28 //////////////////////////////////////////////////////////////////////////////
30 #include <Riostream.h>
31 #include <TParticle.h>
32 #include <TLorentzVector.h>
36 #include "AliGenAfterBurnerFlow.h"
37 #include "AliGenCocktailAfterBurner.h"
40 #include "AliCollisionGeometry.h"
41 #include "AliGenCocktailEntry.h"
44 ClassImp(AliGenAfterBurnerFlow)
47 AliGenAfterBurnerFlow::AliGenAfterBurnerFlow():AliGenerator(),
54 // Default Construction
59 AliGenAfterBurnerFlow::AliGenAfterBurnerFlow(Float_t reactionPlane):AliGenerator(),
60 fReactionPlane(TMath::Pi()*reactionPlane/180.),
65 // reactionPlane - Reaction Plane Angle given in Deg [0-360]
66 // but stored and applied in radiants (standard for TParticle & AliCollisionGeometry)
72 ////////////////////////////////////////////////////////////////////////////////////////////////////
74 AliGenAfterBurnerFlow::~AliGenAfterBurnerFlow()
79 void AliGenAfterBurnerFlow::SetDirectedSimple(Int_t pdg, Float_t v1)
83 // The same directed flow is applied to all specified particles
84 // independently on transverse momentum or rapidity
86 // PDG - particle type to apply directed flow
87 // if (PDG == 0) use as default
90 SetFlowParameters(pdg, 1, 0, v1, 0, 0, 0);
93 ////////////////////////////////////////////////////////////////////////////////////////////////////
95 void AliGenAfterBurnerFlow::SetDirectedParam(Int_t pdg, Float_t v11, Float_t v12,
96 Float_t v13, Float_t v14)
100 // Directed flow is parameterised as follows
102 // V1(Pt,Y) = (V11 + V12*Pt) * sign(Y) * (V13 + V14 * abs(Y)^3)
104 // where sign = 1 for Y > 0 and -1 for Y < 0
110 // PDG - particle type to apply directed flow
111 // if (PDG == 0) use as default
114 SetFlowParameters(pdg, 1, 1, v11, v12, v13, v14);
117 ////////////////////////////////////////////////////////////////////////////////////////////////////
119 void AliGenAfterBurnerFlow::SetEllipticSimple(Int_t pdg, Float_t v2)
123 // The same Elliptic flow is applied to all specified particles
124 // independently on transverse momentum or rapidity
126 // PDG - particle type to apply directed flow
127 // if (PDG == 0) use as default
129 // V2 - flow coefficient
131 // NOTE: for starting playing with FLOW
132 // start with this function and values 0.05 - 0.1
135 SetFlowParameters(pdg, 2, 0, v2, 0, 0, 0);
138 ////////////////////////////////////////////////////////////////////////////////////////////////////
140 void AliGenAfterBurnerFlow::SetEllipticParam(Int_t pdg,
141 Float_t v00, Float_t v10, Float_t v11,
147 // Elliptic flow is parametrised to reproduce
148 // V2 of Pions at RHIC energies and is given by:
150 // V2 = (v00 + v10*pt + v11*pt^2) * exp (-v22 * y^2) and zero if V2<0.
153 SetFlowParameters(pdg, 2, 3, v00, v10, v11, v22);
156 void AliGenAfterBurnerFlow::SetEllipticParamPion(Int_t pdg, Float_t v21,
157 Float_t pTmax, Float_t v22)
162 // Elliptic flow is parametrised to reproduce
163 // V2 of Pions at RHIC energies and is given by:
165 // V2 = v21 * (pT/pTMax ) * exp (-v22 * y^2) where pT <= pTmax
166 // v21 * exp (-v22 * y^2) where pT > pTmax
168 // v21 - value at saturation
169 // pTmax - saturation transverse momentum
170 // v22 - rapidity decreasing
173 SetFlowParameters(pdg, 2, 1, v21, pTmax, v22, 0);
176 ////////////////////////////////////////////////////////////////////////////////////////////////////
178 void AliGenAfterBurnerFlow::SetEllipticParamOld(Int_t pdg, Float_t v21, Float_t v22, Float_t v23)
183 // Elliptic flow is parameterised using
184 // old MevSim parameterisation
186 // V2 = (V21 + V22 pT^2) * exp (-v22 * y^2)
189 SetFlowParameters(pdg, 2, 2, v21, v22, v23, 0);
192 ////////////////////////////////////////////////////////////////////////////////////////////////////
194 void AliGenAfterBurnerFlow::SetNpParams(Int_t order, Float_t p0, Float_t p1, Float_t p2, Float_t p3)
197 // Set npart parameterization.
200 fNpParams[0] = order;
207 ////////////////////////////////////////////////////////////////////////////////////////////////////
209 void AliGenAfterBurnerFlow::SetFlowParameters(Int_t pdg, Int_t order, Int_t type,
210 Float_t v1, Float_t v2,Float_t v3,Float_t v4)
216 if(TMath::Abs(pdg)>=fgkPDG){
217 Error("AliAfterBurnerFlow","Overflow");
220 fIsPrim[TMath::Abs(pdg)]=kTRUE;
223 Bool_t newEntry = kTRUE;
227 index = fgkN - order;
231 // try to find existing entry
232 for (Int_t i=0; i<fCounter; i++) {
233 if (pdg == (Int_t)fParams[i][0] &&
234 order == (Int_t)fParams[i][1]) {
243 if (newEntry && (fCounter > fgkN-3)) {
244 Error("AliAfterBurnerFlow","Overflow");
253 // Set new particle type
255 fParams[index][0] = pdg;
256 fParams[index][1] = order;
257 fParams[index][2] = type;
258 fParams[index][3] = v1;
259 fParams[index][4] = v2;
260 fParams[index][5] = v3;
261 fParams[index][6] = v4;
264 ////////////////////////////////////////////////////////////////////////////////////////////////////
266 void AliGenAfterBurnerFlow::Init()
269 // Standard AliGenerator Initializer
272 if(fHow == 0) { Info("AliGenAfterBurnerFlow", "Using the Hijing R.P. Angle event by event "); }
273 else if(fHow == 1){ Info("AliGenAfterBurnerFlow", "Using a fixed R.P. Angle for every event ") ; }
274 else { Info("AliGenAfterBurnerFlow",
275 "Using a random R.P. Angle event by event ( ! not the same used by Hijing ! ) "); }
278 ////////////////////////////////////////////////////////////////////////////////////////////////////
280 Float_t AliGenAfterBurnerFlow::GetCoefficient(Int_t pdg, Int_t n, Float_t Pt, Float_t Y) const
284 // Return Flow Coefficient for a given particle type flow order
285 // and particle momentum (Pt, Y)
288 Int_t index = fgkN - n; // default index (for all pdg)
291 // try to find specific parametrs
293 for (Int_t i=0; i<fCounter; i++) {
294 if ((Int_t)fParams[i][0] == pdg &&
295 (Int_t)fParams[i][1] == n) {
304 Int_t type = (Int_t)fParams[index][2];
306 if ((Int_t)fParams[index][1] == 1) { // Directed
309 v = fParams[index][3];
311 v = (fParams[index][3] + fParams[index][4] * Pt) * TMath::Sign((Float_t)1.,Y) *
312 (fParams[index][5] + fParams[index][6] * TMath::Abs(Y*Y*Y) );
316 if (type == 0) v = fParams[index][3];
318 // Pion parameterisation
320 if (Pt < fParams[index][4])
321 v = fParams[index][3] * (Pt / fParams[index][4]) ;
323 v = fParams[index][3];
325 v *= TMath::Exp( - fParams[index][5] * Y * Y);
328 // Old parameterisation
330 v = (fParams[index][3] + fParams[index][4] * Pt * Pt) *
331 TMath::Exp( - fParams[index][5] * Y * Y);
333 // New v2 parameterisation
335 v = (fParams[index][3] + fParams[index][4] *Pt + fParams[index][5] *Pt*Pt) *
336 TMath::Exp( - fParams[index][6] * Y*Y);
345 ////////////////////////////////////////////////////////////////////////////////////////////////////
347 Float_t AliGenAfterBurnerFlow::GetNpNorm(Int_t npart) const
350 // Calculate npart norm.
356 Int_t order = (Int_t)fNpParams[0];
362 for (Int_t i=0; i<=order; i++) {
363 ret += npp*fNpParams[i+1];
369 ////////////////////////////////////////////////////////////////////////////////////////////////////
371 Bool_t AliGenAfterBurnerFlow::IsPrimary(Int_t pdg) const
373 if(pdg>=fgkPDG) return kFALSE;
377 ////////////////////////////////////////////////////////////////////////////////////////////////////
379 Double_t CalcAngle(Double_t phi, Double_t phi0, Double_t phiRP, Double_t v2, Double_t v1=0.)
381 // Calculate relative angle
382 Double_t phi1 = phi-(phi+2*v1*TMath::Sin(phi-phiRP)+v2*TMath::Sin(2*(phi-phiRP))-phi0)/
383 (1.+2*v1*TMath::Cos(phi-phiRP)+ 2*v2*TMath::Cos(2*(phi-phiRP)));
384 if(TMath::Abs(phi/phi1-1.)<0.00001) return phi1;
385 return CalcAngle(phi1, phi0, phiRP, v2, v1);
388 ////////////////////////////////////////////////////////////////////////////////////////////////////
390 void AliGenAfterBurnerFlow::InitPrimaries()
392 // Init the primary particle list
393 for(Int_t i=0; i<fgkPDG; i++) fIsPrim[i]=kFALSE;
472 ////////////////////////////////////////////////////////////////////////////////////////////////////
474 void AliGenAfterBurnerFlow::Generate()
477 // AliGenerator generate function doing actual job.
480 // 1. loop over particles on the stack and choose primaries
481 // 2. calculate delta phi
482 // 3. change phi of primary particle and if it is non-stable
483 // then its daughters' phi and vertex also
485 // For more details see :
487 // PWG2 meeting on 06.05.2008 and 03.06.2008
491 for(Int_t ii=0; ii<fCounter;ii++)
493 printf("%d %f %f %f %f\n",ii,fParams[ii][0],fParams[ii][1],fParams[ii][2],fParams[ii][3]);
496 AliGenCocktailAfterBurner *gen;
499 TParticle *particleM;
500 TLorentzVector momentum;
501 TLorentzVector vertex;
507 // Get Stack of the first Generator
508 // gen = (AliGenCocktailAfterBurner *)gAlice->Generator();
509 gen = (AliGenCocktailAfterBurner *)gAlice->GetMCApp()->Generator();
512 AliGenerator* genHijing = 0 ;
513 AliCollisionGeometry* geom = 0 ;
514 AliGenCocktailEntry* entry = 0 ;
515 TList* fEntries = 0 ;
517 TRandom* rand = new TRandom(0) ;
518 for(Int_t ns=0;ns<gen->GetNumberOfEvents();ns++)
520 gen->SetActiveEventNumber(ns) ;
522 fStack = gen->GetStack(ns);
523 fEntries = gen->Entries() ;
525 TIter next(fEntries) ;
528 if(fHow == 0) // hijing R.P.
530 while((entry = (AliGenCocktailEntry*)next()))
532 Info("Generate (e)","Using R.P. from HIJING ... ");
533 genHijing = entry->Generator() ;
534 if(genHijing->ProvidesCollisionGeometry())
536 geom = gen->GetCollisionGeometry(ns) ;
537 fReactionPlane = geom->ReactionPlaneAngle() ;
538 npart = geom->ProjectileParticipants() + geom->TargetParticipants();
543 Error("Generate (e)", "NO CollisionGeometry !!! - using fixed R.P. angle = 0. ") ;
544 fReactionPlane = 0. ;
548 else if(fHow ==1 ) // fixed R.P.
550 Info("Generate (e)","Using fixed R.P. ...");
554 Info("Generate (e)","Using random R.P.s ... ");
555 fReactionPlane = 2 * TMath::Pi() * rand->Rndm() ;
558 cout << " * Reaction Plane Angle (event " << ns << ") = " << fReactionPlane <<
559 " rad. ( = " << (360*fReactionPlane/(2*TMath::Pi())) << " deg.) Npart = " << npart << "* " << endl ;
561 Int_t nParticles = fStack->GetNprimary();
562 for (Int_t i=0; i<nParticles; i++)
564 particle = fStack->Particle(i);
566 Int_t iM=particle->GetMother(0);
567 pdg = particle->GetPdgCode();
569 //exclude incoming protons in PYTHIA
570 if(particle->GetPdgCode()==21) continue;
572 if(TMath::Abs(pdg)>=fgkPDG) continue;
573 // is particle primary?
574 if(!fIsPrim[TMath::Abs(pdg)]) continue;
578 particleM = fStack->Particle(iM);
579 Int_t pdgM = TMath::Abs(particleM->GetPdgCode());
580 // is mother primary?
581 if((TMath::Abs(pdgM)<fgkPDG)&&fIsPrim[TMath::Abs(pdgM)]) continue;
584 particle->Momentum(momentum);
585 phi = particle->Phi();
591 if(TMath::Abs(momentum.Z()) != TMath::Abs(momentum.T()))
592 y = momentum.Rapidity() ;
594 Double_t v1 = GetCoefficient(pdg, 1, pt, y);
595 Double_t v2 = GetCoefficient(pdg, 2, pt, y);
596 Double_t npartnorm = GetNpNorm(npart);
599 //printf("ntup %d %f %f %f %f %f\n ",npart, v1, v2, pt, y, npartnorm);
601 Double_t phi1 = CalcAngle(phi, phi, fReactionPlane,v2,v1);
607 Info("Generate","Flow After Burner: DONE");
610 ////////////////////////////////////////////////////////////////////////////////////////////////////
612 void AliGenAfterBurnerFlow::Rotate(Int_t i, Double_t phi, Bool_t IsPrim)
615 TParticle* particle = fStack->Particle(i);
617 TLorentzVector momentum;
618 particle->Momentum(momentum);
619 momentum.RotateZ(phi);
620 particle->SetMomentum(momentum);
624 TLorentzVector vertex;
625 particle->ProductionVertex(vertex);
627 particle->SetProductionVertex(vertex);
630 if(particle->GetFirstDaughter()<0) return;
631 for(Int_t iD=particle->GetFirstDaughter(); iD<=particle->GetLastDaughter(); iD++) Rotate(iD, phi, kFALSE);