Line data Source code
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 :
16 : /* $Id$ */
17 :
18 : //
19 : // AliGenGeVSim is a class implementing GeVSim event generator.
20 : //
21 : // GeVSim is a simple Monte-Carlo event generator for testing detector and
22 : // algorythm performance especialy concerning flow and event-by-event studies
23 : //
24 : // In this event generator particles are generated from thermal distributions
25 : // without any dynamics and addicional constrains. Distribution parameters like
26 : // multiplicity, particle type yields, inverse slope parameters, flow coeficients
27 : // and expansion velocities are expleicite defined by the user.
28 : //
29 : // GeVSim contains four thermal distributions the same as
30 : // MevSim event generator developed for STAR experiment.
31 : //
32 : // In addition custom distributions can be used be the mean
33 : // either two dimensional formula (TF2), a two dimensional histogram or
34 : // two one dimensional histograms.
35 : //
36 : // Azimuthal distribution is deconvoluted from (Pt,Y) distribution
37 : // and is described by two Fourier coefficients representing
38 : // Directed and Elliptic flow.
39 : //
40 : ////////////////////////////////////////////////////////////////////////////////
41 : //
42 : // To apply flow to event ganerated by an arbitraly event generator
43 : // refer to AliGenAfterBurnerFlow class.
44 : //
45 : ////////////////////////////////////////////////////////////////////////////////
46 : //
47 : // For examples, parameters and testing macros refer to:
48 : // http:/home.cern.ch/radomski
49 : //
50 : // for more detailed description refer to ALICE NOTE
51 : // "GeVSim Monte-Carlo Event Generator"
52 : // S.Radosmki, P. Foka.
53 : //
54 : // Author:
55 : // Sylwester Radomski,
56 : // GSI, March 2002
57 : //
58 : // S.Radomski@gsi.de
59 : //
60 : ////////////////////////////////////////////////////////////////////////////////
61 : //
62 : // Updated and revised: September 2002, S. Radomski, GSI
63 : //
64 : ////////////////////////////////////////////////////////////////////////////////
65 :
66 : #include <RVersion.h>
67 : #include <Riostream.h>
68 : #include <TCanvas.h>
69 : #include <TF1.h>
70 : #include <TF2.h>
71 : #include <TH1.h>
72 : #include <TH2.h>
73 : #include <TObjArray.h>
74 : #include <TPDGCode.h>
75 : #include <TParticle.h>
76 : #include <TDatabasePDG.h>
77 : #include <TROOT.h>
78 :
79 :
80 : #include "AliGeVSimParticle.h"
81 : #include "AliGenGeVSim.h"
82 : #include "AliGenGeVSimEventHeader.h"
83 : #include "AliGenerator.h"
84 : #include "AliRun.h"
85 :
86 :
87 : using std::cout;
88 : using std::endl;
89 6 : ClassImp(AliGenGeVSim)
90 :
91 : //////////////////////////////////////////////////////////////////////////////////
92 :
93 : AliGenGeVSim::AliGenGeVSim() :
94 0 : AliGenerator(-1),
95 0 : fModel(0),
96 0 : fPsi(0),
97 0 : fIsMultTotal(kTRUE),
98 0 : fPtFormula(0),
99 0 : fYFormula(0),
100 0 : fPhiFormula(0),
101 0 : fCurrentForm(0),
102 0 : fPtYHist(0),
103 0 : fPartTypes(0)
104 0 : {
105 : //
106 : // Default constructor
107 : //
108 :
109 0 : for (Int_t i=0; i<4; i++)
110 0 : fPtYFormula[i] = 0;
111 0 : for (Int_t i=0; i<2; i++)
112 0 : fHist[i] = 0;
113 0 : }
114 :
115 : //////////////////////////////////////////////////////////////////////////////////
116 :
117 : AliGenGeVSim::AliGenGeVSim(Float_t psi, Bool_t isMultTotal)
118 0 : : AliGenerator(-1),
119 0 : fModel(0),
120 0 : fPsi(psi),
121 0 : fIsMultTotal(isMultTotal),
122 0 : fPtFormula(0),
123 0 : fYFormula(0),
124 0 : fPhiFormula(0),
125 0 : fCurrentForm(0),
126 0 : fPtYHist(0),
127 0 : fPartTypes(0)
128 0 : {
129 : //
130 : // Standard Constructor.
131 : //
132 : // models - thermal model to be used:
133 : // 1 - deconvoluted pt and Y source
134 : // 2,3 - thermalized sphericaly symetric sources
135 : // 4 - thermalized source with expansion
136 : // 5 - custom model defined in TF2 object named "gevsimPtY"
137 : // 6 - custom model defined by two 1D histograms
138 : // 7 - custom model defined by 2D histogram
139 : //
140 : // psi - reaction plane in degrees
141 : // isMultTotal - multiplicity mode
142 : // kTRUE - total multiplicity (default)
143 : // kFALSE - dN/dY at midrapidity
144 : //
145 :
146 : // checking consistancy
147 :
148 0 : if (psi < 0 || psi > 360 )
149 0 : Error ("AliGenGeVSim", "Reaction plane angle ( %13.3f )out of range [0..360]", psi);
150 :
151 0 : fPsi = psi * TMath::Pi() / 180. ;
152 0 : fIsMultTotal = isMultTotal;
153 :
154 : // Initialization
155 :
156 0 : fPartTypes = new TObjArray();
157 0 : InitFormula();
158 0 : }
159 :
160 : //////////////////////////////////////////////////////////////////////////////////
161 :
162 0 : AliGenGeVSim::~AliGenGeVSim() {
163 : //
164 : // Default Destructor
165 : //
166 : // Removes TObjArray keeping list of registered particle types
167 : //
168 :
169 0 : if (fPartTypes != NULL) delete fPartTypes;
170 0 : }
171 :
172 :
173 : //////////////////////////////////////////////////////////////////////////////////
174 :
175 : Bool_t AliGenGeVSim::CheckPtYPhi(Float_t pt, Float_t y, Float_t phi) const {
176 : //
177 : // private function used by Generate()
178 : //
179 : // Check bounds of Pt, Rapidity and Azimuthal Angle of a track
180 : // Used only when generating particles from a histogram
181 : //
182 :
183 0 : if ( TestBit(kPtRange) && ( pt < fPtMin || pt > fPtMax )) return kFALSE;
184 0 : if ( TestBit(kPhiRange) && ( phi < fPhiMin || phi > fPhiMax )) return kFALSE;
185 0 : if ( TestBit(kYRange) && ( y < fYMin || y > fYMax )) return kFALSE;
186 :
187 0 : return kTRUE;
188 0 : }
189 :
190 : //////////////////////////////////////////////////////////////////////////////////
191 :
192 : Bool_t AliGenGeVSim::CheckAcceptance(Float_t p[3]) {
193 : //
194 : // private function used by Generate()
195 : //
196 : // Check bounds of a total momentum and theta of a track
197 : //
198 :
199 0 : if ( TestBit(kThetaRange) ) {
200 :
201 0 : Double_t theta = TMath::ATan2( TMath::Sqrt(p[0]*p[0]+p[1]*p[1]), p[2]);
202 0 : if ( theta < fThetaMin || theta > fThetaMax ) return kFALSE;
203 0 : }
204 :
205 :
206 0 : if ( TestBit(kMomentumRange) ) {
207 :
208 0 : Double_t momentum = TMath::Sqrt(p[0]*p[0] + p[1]*p[1] + p[2]*p[2]);
209 0 : if ( momentum < fPMin || momentum > fPMax) return kFALSE;
210 0 : }
211 :
212 0 : return kTRUE;
213 0 : }
214 :
215 : //////////////////////////////////////////////////////////////////////////////////
216 :
217 : // Deconvoluted Pt Y formula
218 :
219 : static Double_t aPtForm(Double_t * x, Double_t * par) {
220 : // ptForm: pt -> x[0] , mass -> [0] , temperature -> [1]
221 : // Description as string: " x * exp( -sqrt([0]*[0] + x*x) / [1] )"
222 :
223 0 : return x[0] * TMath::Exp( -sqrt(par[0]*par[0] + x[0]*x[0]) / par[1]);
224 : }
225 :
226 : static Double_t aYForm(Double_t * x, Double_t * par) {
227 : // y Form: y -> x[0] , sigmaY -> [0]
228 : // Description as string: " exp ( - x*x / (2 * [0]*[0] ) )"
229 :
230 0 : return TMath::Exp ( - x[0]*x[0] / (2 * par[0]*par[0] ) );
231 : }
232 :
233 : // Models 1-3
234 : // Description as strings:
235 :
236 : // const char *kFormE = " ( sqrt([0]*[0] + x*x) * cosh(y) ) ";
237 : // const char *kFormG = " ( 1 / sqrt( 1 - [2]*[2] ) ) ";
238 : // const char *kFormYp = "( [2]*sqrt(([0]*[0]+x*x)*cosh(y)*cosh(y)-[0]*[0])/([1]*sqrt(1-[2]*[2]))) ";
239 :
240 : // const char* kFormula[3] = {
241 : // " x * %s * exp( -%s / [1]) ",
242 : // " (x * %s) / ( exp( %s / [1]) - 1 ) ",
243 : // " x*%s*exp(-%s*%s/[1])*((sinh(%s)/%s)+([1]/(%s*%s))*(sinh(%s)/%s-cosh(%s)))"
244 : // };
245 : // printf(kFormula[0], kFormE, kFormE);
246 : // printf(kFormula[1], kFormE, kFormE);
247 : // printf(kFormula[2], kFormE, kFormG, kFormE, kFormYp, kFormYp, kFormG, kFormE, kFormYp, kFormYp, kFormYp);
248 :
249 :
250 : static Double_t aPtYFormula0(Double_t *x, Double_t * par) {
251 : // pt -> x , Y -> y
252 : // mass -> [0] , temperature -> [1] , expansion velocity -> [2]
253 :
254 0 : Double_t aFormE = TMath::Sqrt(par[0]*par[0] + x[0]*x[0]) * TMath::CosH(x[1]);
255 0 : return x[0] * aFormE * TMath::Exp(-aFormE/par[1]);
256 : }
257 :
258 : static Double_t aPtYFormula1(Double_t *x, Double_t * par) {
259 : // pt -> x , Y -> y
260 : // mass -> [0] , temperature -> [1] , expansion velocity -> [2]
261 :
262 0 : Double_t aFormE = TMath::Sqrt(par[0]*par[0] + x[0]*x[0]) * TMath::CosH(x[1]);
263 0 : return x[0] * aFormE / ( TMath::Exp( aFormE / par[1]) - 1 );
264 : }
265 :
266 : static Double_t aPtYFormula2(Double_t *x, Double_t * par) {
267 : // pt -> x , Y -> y
268 : // mass -> [0] , temperature -> [1] , expansion velocity -> [2]
269 :
270 0 : Double_t aFormE = TMath::Sqrt(par[0]*par[0] + x[0]*x[0]) * TMath::CosH(x[1]);
271 0 : Double_t aFormG = 1 / TMath::Sqrt((1.-par[2])*(1.+par[2]));
272 0 : Double_t aFormYp = par[2]*TMath::Sqrt( (par[0]*par[0] + x[0]*x[0])
273 0 : * (TMath::CosH(x[1])-par[0])*(TMath::CosH(x[1])+par[0]))
274 0 : /( par[1]*TMath::Sqrt((1.-par[2])*(1.+par[2])));
275 :
276 0 : return x[0] * aFormE * TMath::Exp( - aFormG * aFormE / par[1])
277 0 : *( TMath::SinH(aFormYp)/aFormYp
278 0 : + par[1]/(aFormG*aFormE)
279 0 : * ( TMath::SinH(aFormYp)/aFormYp-TMath::CosH(aFormYp) ) );
280 : }
281 :
282 : // Phi Flow Formula
283 :
284 : static Double_t aPhiForm(Double_t * x, Double_t * par) {
285 : // phi -> x
286 : // Psi -> [0] , Direct Flow -> [1] , Elliptical Flow -> [2]
287 : // Description as string: " 1 + 2*[1]*cos(x-[0]) + 2*[2]*cos(2*(x-[0])) "
288 :
289 0 : return 1 + 2*par[1]*TMath::Cos(x[0]-par[0])
290 0 : + 2*par[2]*TMath::Cos(2*(x[0]-par[0]));
291 : }
292 :
293 : void AliGenGeVSim::InitFormula() {
294 : //
295 : // private function
296 : //
297 : // Initalizes formulas used in GeVSim.
298 :
299 : // Deconvoluted Pt Y formula
300 :
301 0 : fPtFormula = new TF1("gevsimPt", &aPtForm, 0, 3, 2);
302 0 : fYFormula = new TF1("gevsimRapidity", &aYForm, -3, 3,1);
303 :
304 0 : fPtFormula->SetParNames("mass", "temperature");
305 0 : fPtFormula->SetParameters(1., 1.);
306 :
307 0 : fYFormula->SetParName(0, "sigmaY");
308 0 : fYFormula->SetParameter(0, 1.);
309 :
310 : // Grid for Pt and Y
311 0 : fPtFormula->SetNpx(100);
312 0 : fYFormula->SetNpx(100);
313 :
314 :
315 : // Models 1-3
316 :
317 0 : fPtYFormula[0] = new TF2("gevsimPtY_2", &aPtYFormula0, 0, 3, -2, 2, 2);
318 :
319 0 : fPtYFormula[1] = new TF2("gevsimPtY_3", &aPtYFormula1, 0, 3, -2, 2, 2);
320 :
321 0 : fPtYFormula[2] = new TF2("gevsimPtY_4", &aPtYFormula2, 0, 3, -2, 2, 3);
322 :
323 0 : fPtYFormula[3] = 0;
324 :
325 :
326 : // setting names & initialisation
327 :
328 0 : const char* kParamNames[3] = {"mass", "temperature", "expVel"};
329 :
330 : Int_t i, j;
331 0 : for (i=0; i<3; i++) {
332 :
333 0 : fPtYFormula[i]->SetNpx(100); // step 30 MeV
334 0 : fPtYFormula[i]->SetNpy(100); //
335 :
336 0 : for (j=0; j<3; j++) {
337 :
338 0 : if ( i != 2 && j == 2 ) continue; // ExpVel
339 0 : fPtYFormula[i]->SetParName(j, kParamNames[j]);
340 0 : fPtYFormula[i]->SetParameter(j, 0.5);
341 0 : }
342 : }
343 :
344 : // Phi Flow Formula
345 :
346 0 : fPhiFormula = new TF1("gevsimPhi", &aPhiForm, 0, 2*TMath::Pi(), 3);
347 :
348 0 : fPhiFormula->SetParNames("psi", "directed", "elliptic");
349 0 : fPhiFormula->SetParameters(0., 0., 0.);
350 :
351 0 : fPhiFormula->SetNpx(180);
352 :
353 0 : }
354 :
355 : //////////////////////////////////////////////////////////////////////////////////
356 :
357 : void AliGenGeVSim::AddParticleType(AliGeVSimParticle *part) {
358 : //
359 : // Adds new type of particles.
360 : //
361 : // Parameters are defeined in AliGeVSimParticle object
362 : // This method has to be called for every particle type
363 : //
364 :
365 0 : if (fPartTypes == NULL)
366 0 : fPartTypes = new TObjArray();
367 :
368 0 : fPartTypes->Add(part);
369 0 : }
370 :
371 : //////////////////////////////////////////////////////////////////////////////////
372 :
373 : void AliGenGeVSim::SetMultTotal(Bool_t isTotal) {
374 : //
375 : //
376 : //
377 :
378 0 : fIsMultTotal = isTotal;
379 0 : }
380 :
381 : //////////////////////////////////////////////////////////////////////////////////
382 :
383 : Float_t AliGenGeVSim::FindScaler(Int_t paramId, Int_t pdg) {
384 : //
385 : // private function
386 : // Finds Scallar for a given parameter.
387 : // Function used in event-by-event mode.
388 : //
389 : // There are two types of scallars: deterministic and random
390 : // and they can work on either global or particle type level.
391 : // For every variable there are four scallars defined.
392 : //
393 : // Scallars are named as folowa
394 : // deterministic global level : "gevsimParam" (eg. "gevsimTemp")
395 : // deterinistig type level : "gevsimPdgParam" (eg. "gevsim211Mult")
396 : // random global level : "gevsimParamRndm" (eg. "gevsimMultRndm")
397 : // random type level : "gevsimPdgParamRndm" (eg. "gevsim-211V2Rndm");
398 : //
399 : // Pdg - code of a particle type in PDG standard (see: http://pdg.lbl.gov)
400 : // Param - parameter name. Allowed parameters:
401 : //
402 : // "Temp" - inverse slope parameter
403 : // "SigmaY" - rapidity width - for model (1) only
404 : // "ExpVel" - expansion velocity - for model (4) only
405 : // "V1" - directed flow
406 : // "V2" - elliptic flow
407 : // "Mult" - multiplicity
408 : //
409 :
410 :
411 : static const char* params[] = {"Temp", "SigmaY", "ExpVel", "V1", "V2", "Mult"};
412 : static const char* ending[] = {"", "Rndm"};
413 :
414 : static const char* patt1 = "gevsim%s%s";
415 : static const char* patt2 = "gevsim%d%s%s";
416 :
417 0 : char buffer[80];
418 : TF1 *form;
419 :
420 : Float_t scaler = 1.;
421 :
422 : // Scaler evoluation: i - global/local, j - determ/random
423 :
424 : Int_t i, j;
425 :
426 0 : for (i=0; i<2; i++) {
427 0 : for (j=0; j<2; j++) {
428 :
429 : form = 0;
430 :
431 0 : if (i == 0) snprintf(buffer, 80, patt1, params[paramId], ending[j]);
432 0 : else snprintf(buffer, 80, patt2, pdg, params[paramId], ending[j]);
433 :
434 0 : form = (TF1 *)gROOT->GetFunction(buffer);
435 :
436 0 : if (form != 0) {
437 0 : if (j == 0) scaler *= form->Eval(gAlice->GetEvNumber());
438 0 : if (j == 1) {
439 0 : form->SetParameter(0, gAlice->GetEvNumber());
440 0 : scaler *= form->GetRandom();
441 0 : }
442 : }
443 : }
444 : }
445 :
446 0 : return scaler;
447 0 : }
448 :
449 : //////////////////////////////////////////////////////////////////////////////////
450 :
451 : void AliGenGeVSim::DetermineReactionPlane() {
452 : //
453 : // private function used by Generate()
454 : //
455 : // Retermines Reaction Plane angle and set this value
456 : // as a parameter [0] in fPhiFormula
457 : //
458 : // Note: if "gevsimPsiRndm" function is found it override both
459 : // "gevsimPhi" function and initial fPsi value
460 : //
461 :
462 : TF1 *form;
463 :
464 : form = 0;
465 0 : form = (TF1 *)gROOT->GetFunction("gevsimPsi");
466 0 : if (form) fPsi = form->Eval(gAlice->GetEvNumber()) * TMath::Pi() / 180;
467 :
468 : form = 0;
469 0 : form = (TF1 *)gROOT->GetFunction("gevsimPsiRndm");
470 0 : if (form) fPsi = form->GetRandom() * TMath::Pi() / 180;
471 :
472 :
473 0 : cout << "Psi = " << fPsi << "\t" << (Int_t)(fPsi*180./TMath::Pi()) << endl;
474 :
475 0 : fPhiFormula->SetParameter(0, fPsi);
476 0 : }
477 :
478 : //////////////////////////////////////////////////////////////////////////////////
479 :
480 : Float_t AliGenGeVSim::GetdNdYToTotal() {
481 : //
482 : // Private, helper function used by Generate()
483 : //
484 : // Returns total multiplicity to dN/dY ration using current distribution.
485 : // The function have to be called after setting distribution and its
486 : // parameters (like temperature).
487 : //
488 :
489 : Float_t integ, mag;
490 : const Double_t kMaxPt = 3.0, kMaxY = 2.;
491 :
492 0 : if (fModel == 1) {
493 :
494 0 : integ = fYFormula->Integral(-kMaxY, kMaxY);
495 0 : mag = fYFormula->Eval(0);
496 0 : return integ/mag;
497 : }
498 :
499 : // 2D formula standard or custom
500 :
501 0 : if (fModel > 1 && fModel < 6) {
502 :
503 0 : integ = ((TF2*)fCurrentForm)->Integral(0,kMaxPt, -kMaxY, kMaxY);
504 0 : mag = ((TF2*)fCurrentForm)->Integral(0, kMaxPt, -0.1, 0.1) / 0.2;
505 0 : return integ/mag;
506 : }
507 :
508 : // 2 1D histograms
509 :
510 0 : if (fModel == 6) {
511 :
512 0 : integ = fHist[1]->Integral();
513 0 : mag = fHist[0]->GetBinContent(fHist[0]->FindBin(0.));
514 0 : mag /= fHist[0]->GetBinWidth(fHist[0]->FindBin(0.));
515 0 : return integ/mag;
516 : }
517 :
518 : // 2D histogram
519 :
520 0 : if (fModel == 7) {
521 :
522 : // Not tested ...
523 0 : Int_t yBins = fPtYHist->GetNbinsY();
524 0 : Int_t ptBins = fPtYHist->GetNbinsX();
525 :
526 0 : integ = fPtYHist->Integral(0, ptBins, 0, yBins);
527 0 : mag = fPtYHist->Integral(0, ptBins, (yBins/2)-1, (yBins/2)+1 ) / 2;
528 0 : return integ/mag;
529 : }
530 :
531 0 : return 1;
532 0 : }
533 :
534 : //////////////////////////////////////////////////////////////////////////////////
535 :
536 : void AliGenGeVSim::SetFormula(Int_t pdg) {
537 : //
538 : // Private function used by Generate()
539 : //
540 : // Configure a formula for a given particle type and model Id (in fModel).
541 : // If custom formula or histogram was selected the function tries
542 : // to find it.
543 : //
544 : // The function implements naming conventions for custom distributions names
545 : //
546 :
547 0 : char buff[40];
548 0 : const char* msg[4] = {
549 : "Custom Formula for Pt Y distribution not found [pdg = %d]",
550 : "Histogram for Pt distribution not found [pdg = %d]",
551 : "Histogram for Y distribution not found [pdg = %d]",
552 : "HIstogram for Pt Y dostribution not found [pdg = %d]"
553 : };
554 :
555 0 : const char* pattern[8] = {
556 : "gevsimDistPtY", "gevsimDist%dPtY",
557 : "gevsimHistPt", "gevsimHist%dPt",
558 : "gevsimHistY", "gevsimHist%dY",
559 : "gevsimHistPtY", "gevsimHist%dPtY"
560 : };
561 :
562 : const char *where = "SetFormula";
563 :
564 :
565 0 : if (fModel < 1 || fModel > 7)
566 0 : Error("SetFormula", "Model Id (%d) out of range [1-7]", fModel);
567 :
568 :
569 : // standard models
570 :
571 : #if ROOT_VERSION_CODE >= ROOT_VERSION(6,3,3)
572 : if (fModel == 1) fCurrentForm = fPtFormula->GetFormula();
573 : if (fModel > 1 && fModel < 5) fCurrentForm = fPtYFormula[fModel-2]->GetFormula();
574 : #else
575 0 : if (fModel == 1) fCurrentForm = fPtFormula;
576 0 : if (fModel > 1 && fModel < 5) fCurrentForm = fPtYFormula[fModel-2];
577 : #endif
578 :
579 :
580 : // custom model defined by a formula
581 :
582 0 : if (fModel == 5) {
583 :
584 0 : fCurrentForm = 0;
585 : #if ROOT_VERSION_CODE >= ROOT_VERSION(6,3,3)
586 : TF2* tmpTF2 = (TF2*)gROOT->GetFunction(pattern[0]);
587 : if (tmpTF2) fCurrentForm = tmpTF2->GetFormula();
588 : #else
589 0 : fCurrentForm = (TF2*)gROOT->GetFunction(pattern[0]);
590 : #endif
591 :
592 0 : if (!fCurrentForm) {
593 :
594 0 : snprintf(buff, 40, pattern[1], pdg);
595 : #if ROOT_VERSION_CODE >= ROOT_VERSION(6,3,3)
596 : tmpTF2 = (TF2*)gROOT->GetFunction(buff);
597 : if (tmpTF2) fCurrentForm = tmpTF2->GetFormula();
598 : #else
599 0 : fCurrentForm = (TF2*)gROOT->GetFunction(buff);
600 : #endif
601 :
602 0 : if (!fCurrentForm) Error(where, msg[0], pdg);
603 : }
604 : }
605 :
606 : // 2 1D histograms
607 :
608 0 : if (fModel == 6) {
609 :
610 0 : for (Int_t i=0; i<2; i++) {
611 :
612 0 : fHist[i] = 0;
613 0 : fHist[i] = (TH1D*)gROOT->FindObject(pattern[2+2*i]);
614 :
615 0 : if (!fHist[i]) {
616 :
617 0 : snprintf(buff, 40, pattern[3+2*i], pdg);
618 0 : fHist[i] = (TH1D*)gROOT->FindObject(buff);
619 :
620 0 : if (!fHist[i]) Error(where, msg[1+i], pdg);
621 : }
622 : }
623 0 : }
624 :
625 : // 2d histogram
626 :
627 0 : if (fModel == 7) {
628 :
629 0 : fPtYHist = 0;
630 0 : fPtYHist = (TH2D*)gROOT->FindObject(pattern[6]);
631 :
632 0 : if (!fPtYHist) {
633 :
634 0 : snprintf(buff, 40, pattern[7], pdg);
635 0 : fPtYHist = (TH2D*)gROOT->FindObject(buff);
636 0 : }
637 :
638 0 : if (!fPtYHist) Error(where, msg[3], pdg);
639 : }
640 :
641 0 : }
642 :
643 : //////////////////////////////////////////////////////////////////////////////////
644 :
645 : void AliGenGeVSim:: AdjustFormula() {
646 : //
647 : // Private Function
648 : // Adjust fomula bounds according to acceptance cuts.
649 : //
650 : // Since GeVSim is producing "thermal" particles Pt
651 : // is cut at 3 GeV even when acceptance extends to grater momenta.
652 : //
653 : // WARNING !
654 : // If custom formula was provided function preserves
655 : // original cuts.
656 : //
657 :
658 : const Double_t kMaxPt = 3.0;
659 : const Double_t kMaxY = 2.0;
660 : Double_t minPt, maxPt, minY, maxY;
661 :
662 :
663 0 : if (fModel > 4) return;
664 :
665 : // max Pt
666 0 : if (TestBit(kPtRange) && fPtMax < kMaxPt ) maxPt = fPtMax;
667 : else maxPt = kMaxPt;
668 :
669 : // min Pt
670 0 : if (TestBit(kPtRange)) minPt = fPtMin;
671 : else minPt = 0;
672 :
673 0 : if (TestBit(kPtRange) && fPtMin > kMaxPt )
674 0 : Warning("Acceptance", "Minimum Pt (%3.2f GeV) greater that 3.0 GeV ", fPtMin);
675 :
676 : // Max Pt < Max P
677 0 : if (TestBit(kMomentumRange) && fPtMax < maxPt) maxPt = fPtMax;
678 :
679 : // max and min rapidity
680 0 : if (TestBit(kYRange)) {
681 0 : minY = fYMin;
682 0 : maxY = fYMax;
683 0 : } else {
684 : minY = -kMaxY;
685 : maxY = kMaxY;
686 : }
687 :
688 : // adjust formula
689 :
690 0 : if (fModel == 1) {
691 0 : fPtFormula->SetRange(fPtMin, maxPt);
692 0 : fYFormula->SetRange(fYMin, fYMax);
693 0 : }
694 :
695 0 : if (fModel > 1)
696 0 : ((TF2*)fCurrentForm)->SetRange(minPt, minY, maxPt, maxY);
697 :
698 : // azimuthal cut
699 :
700 0 : if (TestBit(kPhiRange))
701 0 : fPhiFormula->SetRange(fPhiMin, fPhiMax);
702 :
703 0 : }
704 :
705 : //////////////////////////////////////////////////////////////////////////////////
706 :
707 : void AliGenGeVSim::GetRandomPtY(Double_t &pt, Double_t &y) {
708 : //
709 : // Private function used by Generate()
710 : //
711 : // Returns random values of Pt and Y corresponding to selected
712 : // distribution.
713 : //
714 :
715 0 : if (fModel == 1) {
716 0 : pt = fPtFormula->GetRandom();
717 0 : y = fYFormula->GetRandom();
718 0 : return;
719 : }
720 :
721 0 : if (fModel > 1 && fModel < 6) {
722 0 : ((TF2*)fCurrentForm)->GetRandom2(pt, y);
723 0 : return;
724 : }
725 :
726 0 : if (fModel == 6) {
727 0 : pt = fHist[0]->GetRandom();
728 0 : y = fHist[1]->GetRandom();
729 0 : }
730 :
731 0 : if (fModel == 7) {
732 0 : fPtYHist->GetRandom2(pt, y);
733 0 : return;
734 : }
735 0 : }
736 :
737 : //////////////////////////////////////////////////////////////////////////////////
738 :
739 : void AliGenGeVSim::Init() {
740 : //
741 : // Standard AliGenerator initializer.
742 : // does nothing
743 : //
744 0 : }
745 :
746 : //////////////////////////////////////////////////////////////////////////////////
747 :
748 : void AliGenGeVSim::Generate() {
749 : //
750 : // Standard AliGenerator function
751 : // This function do actual job and puts particles on stack.
752 : //
753 :
754 : PDG_t pdg; // particle type
755 : Float_t mass; // particle mass
756 0 : Float_t orgin[3] = {0,0,0}; // particle orgin [cm]
757 0 : Float_t polar[3] = {0,0,0}; // polarisation
758 : Float_t time = 0; // time of creation
759 :
760 : Float_t multiplicity = 0;
761 : Bool_t isMultTotal = kTRUE;
762 :
763 : Float_t paramScaler;
764 : Float_t directedScaller = 1., ellipticScaller = 1.;
765 :
766 0 : TLorentzVector *v = new TLorentzVector(0,0,0,0);
767 :
768 : const Int_t kParent = -1;
769 0 : Int_t id;
770 :
771 : // vertexing
772 0 : VertexInternal();
773 0 : orgin[0] = fVertex[0];
774 0 : orgin[1] = fVertex[1];
775 0 : orgin[2] = fVertex[2];
776 0 : time = fTime;
777 :
778 : // Particle params database
779 :
780 0 : TDatabasePDG *db = TDatabasePDG::Instance();
781 : TParticlePDG *type;
782 : AliGeVSimParticle *partType;
783 :
784 : Int_t nType, nParticle, nParam;
785 : const Int_t kNParams = 6;
786 :
787 : // reaction plane determination and model
788 0 : DetermineReactionPlane();
789 :
790 : // loop over particle types
791 :
792 0 : for (nType = 0; nType < fPartTypes->GetEntries(); nType++) {
793 :
794 0 : partType = (AliGeVSimParticle *)fPartTypes->At(nType);
795 :
796 0 : pdg = (PDG_t)partType->GetPdgCode();
797 0 : type = db->GetParticle(pdg);
798 0 : mass = type->Mass();
799 :
800 0 : fModel = partType->GetModel();
801 0 : SetFormula(pdg);
802 0 : fCurrentForm->SetParameter("mass", mass);
803 :
804 :
805 : // Evaluation of parameters - loop over parameters
806 :
807 0 : for (nParam = 0; nParam < kNParams; nParam++) {
808 :
809 0 : paramScaler = FindScaler(nParam, pdg);
810 :
811 0 : if (nParam == 0)
812 0 : fCurrentForm->SetParameter("temperature", paramScaler * partType->GetTemperature());
813 :
814 0 : if (nParam == 1 && fModel == 1)
815 0 : fYFormula->SetParameter("sigmaY", paramScaler * partType->GetSigmaY());
816 :
817 0 : if (nParam == 2 && fModel == 4) {
818 :
819 0 : Double_t totalExpVal = paramScaler * partType->GetExpansionVelocity();
820 :
821 0 : if (totalExpVal == 0.0) totalExpVal = 0.0001;
822 0 : if (totalExpVal == 1.0) totalExpVal = 9.9999;
823 :
824 0 : fCurrentForm->SetParameter("expVel", totalExpVal);
825 0 : }
826 :
827 : // flow
828 :
829 0 : if (nParam == 3) directedScaller = paramScaler;
830 0 : if (nParam == 4) ellipticScaller = paramScaler;
831 :
832 : // multiplicity
833 :
834 0 : if (nParam == 5) {
835 :
836 0 : if (partType->IsMultForced()) isMultTotal = partType->IsMultTotal();
837 0 : else isMultTotal = fIsMultTotal;
838 :
839 0 : multiplicity = paramScaler * partType->GetMultiplicity();
840 0 : multiplicity *= (isMultTotal)? 1 : GetdNdYToTotal();
841 0 : }
842 : }
843 :
844 : // Flow defined on the particle type level (not parameterised)
845 0 : if (partType->IsFlowSimple()) {
846 0 : fPhiFormula->SetParameter(1, partType->GetDirectedFlow(0,0) * directedScaller);
847 0 : fPhiFormula->SetParameter(2, partType->GetEllipticFlow(0,0) * ellipticScaller);
848 0 : }
849 :
850 0 : AdjustFormula();
851 :
852 :
853 0 : Info("Generate","PDG = %d \t Mult = %d", pdg, (Int_t)multiplicity);
854 :
855 : // loop over particles
856 :
857 : nParticle = 0;
858 0 : while (nParticle < multiplicity) {
859 :
860 0 : Double_t pt, y, phi; // momentum in [pt,y,phi]
861 0 : Float_t p[3] = {0,0,0}; // particle momentum
862 :
863 0 : GetRandomPtY(pt, y);
864 :
865 : // phi distribution configuration when differential flow defined
866 : // to be optimised in future release
867 :
868 0 : if (!partType->IsFlowSimple()) {
869 0 : fPhiFormula->SetParameter(1, partType->GetDirectedFlow(pt,y) * directedScaller);
870 0 : fPhiFormula->SetParameter(2, partType->GetEllipticFlow(pt,y) * ellipticScaller);
871 0 : }
872 :
873 0 : phi = fPhiFormula->GetRandom();
874 :
875 0 : if (!isMultTotal) nParticle++;
876 0 : if (fModel > 4 && !CheckPtYPhi(pt,y,phi) ) continue;
877 :
878 : // coordinate transformation
879 0 : v->SetPtEtaPhiM(pt, y, phi, mass);
880 :
881 0 : p[0] = v->Px();
882 0 : p[1] = v->Py();
883 0 : p[2] = v->Pz();
884 :
885 : // momentum range test
886 0 : if ( !CheckAcceptance(p) ) continue;
887 :
888 : // putting particle on the stack
889 :
890 0 : PushTrack(fTrackIt, kParent, pdg, p, orgin, polar, time, kPPrimary, id, fTrackIt);
891 0 : if (isMultTotal) nParticle++;
892 0 : }
893 : }
894 :
895 : // prepare and store header
896 :
897 0 : AliGenGeVSimEventHeader *header = new AliGenGeVSimEventHeader("GeVSim header");
898 0 : TArrayF eventVertex(3,orgin);
899 :
900 0 : header->SetPrimaryVertex(eventVertex);
901 0 : header->SetInteractionTime(time);
902 0 : header->SetEventPlane(fPsi);
903 0 : header->SetEllipticFlow(fPhiFormula->GetParameter(2));
904 :
905 0 : gAlice->SetGenEventHeader(header);
906 :
907 0 : delete v;
908 0 : }
909 :
910 : //////////////////////////////////////////////////////////////////////////////////
|