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 // Glauber MC implementation
20 // origin: PHOBOS experiment
21 // alification: Mikolaj Krzewicki, Nikhef, mikolaj.krzewicki@cern.ch
23 ////////////////////////////////////////////////////////////////////////////////
25 #include <Riostream.h>
30 #include <TObjArray.h>
38 #include "AliGlauberNucleon.h"
39 #include "AliGlauberNucleus.h"
40 #include "AliGlauberMC.h"
42 ClassImp(AliGlauberMC)
44 //______________________________________________________________________________
45 AliGlauberMC::AliGlauberMC(Option_t* NA, Option_t* NB, Double_t xsect) :
89 fdNdEtaParam[0] = 8.0;
90 fdNdEtaParam[1] = 0.13;
91 fdNdEtaGBWParam[0] = 0.79;
92 fdNdEtaGBWParam[1] = 0.288;
93 fdNdEtaGBWParam[2] = 30.25;
94 fdNdEtaNBDParam[0] = 3.0;
95 fdNdEtaNBDParam[1] = 4.0;
96 fdNdEtaNBDParam[2] = 0.13;
97 fdNdEtaTwoNBDParam[0] = 3.0;
98 fdNdEtaTwoNBDParam[1] = 4.0;
99 fdNdEtaTwoNBDParam[2] = 2.0;
100 fdNdEtaTwoNBDParam[3] = 11.0;
101 fdNdEtaTwoNBDParam[4] = 0.4;
102 fdNdEtaTwoNBDParam[5] = 0.13;
104 SetName(Form("Glauber_%s_%s",fANucleus.GetName(),fBNucleus.GetName()));
105 SetTitle(Form("Glauber %s+%s Version",fANucleus.GetName(),fBNucleus.GetName()));
108 //______________________________________________________________________________
109 AliGlauberMC::~AliGlauberMC()
115 //______________________________________________________________________________
116 AliGlauberMC::AliGlauberMC(const AliGlauberMC& in):
118 fANucleus(in.fANucleus),
119 fBNucleus(in.fBNucleus),
121 fNucleonsA(in.fNucleonsA),
122 fNucleonsB(in.fNucleonsB),
129 fMeanXParts(in.fMeanXParts),
130 fMeanYParts(in.fMeanYParts),
131 fMeanXColl(in.fMeanXColl),
132 fMeanYColl(in.fMeanYColl),
133 fMeanX2Coll(in.fMeanX2Coll),
134 fMeanY2Coll(in.fMeanY2Coll),
135 fMeanXYColl(in.fMeanXYColl),
136 fMeanXSystem(in.fMeanXSystem),
137 fMeanYSystem(in.fMeanYSystem),
138 fMeanX_A(in.fMeanX_A),
139 fMeanY_A(in.fMeanY_A),
140 fMeanX_B(in.fMeanX_B),
141 fMeanY_B(in.fMeanY_B),
144 fTotalEvents(in.fTotalEvents),
147 fMaxNpartFound(in.fMaxNpartFound),
153 fSx2Coll(in.fSx2Coll),
154 fSy2Coll(in.fSy2Coll),
155 fSxyColl(in.fSxyColl),
161 memcpy(fdNdEtaParam,in.fdNdEtaParam,2*sizeof(Double_t));
162 memcpy(fdNdEtaGBWParam,in.fdNdEtaGBWParam,3*sizeof(Double_t));
163 memcpy(fdNdEtaNBDParam,in.fdNdEtaNBDParam,3*sizeof(Double_t));
164 memcpy(fdNdEtaTwoNBDParam,in.fdNdEtaTwoNBDParam,6*sizeof(Double_t));
167 //______________________________________________________________________________
168 AliGlauberMC& AliGlauberMC::operator=(const AliGlauberMC& in)
171 fANucleus=in.fANucleus;
172 fBNucleus=in.fBNucleus;
174 fNucleonsA=in.fNucleonsA;
175 fNucleonsB=in.fNucleonsB;
182 fMeanXParts=in.fMeanXParts;
183 fMeanYParts=in.fMeanYParts;
184 fMeanXColl=in.fMeanXColl;
185 fMeanYColl=in.fMeanYColl;
186 fMeanX2Coll=in.fMeanX2Coll;
187 fMeanY2Coll=in.fMeanY2Coll;
188 fMeanXYColl=in.fMeanXYColl;
189 fMeanXSystem=in.fMeanXSystem;
190 fMeanYSystem=in.fMeanYSystem;
191 fMeanX_A=in.fMeanX_A;
192 fMeanY_A=in.fMeanY_A;
193 fMeanX_B=in.fMeanX_B;
194 fMeanY_B=in.fMeanY_B;
197 fTotalEvents=in.fTotalEvents;
200 memcpy(fdNdEtaParam,in.fdNdEtaParam,2*sizeof(Double_t));
201 memcpy(fdNdEtaGBWParam,in.fdNdEtaGBWParam,3*sizeof(Double_t));
202 memcpy(fdNdEtaNBDParam,in.fdNdEtaNBDParam,3*sizeof(Double_t));
203 memcpy(fdNdEtaTwoNBDParam,in.fdNdEtaTwoNBDParam,6*sizeof(Double_t));
204 fMaxNpartFound=in.fMaxNpartFound;
210 fSx2Coll=in.fSx2Coll;
211 fSy2Coll=in.fSy2Coll;
212 fSxyColl=in.fSxyColl;
218 //______________________________________________________________________________
219 Bool_t AliGlauberMC::CalcEvent(Double_t bgen)
222 fANucleus.ThrowNucleons(-bgen/2.);
223 fNucleonsA = fANucleus.GetNucleons();
224 fAN = fANucleus.GetN();
225 for (Int_t i = 0; i<fAN; i++)
227 AliGlauberNucleon *nucleonA=(AliGlauberNucleon*)(fNucleonsA->UncheckedAt(i));
228 nucleonA->SetInNucleusA();
230 fBNucleus.ThrowNucleons(bgen/2.);
231 fNucleonsB = fBNucleus.GetNucleons();
232 fBN = fBNucleus.GetN();
233 for (Int_t i = 0; i<fBN; i++)
235 AliGlauberNucleon *nucleonB=(AliGlauberNucleon*)(fNucleonsB->UncheckedAt(i));
236 nucleonB->SetInNucleusB();
239 // "ball" diameter = distance at which two balls interact
240 Double_t d2 = (Double_t)fXSect/(TMath::Pi()*10); // in fm^2
242 // for each of the A nucleons in nucleus B
243 for (Int_t i = 0; i<fBN; i++)
245 AliGlauberNucleon *nucleonB=(AliGlauberNucleon*)(fNucleonsB->UncheckedAt(i));
246 for (Int_t j = 0 ; j < fAN ; j++)
248 AliGlauberNucleon *nucleonA=(AliGlauberNucleon*)(fNucleonsA->UncheckedAt(j));
249 Double_t dx = nucleonB->GetX()-nucleonA->GetX();
250 Double_t dy = nucleonB->GetY()-nucleonA->GetY();
251 Double_t dij = dx*dx+dy*dy;
260 return CalcResults(bgen);
263 //______________________________________________________________________________
264 Bool_t AliGlauberMC::CalcResults(Double_t bgen)
266 // calc results for the given event
267 //return true if we have participants
288 for (Int_t i = 0; i<fAN; i++)
290 AliGlauberNucleon *nucleonA=(AliGlauberNucleon*)(fNucleonsA->UncheckedAt(i));
291 Double_t xA=nucleonA->GetX();
292 Double_t yA=nucleonA->GetY();
298 if(nucleonA->IsWounded())
309 for (Int_t i = 0; i<fBN; i++)
311 AliGlauberNucleon *nucleonB=(AliGlauberNucleon*)(fNucleonsB->UncheckedAt(i));
312 Double_t xB=nucleonB->GetX();
313 Double_t yB=nucleonB->GetY();
319 if(nucleonB->IsWounded())
321 Int_t ncoll = nucleonB->GetNColl();
324 fMeanXColl += xB*ncoll;
326 fMeanYColl += yB*ncoll;
328 fMeanX2Coll += xB*xB*ncoll*ncoll;
330 fMeanY2Coll += yB*yB*ncoll*ncoll;
332 fMeanXYColl += xB*yB*ncoll*ncoll;
333 fNcoll += nucleonB->GetNColl();
339 fMeanXParts /= fNpart;
340 fMeanYParts /= fNpart;
356 fMeanXColl /= fNcoll;
357 fMeanYColl /= fNcoll;
358 fMeanX2Coll /= fNcoll;
359 fMeanY2Coll /= fNcoll;
360 fMeanXYColl /= fNcoll;
373 fMeanXSystem /= (fAN + fBN);
374 fMeanYSystem /= (fAN + fBN);
403 fSx2=fMeanX2-(fMeanXParts*fMeanXParts);
404 fSy2=fMeanY2-(fMeanYParts*fMeanYParts);
405 fSxy=fMeanXY-fMeanXParts*fMeanYParts;
407 fSx2Coll=fMeanX2Coll-(fMeanXColl*fMeanXColl);
408 fSy2Coll=fMeanY2Coll-(fMeanYColl*fMeanYColl);
409 fSxyColl=fMeanXYColl-fMeanXColl*fMeanYColl;
414 if (fNpart>0) fEvents++;
416 if (fNpart==0) return kFALSE;
417 if (fNpart > fMaxNpartFound) fMaxNpartFound = fNpart;
422 //______________________________________________________________________________
423 void AliGlauberMC::Draw(Option_t* /*option*/)
425 fANucleus.Draw(fXSect, 2);
426 fBNucleus.Draw(fXSect, 4);
433 e.DrawEllipse(GetB()/2,0,fBNucleus.GetR(),fBNucleus.GetR(),0,360,0);
434 e.DrawEllipse(-GetB()/2,0,fANucleus.GetR(),fANucleus.GetR(),0,360,0);
437 //______________________________________________________________________________
438 Double_t AliGlauberMC::GetTotXSect() const
440 return (1.*fEvents/fTotalEvents)*TMath::Pi()*fBMax*fBMax/100;
443 //______________________________________________________________________________
444 Double_t AliGlauberMC::GetTotXSectErr() const
446 return GetTotXSect()/TMath::Sqrt((Double_t)fEvents) *
447 TMath::Sqrt(Double_t(1.-fEvents/fTotalEvents));
450 //______________________________________________________________________________
451 TObjArray *AliGlauberMC::GetNucleons()
453 if(!fNucleonsA || !fNucleonsB) return 0;
454 fNucleonsA->SetOwner(0);
455 fNucleonsB->SetOwner(0);
456 TObjArray *allnucleons=new TObjArray(fAN+fBN);
457 allnucleons->SetOwner();
458 for (Int_t i = 0; i<fAN; i++)
460 allnucleons->Add(fNucleonsA->UncheckedAt(i));
462 for (Int_t i = 0; i<fBN; i++)
464 allnucleons->Add(fNucleonsB->UncheckedAt(i));
468 //______________________________________________________________________________
469 Double_t AliGlauberMC::NegativeBinomialDistribution(Int_t x, Int_t k, Double_t nmean)
473 cout << "Error, zero or negative K" << endl;
476 return (TMath::Binomial(x+k-1,x))
477 *TMath::Power(((nmean/Double_t(k))/(1+nmean/Double_t(k))),Double_t(x))
478 *(1/(TMath::Power((1+nmean/Double_t(k)),Double_t(k))));
480 //______________________________________________________________________________
481 Int_t AliGlauberMC::NegativeBinomialRandom(Int_t k, Double_t nmean)
482 //return random integer from a Negative Binomial Distribution
484 static const Int_t fMaxPlot = 1000;
485 Double_t array[fMaxPlot];
486 array[0] = NegativeBinomialDistribution(0,k,nmean);
487 for (Int_t i=1; i<fMaxPlot; i++)
489 array[i] = NegativeBinomialDistribution(i,k,nmean) + array[i-1];
491 Double_t r = gRandom->Uniform(0,1);
492 return TMath::BinarySearch(fMaxPlot,array,r)+2;
494 //______________________________________________________________________________
495 Int_t AliGlauberMC::DoubleNegativeBinomialRandom( Int_t k,
501 //return random integer from a Double Negative Binomial Distribution
502 static const Int_t fMaxPlot = 1000;
503 Double_t array[fMaxPlot];
504 array[0] = alpha*NegativeBinomialDistribution(0,k,nmean)+(1-alpha)*NegativeBinomialDistribution(0,k2,nmean2);
505 for (Int_t i=1; i<fMaxPlot; i++)
507 array[i] = alpha*NegativeBinomialDistribution(i,k,nmean)+(1-alpha)*NegativeBinomialDistribution(i,k2,nmean2) + array[i-1];
509 Double_t r = gRandom->Uniform(0,1);
510 return TMath::BinarySearch(fMaxPlot,array,r)+2;
513 //______________________________________________________________________________
514 void AliGlauberMC::SetdNdEtaParam(Double_t nnp, Double_t x)
516 // set parameters used for calculating multiplicity, see GetdNdEta() for commments
521 //______________________________________________________________________________
522 void AliGlauberMC::SetdNdEtaGBWParam(Double_t delta, Double_t lambda, Double_t snn)
524 // set parameters used for calculating multiplicity see GetdNdEtaGBW() for commments
525 fdNdEtaGBWParam[0]=delta;
526 fdNdEtaGBWParam[1]=lambda;
527 fdNdEtaGBWParam[2]=snn;
530 //______________________________________________________________________________
531 void AliGlauberMC::SetdNdEtaNBDParam(Double_t k, Double_t nmean, Double_t beta)
533 // set parameters used for calculating multiplicity see GetdNdEtaNBD() for commments
534 fdNdEtaNBDParam[0]=k;
535 fdNdEtaNBDParam[1]=nmean;
536 fdNdEtaNBDParam[2]=beta;
539 //______________________________________________________________________________
540 void AliGlauberMC::SetdNdEtaTwoNBDParam( Double_t k1,
547 // set parameters used for calculating multiplicity see GetdNdEtaTwoNBD() for commments
548 fdNdEtaTwoNBDParam[0]=k1;
549 fdNdEtaTwoNBDParam[1]=nmean1;
550 fdNdEtaTwoNBDParam[2]=k2;
551 fdNdEtaTwoNBDParam[3]=nmean2;
552 fdNdEtaTwoNBDParam[4]=alpha;
553 fdNdEtaTwoNBDParam[5]=beta;
556 //______________________________________________________________________________
557 Double_t AliGlauberMC::GetdNdEta(Double_t nnp, Double_t x)
559 //Get particle density per unit of rapidity
560 //using two component model
562 return nnp*((1.-x)*fNpart/2.+x*fNcoll);
565 //______________________________________________________________________________
566 Double_t AliGlauberMC::GetdNdEtaGBW( Double_t delta,
570 //Get particle density per unit of rapidity
571 //using the GBW model
572 //Parameters: delta, lambda, snn
573 return fNpart*0.47*TMath::Sqrt(TMath::Power(snn,lambda))
574 * TMath::Power(fNpart,(1.-delta)/3./delta);
577 //_______________________________________________________________________________
578 Double_t AliGlauberMC::GetdNdEtaNBD ( Int_t k, Double_t nmean, Double_t beta)
580 //Get particle density per unit of rapidity
581 //using a aandomized number from a negative binomial distrubution
582 //Parameters: k = related to distribition width
583 // nmean = mean of distribution
584 // beta = set contribution of participants / binary collisions to multiplicity
586 for(Int_t i = 0; i<fNpart; i++)
588 mulnp+=NegativeBinomialRandom(k,nmean);
591 for(Int_t i = 0; i<fNcoll; i++)
593 mulnb+=NegativeBinomialRandom(k,nmean);
595 return (1-beta)*mulnp/2+beta*mulnb;
598 //______________________________________________________________________________
599 Double_t AliGlauberMC::GetdNdEtaTwoNBD ( Int_t k1,
606 //Get particle density per unit of rapidity
607 //using random numbers from two negative binomial distributions
608 //Parameters: k1 = related to distribition width of distribution 1
609 // nmean1 = mean of distribution 1
610 // k2 = related to distribition width of distribution 2
611 // nmean2 = mean of distribution 2
612 // alpha = set contributions of distrubitin 1 / distribution 2
613 // beta = set contribution of participants / binary collisions to multiplicity
615 for(Int_t i = 0; i<fNpart; i++)
617 mulnp+=DoubleNegativeBinomialRandom(k1,nmean1,k2,nmean2,alpha);
620 for(Int_t i = 0; i<fNcoll; i++)
622 mulnb+=DoubleNegativeBinomialRandom(k1,nmean1,k2,nmean2,alpha);
624 Double_t mul=(1-beta)*mulnp/2+beta*mulnb;
628 //______________________________________________________________________________
629 Double_t AliGlauberMC::GetEccentricityPart() const
631 //get participant eccentricity of participants
632 if (fNpart<2) return 0.0;
633 return (TMath::Sqrt((fSy2-fSx2)*(fSy2-fSx2)+4*fSxy*fSxy)/(fSy2+fSx2));
636 //______________________________________________________________________________
637 Double_t AliGlauberMC::GetEccentricityPartColl() const
639 //get participant eccentricity of binary collisions
640 if (fNcoll<2) return 0.0;
641 return (TMath::Sqrt((fSy2Coll-fSx2Coll)*(fSy2Coll-fSx2Coll)+4*fSxyColl*fSxyColl)/(fSy2Coll+fSx2Coll));
644 //______________________________________________________________________________
645 Double_t AliGlauberMC::GetEccentricity() const
647 //get standard eccentricity of participants
648 if (fNpart<2) return 0.0;
649 return ((fSy2-fSx2)/(fSy2+fSx2));
652 //______________________________________________________________________________
653 Double_t AliGlauberMC::GetEccentricityColl() const
655 //get standard eccentricity of binary collisions
656 if (fNcoll<2) return 0.0;
657 return ((fSy2Coll-fSx2Coll)/(fSy2Coll+fSx2Coll));
660 //______________________________________________________________________________
661 Bool_t AliGlauberMC::NextEvent(Double_t bgen)
664 Int_t nAttempts = 10; // set indices, max attempts and max comparisons
665 Bool_t succes = kFALSE;
666 for(Int_t j=0; j<nAttempts; j++)
668 if(bgen<0||!succes) //get impactparameter
670 bgen = TMath::Sqrt((fBMax*fBMax-fBMin*fBMin)*gRandom->Rndm()+fBMin*fBMin);
672 if ( (succes=CalcEvent(bgen)) ) break; //ends if we have particparts
677 //______________________________________________________________________________
678 void AliGlauberMC::Run(Int_t nevents)
680 cout << "Generating " << nevents << " events..." << endl;
681 TString name(Form("nt_%s_%s",fANucleus.GetName(),fBNucleus.GetName()));
682 TString title(Form("%s + %s (x-sect = %d mb)",fANucleus.GetName(),fBNucleus.GetName(),(Int_t) fXSect));
685 fnt = new TNtuple(name,title,
686 "Npart:Ncoll:B:MeanX:MeanY:MeanX2:MeanY2:MeanXY:VarX:VarY:VarXY:MeanXSystem:MeanYSystem:MeanXA:MeanYA:MeanXB:MeanYB:VarE:VarEColl:VarEPart:VarEPartColl:dNdEta:dNdEtaGBW:dNdEtaNBD:dNdEtaTwoNBD:xsect:tAA");
687 fnt->SetDirectory(0);
691 for (Int_t i = 0; i<nevents; i++)
713 v[11] = fMeanXSystem;
714 v[12] = fMeanYSystem;
719 v[17] = GetEccentricity();
720 v[18] = GetEccentricityColl();
721 v[19] = GetEccentricityPart();
722 v[20] = GetEccentricityPartColl();
724 v[21] = GetdNdEta( fdNdEtaParam[0],fdNdEtaParam[1] );
725 v[22] = GetdNdEtaGBW( fdNdEtaGBWParam[0],fdNdEtaGBWParam[1],fdNdEtaGBWParam[2] );
726 v[23] = GetdNdEtaNBD( TMath::Nint(fdNdEtaNBDParam[0]),
728 fdNdEtaNBDParam[2] );
729 v[24] = GetdNdEtaTwoNBD( TMath::Nint(fdNdEtaTwoNBDParam[0]),
730 fdNdEtaTwoNBDParam[1],
731 TMath::Nint(fdNdEtaTwoNBDParam[2]),
732 fdNdEtaTwoNBDParam[3],
733 fdNdEtaTwoNBDParam[4],
734 fdNdEtaTwoNBDParam[5] );
744 if (GetNcoll()>0) mytAA=GetNcoll()/fXSect;
748 if ((i%50)==0) std::cout << "Generating Event # " << i << "... \r" << flush;
750 std::cout << "Generating Event # " << nevents << "... \r" << endl << "Done! Succesfull events: " << q << " discarded events: " << u <<"."<< endl;
753 //---------------------------------------------------------------------------------
754 void AliGlauberMC::runAndSaveNtuple( Int_t n,
763 AliGlauberMC mcg(sysA,sysB,signn);
764 mcg.SetMinDistance(mind);
768 TNtuple *nt=mcg.GetNtuple();
769 TFile out(fname,"recreate",fname,9);
771 printf("total cross section with a nucleon-nucleon cross section \t%f is \t%f",signn,mcg.GetTotXSect());
775 //---------------------------------------------------------------------------------
776 void AliGlauberMC::runAndSaveNucleons( Int_t n,
784 AliGlauberMC mcg(sysA,sysB,signn);
785 mcg.SetMinDistance(mind);
788 out=new TFile(fname,"recreate",fname,9);
790 for(Int_t ievent=0; ievent<n; ievent++)
793 //get an event with at least one collision
794 while(!mcg.NextEvent()) {}
796 //access, save and (if wanted) print out nucleons
797 TObjArray* nucleons=mcg.GetNucleons();
798 if(!nucleons) continue;
800 nucleons->Write(Form("nucleonarray%d",ievent),TObject::kSingleKey);
804 cout<<endl<<endl<<"EVENT NO: "<<ievent<<endl;
805 cout<<"B = "<<mcg.GetB()<<" Npart = "<<mcg.GetNpart()<<endl<<endl;
806 printf("Nucleus\t X\t Y\t Z\tNcoll\n");
807 Int_t nNucls=nucleons->GetEntries();
808 for(Int_t iNucl=0; iNucl<nNucls; iNucl++)
810 AliGlauberNucleon *nucl=(AliGlauberNucleon *)nucleons->UncheckedAt(iNucl);
812 if(nucl->IsInNucleusB()) nucleus='B';
813 Double_t x=nucl->GetX();
814 Double_t y=nucl->GetY();
815 Double_t z=nucl->GetZ();
816 Int_t ncoll=nucl->GetNColl();
817 printf(" %c\t%2.2f\t%2.2f\t%2.2f\t%3d\n",nucleus,x,y,z,ncoll);
824 //---------------------------------------------------------------------------------
825 void AliGlauberMC::Reset()
828 delete fnt; fnt=NULL;