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 /* Origin: Alberica Toia, CERN, Alberica.Toia@cern.ch */
18 ///////////////////////////////////////////////////////////////////////////////
20 // class to determine centrality percentiles from 1D distributions //
22 ///////////////////////////////////////////////////////////////////////////////
34 #include <TGraphErrors.h>
37 #include <TStopwatch.h>
39 #include "AliCentralityGlauberFit.h"
42 ClassImp(AliCentralityGlauberFit)
44 //______________________________________________________________________________
45 AliCentralityGlauberFit::AliCentralityGlauberFit(const char *filename) :
80 fAncfilename("ancestor_hists.root"),
83 // Standard constructor.
85 if (filename) { // glauber file
86 f = TFile::Open(filename);
87 fGlauntuple = (TNtuple*) f->Get("nt_Pb_Pb");
88 fGlauntuple->SetBranchAddress("Npart",&fNpart);
89 fGlauntuple->SetBranchAddress("Ncoll",&fNcoll);
90 fGlauntuple->SetBranchAddress("B",&fB);
91 fGlauntuple->SetBranchAddress("tAA",&fTaa);
94 fNBD = new TF1 ("fNBD", AliCentralityGlauberFit::NBDFunc, 0, 100,2);
97 //--------------------------------------------------------------------------------------------------
98 void AliCentralityGlauberFit::SetRangeToFit(Double_t fmultmin, Double_t fmultmax)
106 //--------------------------------------------------------------------------------------------------
107 void AliCentralityGlauberFit::SetRangeToScale(Double_t fscalemin)
109 // Set range where to scale simulated histo to data
114 //--------------------------------------------------------------------------------------------------
115 void AliCentralityGlauberFit::SetGlauberParam(
126 // Set Glauber parameters.
136 fAlphahigh=alphahigh;
139 //--------------------------------------------------------------------------------------------------
140 void AliCentralityGlauberFit::MakeFits()
148 //FILE* fTxt = fopen ("parameters.txt","w");
150 // open inrootfile, outrootfile
151 std::cout << "input file " << fInrootfilename << std::endl;
152 std::cout << "output file " << fOutrootfilename << std::endl;
153 inrootfile = new TFile(fInrootfilename,"OPEN");
154 outrootfile = new TFile(fOutrootfilename,"RECREATE");
156 // loop over all distribution names
157 std::vector<TString>::const_iterator hni;
158 for(hni=fHistnames.begin(); hni!=fHistnames.end(); hni++) {
159 hDATA = (TH1F*) (inrootfile->Get(*hni));
161 TList *list = (TList*) (inrootfile->Get("CentralityStat"));
162 //TList *list = (TList*) (inrootfile->Get("VZEROEquaFactorStat"));
163 hDATA = (TH1F*) (list->FindObject(*hni));
165 hDATA->Rebin(fRebinFactor);
166 //TH1F *hGLAU = new TH1F("hGLAU","hGLAU",hDATA->GetNbinsX(),0,hDATA->GetNbinsX()*hDATA->GetBinWidth(1));
167 Double_t chi2min = 9999999.0;
168 Double_t alpha_min=-1;
171 Double_t alpha, mu, k, chi2;
173 for (Int_t nalpha=0;nalpha<fNalpha;nalpha++) {
174 alpha = fAlphalow + ((Double_t) nalpha ) * (fAlphahigh - fAlphalow ) / fNalpha;
177 for (Int_t nmu=0; nmu<fNmu; nmu++) {
178 mu = fMulow + ((Double_t) nmu ) * (fMuhigh - fMulow ) / fNmu;
180 for (Int_t nk=0; nk<fNk; nk++) {
181 k = fKlow + ((Double_t) nk ) * (fKhigh - fKlow ) / fNk;
183 thistGlau = GlauberHisto(mu,k,alpha,hDATA,kFALSE);
184 chi2 = CalculateChi2(hDATA,thistGlau);
185 //fprintf(fTxt, "%3.3f %3.3f %3.3f %3.3f\n", (float) mu, (float) k, (float) alpha, chi2);
186 if ( chi2 < chi2min ) {
196 thistGlau = GlauberHisto(mu_min,k_min,alpha_min,hDATA,kTRUE);
199 hGLAU = (TH1F *) thistGlau->Clone("hGLAU");
200 hGLAU->SetName( ((TString)hDATA->GetName()).Append(Form("_GLAU")));
201 hGLAU->SetTitle( ((TString)hDATA->GetName()).Append(Form("_GLAU_%.3f_%.3f_%.3f",
202 mu_min,k_min,alpha_min)));
204 Double_t mcintegral = hGLAU->Integral(hGLAU->FindBin(fScalemin),hGLAU->GetNbinsX());
205 Double_t scale = (hDATA->Integral(hDATA->FindBin(fScalemin),hDATA->GetNbinsX())/mcintegral);
208 fhEffi = GetTriggerEfficiencyFunction(hDATA, hGLAU);
209 SaveHisto(hDATA,hGLAU,fhEffi,outrootfile);
212 std::cout << "chi2 min is " << chi2min << std::endl;
213 std::cout << "fitted " << hGLAU->Integral(hGLAU->FindBin(fMultmin),
214 hGLAU->FindBin(fMultmax))/hGLAU->Integral()
215 << " of the total cross section" << std::endl;
220 // close inrootfile, outrootfile
222 outrootfile->Close();
225 //--------------------------------------------------------------------------------------------------
226 void AliCentralityGlauberFit::MakeFitsMinuitNBD(Double_t alpha, Double_t mu, Double_t k)
228 // Make fits using Minuit.
236 printf("Calling Minuit with starting values: %f %f %f\n", alpha, mu, k);
243 // open inrootfile, outrootfile
244 std::cout << "input file " << fInrootfilename << std::endl;
245 std::cout << "output file " << fOutrootfilename << std::endl;
246 inrootfile = new TFile(fInrootfilename,"OPEN");
247 outrootfile = new TFile(fOutrootfilename,"RECREATE");
249 // loop over all distribution names
250 std::vector<TString>::const_iterator hni;
251 for(hni=fHistnames.begin(); hni!=fHistnames.end(); hni++) {
252 hDATA = (TH1F*) (inrootfile->Get(*hni));
254 TList *list = (TList*) (inrootfile->Get("CentralityStat"));
255 //TList *list = (TList*) (inrootfile->Get("VZEROEquaFactorStat"));
256 hDATA = (TH1F*) (list->FindObject(*hni));
258 hDATA->Rebin(fRebinFactor);
261 TH1F *hGLAU = new TH1F("hGLAU","hGLAU",hDATA->GetNbinsX(),0,hDATA->GetNbinsX()*hDATA->GetBinWidth(1));
265 if(gMinuit) delete gMinuit;
268 gMinuit->SetFCN(AliCentralityGlauberFit::MinuitFcnNBD);
269 gMinuit->SetObjectFit(this);
271 Double_t arglist[2]={0};
273 if (fUseChi2) arglist[0] = 1; // should be 1 if you want to minimize chi2
274 else arglist[0] = 0.5; // should be 0.5 for ll
275 gMinuit->mnexcm("SET ERR",arglist, 1, ierflg);
276 gMinuit->mnparm(0,"alpha", alpha, (fAlphahigh-fAlphalow)/fNalpha, fAlphalow, fAlphahigh, ierflg);
277 gMinuit->mnparm(1,"mu" , mu, (fMuhigh-fMulow)/fNmu, fMulow, fMuhigh, ierflg);
278 gMinuit->mnparm(2,"k" , k, (fKhigh-fKlow)/fNk, fKlow, fKhigh, ierflg);
281 arglist[0] = 100; // max calls
282 arglist[1] = 0.1; // tolerance
283 gMinuit->mnexcm("SIMPLEX",arglist, 2, ierflg);
284 arglist[0] = 1000; // max calls
285 arglist[1] = 0.1; // tolerance
286 gMinuit->mnexcm("MIGrad",arglist, 2, ierflg);
287 //gMinuit->mnexcm("IMPROVE",arglist, 0, ierflg);
290 AliWarning("Abnormal termination of minimization.");
293 // ______________________ Get chi2 and Fit Status __________
294 Double_t amin,edm,errdef;
295 Int_t nvpar, nparx, icstat;
297 gMinuit->mnstat(amin,edm,errdef,nvpar,nparx,icstat);
298 Double_t chi2min = amin;
299 std::cout << "Fit status " << icstat << std::endl;
301 Double_t alpha_min, mu_min, k_min;
302 Double_t alpha_mine, mu_mine, k_mine;
303 gMinuit->GetParameter(0, alpha_min , alpha_mine );
304 gMinuit->GetParameter(1, mu_min , mu_mine );
305 gMinuit->GetParameter(2, k_min , k_mine );
308 std::cout << "chi2 min is " << chi2min << ", " << alpha_min << ", "<< mu_min<< ", "
309 << k_min << std::endl;
311 thistGlau = GlauberHisto(mu_min,k_min,alpha_min,hDATA,kTRUE);
313 hGLAU = (TH1F *) thistGlau->Clone("hGLAU");
314 hGLAU->SetName( ((TString)hDATA->GetName()).Append(Form("_GLAU")));
315 hGLAU->SetTitle( ((TString)hDATA->GetName()).Append(Form("_GLAU_%.3f_%.3f_%.3f",
316 mu_min,k_min,alpha_min)));
319 std::cout << "fitted " << hGLAU->Integral(hGLAU->FindBin(fMultmin),
320 hGLAU->FindBin(fMultmax))/hGLAU->Integral()
321 << " of the total cross section" << std::endl;
323 Double_t mcintegral = hGLAU->Integral(hGLAU->FindBin(fScalemin),hGLAU->GetNbinsX());
324 Double_t scale = (hDATA->Integral(hDATA->FindBin(fScalemin),hDATA->GetNbinsX())/mcintegral);
327 std::cout << "Chi2 final " << CalculateChi2(hDATA,hGLAU) << std::endl;
329 fhEffi = GetTriggerEfficiencyFunction(hDATA, hGLAU);
330 SaveHisto(hDATA,hGLAU,fhEffi,outrootfile);
333 // close inrootfile, outrootfile
335 outrootfile->Close();
338 //--------------------------------------------------------------------------------------------------
339 TH1F *AliCentralityGlauberFit::GlauberHisto(Double_t mu, Double_t k, Double_t alpha,
340 TH1F *hDATA, Bool_t save)
342 // Get Glauber histogram.
343 static TH1F *h1 = (TH1F*)hDATA->Clone();
345 h1->SetName(Form("fit_%.3f_%.3f_%.3f",mu,k,alpha));
348 fhAncestor = MakeAncestor(alpha);
349 for (Int_t np=1; np<=fhAncestor->GetNbinsX(); ++np) {
350 Double_t nanc = fhAncestor->GetBinCenter(np);
351 Double_t weights = fhAncestor->GetBinContent(np);
353 if (weights <= 0) continue;
354 Int_t trials = (Int_t) (20 * nanc * (Int_t) mu);
355 if (trials <=0) continue;
356 for (Int_t j=0; j<trials; j++) {
357 Double_t nbdvalue = NBD(j, mu * nanc, k * nanc);
358 h1->Fill((Double_t) j, nbdvalue * weights);
364 TH1F *hSample = fFastFit != 2 ? NBDhist(mu,k) : 0;
366 TFile *outFile = NULL;
367 TNtuple *ntuple = NULL;
370 outFile = new TFile(fOutntuplename,"RECREATE");
371 ntuple = new TNtuple("gnt", "Glauber ntuple", "Npart:Ncoll:B:tAA:ntot");
376 nents = fGlauntuple->GetEntries();
378 for (Int_t i=0;i<fNevents;++i) {
380 fGlauntuple->GetEntry(i % nents);
386 if (fAncestor == 1) n = (Int_t)(TMath::Power(fNpart,alpha));
387 //if (fAncestor == 1) n = (Int_t)(TMath::Power(fNcoll,alpha));
388 else if (fAncestor == 2) n = (Int_t)(alpha * fNpart + (1-alpha) * fNcoll);
389 else if (fAncestor == 3) n = (Int_t)((1-alpha) * fNpart/2 + alpha * fNcoll);
393 ntot = (Int_t)(n*hSample->GetRandom()); // NBD
395 else if (fFastFit == 2) {
396 Double_t sigma = k*TMath::Sqrt(n*mu);
397 ntot = (Int_t)(gRandom->Gaus(n*mu,sigma)); // Gaussian
400 for(Int_t j = 0; j<(Int_t)n; ++j)
401 ntot += (Int_t)hSample->GetRandom();
406 ntuple->Fill(fNpart,fNcoll,fB,fTaa,ntot);
414 if (fFastFit != 2) delete hSample;
418 //--------------------------------------------------------------------------------------------------
419 Double_t AliCentralityGlauberFit::CalculateChi2(TH1F *hDATA, TH1F *thistGlau)
421 // Note that for different values of neff the mc distribution is identical, just re-scaled below
422 // normalize the two histogram, scale MC up but leave data alone - that preserves error bars !!!!
424 Int_t lowchibin = hDATA->FindBin(fMultmin);
425 Int_t highchibin = hDATA->FindBin(fMultmax);
427 Double_t mcintegral = thistGlau->Integral(1,thistGlau->GetNbinsX());
428 Double_t scale = (hDATA->Integral(1,hDATA->GetNbinsX())/mcintegral);
429 thistGlau->Scale(scale);
431 // calculate the chi2 between MC and real data over some range ????
434 for (Int_t i=lowchibin; i<=highchibin; i++) {
435 if (hDATA->GetBinContent(i) < 1.0) continue;
436 Double_t diff = TMath::Power((thistGlau->GetBinContent(i) - hDATA->GetBinContent(i)),2);
437 diff = diff / (TMath::Power(hDATA->GetBinError(i),2) + TMath::Power(thistGlau->GetBinError(i),2));
440 chi2 = chi2 / (highchibin - lowchibin + 1);
443 // "-2 log likelihood ratio(mu;n) = 2[(mu - n) + n ln(n/mu)]"
445 std::cout << "LL" << std::endl;
448 for (Int_t i=lowchibin; i<=highchibin; i++) {
449 Double_t data = hDATA ->GetBinContent(i);
450 Double_t mc = thistGlau->GetBinContent(i);
451 Int_t idata = TMath::Nint(data);
452 if (mc < 1.e-9) mc = 1.e-9;
453 Double_t fsub = - mc + idata * TMath::Log(mc);
456 for(Int_t istep = 0; istep < idata; istep++){
458 fobs += TMath::Log(istep);
468 //--------------------------------------------------------------------------------------------------
469 TH1F *AliCentralityGlauberFit::GetTriggerEfficiencyFunction(TH1F *hist1, TH1F *hist2)
473 fhEffi = (TH1F*)hist1->Clone("heffi");
474 fhEffi->Divide(hist2);
478 //--------------------------------------------------------------------------------------------------
479 Double_t AliCentralityGlauberFit::GetTriggerEfficiencyIntegral(TH1F *hist1, TH1F *hist2)
483 fEffi = hist1->Integral()/hist2->Integral();
487 //--------------------------------------------------------------------------------------------------
488 void AliCentralityGlauberFit::SaveHisto(TH1F *hist1, TH1F *hist2, TH1F *heffi, TFile *outrootfile)
498 //--------------------------------------------------------------------------------------------------
499 Double_t AliCentralityGlauberFit::NBD(Int_t n, Double_t mu, Double_t k) const
506 // log method for handling large numbers
507 F = TMath::LnGamma(n + k)- TMath::LnGamma(n + 1.)- TMath::LnGamma(k);
508 f = n * TMath::Log(mu/k) - (n + k) * TMath::Log(1.0 + mu/k);
512 F = TMath::Gamma(n + k) / ( TMath::Gamma(n + 1.) * TMath::Gamma(k) );
513 f = n * TMath::Log(mu/k) - (n + k) * TMath::Log(1.0 + mu/k);
522 //--------------------------------------------------------------------------------------------------
523 TH1F *AliCentralityGlauberFit::NBDhist(Double_t mu, Double_t k)
525 // Interface for TH1F.
527 TH1F *h = new TH1F("htemp","",100,-0.5,299.5);
528 h->SetName(Form("nbd_%f_%f",mu,k));
530 for (Int_t i=0;i<300;++i) {
531 Double_t val = NBD(i,mu,k);
532 if (val>1e-20) h->Fill(i,val);
537 //--------------------------------------------------------------------------------------------------
538 void AliCentralityGlauberFit::MinuitFcnNBD(Int_t &/*npar*/, Double_t */*gin*/, Double_t &f, Double_t *par, Int_t /*iflag*/)
542 Double_t alpha = par[0];
543 Double_t mu = par[1];
546 AliCentralityGlauberFit * obj = (AliCentralityGlauberFit *) gMinuit->GetObjectFit();
547 TH1F * thistGlau = obj->GlauberHisto(mu,k,alpha,obj->GetTempHist(),kFALSE);
548 f = obj->CalculateChi2(obj->GetTempHist(),thistGlau);
549 Printf("Minuit step: chi2=%f, alpha=%f, mu=%f, k=%f\n",f,alpha,mu,k);
552 //--------------------------------------------------------------------------------------------------
553 Double_t AliCentralityGlauberFit::NBDFunc(const Double_t *x, const Double_t *par)
557 Double_t mu = par[0];
560 Double_t ret = exp( TMath::LnGamma(n+k) - TMath::LnGamma(k) - TMath::LnGamma(n+1) ) *
561 TMath::Power(mu/(mu+k),n) * TMath::Power(1-mu/(mu+k),k);
565 //--------------------------------------------------------------------------------------------------
566 TH1F *AliCentralityGlauberFit::MakeAncestor(Double_t alpha)
568 // Make ancestor histogram.
570 TString hname(Form("fhAncestor_%.3f",alpha));
572 if (hname.CompareTo(fhAncestor->GetName())==0)
578 TFile *ancfile = TFile::Open(fAncfilename,"read");
579 if (ancfile && ancfile->IsOpen()) {
580 fhAncestor = dynamic_cast<TH1F*>(ancfile->Get(hname));
582 fhAncestor->SetDirectory(0);
589 fhAncestor = new TH1F(hname,hname,3000,0,3000);
590 fhAncestor->SetDirectory(0);
591 Int_t nents = fGlauntuple->GetEntries();
592 for (Int_t i=0;i<nents;++i) {
593 fGlauntuple->GetEntry(i % nents);
595 if (fAncestor == 1) n = (Int_t) (TMath::Power(fNpart,alpha));
596 //if (fAncestor == 1) n = (Int_t) (TMath::Power(fNcoll,alpha));
597 else if (fAncestor == 2) n = (Int_t) (alpha * fNpart + (1-alpha) * fNcoll);
598 else if (fAncestor == 3) n = (Int_t) ((1-alpha) * fNpart/2 + alpha * fNcoll);
602 ancfile = TFile::Open(fAncfilename,"update");
603 if (ancfile && ancfile->IsOpen()) {