2 // Class to do the energy correction of FMD ESD data
4 #include "AliFMDEnergyFitter.h"
11 #include "AliFMDAnaParameters.h"
13 #include <TClonesArray.h>
14 #include <TFitResult.h>
17 ClassImp(AliFMDEnergyFitter)
19 ; // This is for Emacs
23 //____________________________________________________________________
24 AliFMDEnergyFitter::AliFMDEnergyFitter()
35 fUseIncreasingBins(true),
41 //____________________________________________________________________
42 AliFMDEnergyFitter::AliFMDEnergyFitter(const char* title)
43 : TNamed("fmdEnergyFitter", title),
53 fUseIncreasingBins(true),
58 fEtaAxis.SetName("etaAxis");
59 fEtaAxis.SetTitle("#eta");
60 fRingHistos.Add(new RingHistos(1, 'I'));
61 fRingHistos.Add(new RingHistos(2, 'I'));
62 fRingHistos.Add(new RingHistos(2, 'O'));
63 fRingHistos.Add(new RingHistos(3, 'I'));
64 fRingHistos.Add(new RingHistos(3, 'O'));
67 //____________________________________________________________________
68 AliFMDEnergyFitter::AliFMDEnergyFitter(const AliFMDEnergyFitter& o)
72 fNParticles(o.fNParticles),
73 fMinEntries(o.fMinEntries),
74 fFitRangeBinWidth(o.fFitRangeBinWidth),
79 fUseIncreasingBins(o.fUseIncreasingBins),
80 fMaxRelParError(o.fMaxRelParError),
81 fMaxChi2PerNDF(o.fMaxChi2PerNDF),
84 TIter next(&o.fRingHistos);
86 while ((obj = next())) fRingHistos.Add(obj);
89 //____________________________________________________________________
90 AliFMDEnergyFitter::~AliFMDEnergyFitter()
95 //____________________________________________________________________
97 AliFMDEnergyFitter::operator=(const AliFMDEnergyFitter& o)
102 fNParticles = o.fNParticles;
103 fMinEntries = o.fMinEntries;
104 fFitRangeBinWidth= o.fFitRangeBinWidth;
106 fEtaAxis.Set(o.fEtaAxis.GetNbins(),o.fEtaAxis.GetXmin(),o.fEtaAxis.GetXmax());
109 fRingHistos.Delete();
110 TIter next(&o.fRingHistos);
112 while ((obj = next())) fRingHistos.Add(obj);
117 //____________________________________________________________________
118 AliFMDEnergyFitter::RingHistos*
119 AliFMDEnergyFitter::GetRingHistos(UShort_t d, Char_t r) const
123 case 1: idx = 0; break;
124 case 2: idx = 1 + (r == 'I' || r == 'i' ? 0 : 1); break;
125 case 3: idx = 3 + (r == 'I' || r == 'i' ? 0 : 1); break;
127 if (idx < 0 || idx >= fRingHistos.GetEntries()) return 0;
129 return static_cast<RingHistos*>(fRingHistos.At(idx));
132 //____________________________________________________________________
134 AliFMDEnergyFitter::Init(const TAxis& eAxis)
136 if (fEtaAxis.GetNbins() == 0 ||
137 fEtaAxis.GetXmin() == fEtaAxis.GetXmax())
139 TIter next(&fRingHistos);
141 while ((o = static_cast<RingHistos*>(next())))
142 o->Init(fEtaAxis, fMaxE, fNEbins, fUseIncreasingBins);
144 //____________________________________________________________________
146 AliFMDEnergyFitter::SetEtaAxis(const TAxis& eAxis)
148 SetEtaAxis(eAxis.GetNbins(),eAxis.GetXmin(),eAxis.GetXmax());
150 //____________________________________________________________________
152 AliFMDEnergyFitter::SetEtaAxis(Int_t nBins, Double_t etaMin, Double_t etaMax)
154 fEtaAxis.Set(nBins,etaMin,etaMax);
157 //____________________________________________________________________
159 AliFMDEnergyFitter::Accumulate(const AliESDFMD& input,
162 for(UShort_t d = 1; d <= 3; d++) {
163 Int_t nRings = (d == 1 ? 1 : 2);
164 for (UShort_t q = 0; q < nRings; q++) {
165 Char_t r = (q == 0 ? 'I' : 'O');
166 UShort_t nsec = (q == 0 ? 20 : 40);
167 UShort_t nstr = (q == 0 ? 512 : 256);
169 RingHistos* histos = GetRingHistos(d, r);
171 for(UShort_t s = 0; s < nsec; s++) {
172 for(UShort_t t = 0; t < nstr; t++) {
173 Float_t mult = input.Multiplicity(d,r,s,t);
175 // Keep dead-channel information.
176 if(mult == AliESDFMD::kInvalidMult || mult > 10 || mult <= 0)
179 // Get the pseudo-rapidity
180 Double_t eta1 = input.Eta(d,r,s,t);
181 Int_t ieta = fEtaAxis.FindBin(eta1);
182 if (ieta < 1 || ieta > fEtaAxis.GetNbins()) continue;
184 histos->Fill(empty, ieta-1, mult);
194 //____________________________________________________________________
196 AliFMDEnergyFitter::Fit(TList* dir)
198 if (!fDoFits) return;
200 TList* d = static_cast<TList*>(dir->FindObject(GetName()));
206 // +fNParticles-1 for weights
207 Int_t nStack = kN+fNParticles;
208 THStack* stack[nStack];
209 stack[0] = new THStack("chi2", "#chi^{2}/#nu");
210 stack[kC +1] = new THStack("c", "Constant");
211 stack[kDelta +1] = new THStack("delta", "#Delta_{p}");
212 stack[kXi +1] = new THStack("xi", "#xi");
213 stack[kSigma +1] = new THStack("sigma", "#sigma");
214 stack[kSigmaN+1] = new THStack("sigman", "#sigma_{n}");
215 stack[kN +1] = new THStack("n", "# Particles");
216 for (Int_t i = 2; i <= fNParticles; i++)
217 stack[kN+i] = new THStack(Form("a%d", i), Form("a_{%d}", i));
218 for (Int_t i = 0; i < nStack; i++)
221 TIter next(&fRingHistos);
223 while ((o = static_cast<RingHistos*>(next()))) {
224 TObjArray* l = o->Fit(d, fEtaAxis, fLowCut, fNParticles,
225 fMinEntries, fFitRangeBinWidth,
226 fMaxRelParError, fMaxChi2PerNDF);
228 for (Int_t i = 0; i < l->GetEntriesFast(); i++) {
229 stack[i % nStack]->Add(static_cast<TH1*>(l->At(i)));
234 //____________________________________________________________________
236 AliFMDEnergyFitter::DefineOutput(TList* dir)
238 TList* d = new TList;
239 d->SetName(GetName());
242 TIter next(&fRingHistos);
244 while ((o = static_cast<RingHistos*>(next()))) {
248 //____________________________________________________________________
250 AliFMDEnergyFitter::SetDebug(Int_t dbg)
253 TIter next(&fRingHistos);
255 while ((o = static_cast<RingHistos*>(next())))
259 //====================================================================
260 AliFMDEnergyFitter::RingHistos::RingHistos()
261 : AliForwardUtil::RingHistos(),
269 //____________________________________________________________________
270 AliFMDEnergyFitter::RingHistos::RingHistos(UShort_t d, Char_t r)
271 : AliForwardUtil::RingHistos(d,r),
278 fEtaEDists.SetName("EDists");
280 //____________________________________________________________________
281 AliFMDEnergyFitter::RingHistos::RingHistos(const RingHistos& o)
282 : AliForwardUtil::RingHistos(o),
289 TIter next(&o.fEtaEDists);
291 while ((obj = next())) fEtaEDists.Add(obj->Clone());
294 fList->SetName(fName);
295 TIter next2(o.fList);
296 while ((obj = next2())) fList->Add(obj->Clone());
300 //____________________________________________________________________
301 AliFMDEnergyFitter::RingHistos&
302 AliFMDEnergyFitter::RingHistos::operator=(const RingHistos& o)
304 AliForwardUtil::RingHistos::operator=(o);
306 if (fEDist) delete fEDist;
307 if (fEmpty) delete fEmpty;
309 if (fList) fList->Delete();
311 fEDist = static_cast<TH1D*>(o.fEDist->Clone());
312 fEmpty = static_cast<TH1D*>(o.fEmpty->Clone());
314 TIter next(&o.fEtaEDists);
316 while ((obj = next())) fEtaEDists.Add(obj->Clone());
320 fList->SetName(fName);
321 TIter next2(o.fList);
322 while ((obj = next2())) fList->Add(obj->Clone());
327 //____________________________________________________________________
328 AliFMDEnergyFitter::RingHistos::~RingHistos()
330 if (fEDist) delete fEDist;
334 //____________________________________________________________________
336 AliFMDEnergyFitter::RingHistos::Fill(Bool_t empty, Int_t ieta, Double_t mult)
344 if (ieta < 0 || ieta >= fEtaEDists.GetEntries()) return;
346 TH1D* h = static_cast<TH1D*>(fEtaEDists.At(ieta));
352 //__________________________________________________________________
354 AliFMDEnergyFitter::RingHistos::MakeIncreasingAxis(Int_t n, Double_t min,
357 // Service function to define a logarithmic axis.
360 // min Minimum of axis
361 // max Maximum of axis
363 Double_t dx = (max-min) / n;
366 for (i = 1; i < n+1; i++) {
367 Double_t dI = float(i)/n;
368 Double_t next = bins[i-1] + dx + dI * dI * dx;
370 if (next > max) break;
376 //____________________________________________________________________
378 AliFMDEnergyFitter::RingHistos::Make(Int_t ieta,
386 TString name = Form("%s_etabin%03d", fName.Data(), ieta);
387 TString title = Form("#DeltaE/#DeltaE_{mip} for %s %+5.3f#leq#eta<%+5.3f "
388 "(#eta bin %d)", fName.Data(), emin, emax, ieta);
390 h = new TH1D(name.Data(), title.Data(), nDeBins, 0, deMax);
392 TArrayD deAxis = MakeIncreasingAxis(nDeBins, 0, deMax);
393 h = new TH1D(name.Data(), title.Data(), deAxis.fN-1, deAxis.fArray);
397 h->SetXTitle("#DeltaE/#DeltaE_{mip}");
398 h->SetFillColor(Color());
399 h->SetMarkerColor(Color());
400 h->SetLineColor(Color());
401 h->SetFillStyle(3001);
404 fEtaEDists.AddAt(h, ieta-1);
406 //____________________________________________________________________
407 TH1D* AliFMDEnergyFitter::RingHistos::MakePar(const char* name,
409 const TAxis& eta) const
411 TH1D* h = new TH1D(Form("%s_%s", fName.Data(), name),
412 Form("%s for %s", title, fName.Data()),
413 eta.GetNbins(), eta.GetXmin(), eta.GetXmax());
414 h->SetXTitle("#eta");
417 h->SetFillColor(Color());
418 h->SetMarkerColor(Color());
419 h->SetLineColor(Color());
420 h->SetFillStyle(3001);
425 //____________________________________________________________________
427 AliFMDEnergyFitter::RingHistos::MakeTotal(const char* name,
435 Double_t xlow = eta.GetBinLowEdge(low);
436 Double_t xhigh = eta.GetBinUpEdge(high);
437 TH1D* h = new TH1D(Form("%s_%s", fName.Data(), name),
438 Form("%s for %s", title, fName.Data()),
440 h->SetBinContent(1, val);
441 h->SetBinError(1, err);
442 h->SetXTitle("#eta");
446 h->SetMarkerColor(Color());
447 h->SetLineColor(Color());
455 //____________________________________________________________________
457 AliFMDEnergyFitter::RingHistos::Init(const TAxis& eAxis,
458 Double_t maxDE, Int_t nDEbins,
461 fEDist = new TH1D(Form("%s_edist", fName.Data()),
462 Form("#DeltaE/#DeltaE_{mip} for %s", fName.Data()),
464 fEmpty = new TH1D(Form("%s_empty", fName.Data()),
465 Form("#DeltaE/#DeltaE_{mip} for %s (empty events)",
466 fName.Data()), 200, 0, 6);
469 // fEtaEDists.Expand(eAxis.GetNbins());
470 for (Int_t i = 1; i <= eAxis.GetNbins(); i++) {
471 Double_t min = eAxis.GetBinLowEdge(i);
472 Double_t max = eAxis.GetBinUpEdge(i);
473 Make(i, min, max, maxDE, nDEbins, useIncrBin);
475 fList->Add(&fEtaEDists);
477 //____________________________________________________________________
479 AliFMDEnergyFitter::RingHistos::Fit(TList* dir, const TAxis& eta,
484 Double_t relErrorCut,
485 Double_t chi2nuCut) const
487 // Get our ring list from the output container
488 TList* l = GetOutputList(dir);
491 // Get the energy distributions from the output container
492 TList* dists = static_cast<TList*>(l->FindObject("EDists"));
494 AliWarning(Form("Didn't find %s_EtaEDists in %s",
495 fName.Data(), l->GetName()));
500 // Container of the fit results histograms
501 TObjArray* pars = new TObjArray(3+nParticles+1);
502 pars->SetName("FitResults");
505 // Result objects stored in separate list on the output
513 TH1* hA[nParticles-1];
514 pars->Add(hChi2 = MakePar("chi2", "#chi^{2}/#nu", eta));
515 pars->Add(hC = MakePar("c", "Constant", eta));
516 pars->Add(hDelta = MakePar("delta", "#Delta_{p}", eta));
517 pars->Add(hXi = MakePar("xi", "#xi", eta));
518 pars->Add(hSigma = MakePar("sigma", "#sigma", eta));
519 pars->Add(hSigmaN = MakePar("sigman", "#sigma_{n}", eta));
520 pars->Add(hN = MakePar("n", "N", eta));
521 for (UShort_t i = 1; i < nParticles; i++)
522 pars->Add(hA[i-1] = MakePar(Form("a%d",i+1), Form("a_{%d}",i+1), eta));
525 Int_t nDists = dists->GetEntries();
528 for (Int_t i = 0; i < nDists; i++) {
529 TH1D* dist = static_cast<TH1D*>(dists->At(i));
530 // Ignore empty histograms altoghether
531 if (!dist || dist->GetEntries() <= 0) continue;
533 // Scale to the bin-width
534 dist->Scale(1., "width");
536 // Normalize peak to 1
537 Double_t max = dist->GetMaximum();
540 // Check that we have enough entries
541 if (dist->GetEntries() <= minEntries) continue;
544 TF1* res = FitHist(dist,lowCut,nParticles,minusBins,
545 relErrorCut,chi2nuCut);
547 // dist->GetListOfFunctions()->Add(res);
550 low = TMath::Min(low,i+1);
551 high = TMath::Max(high,i+1);
553 // Get the reduced chi square
554 Double_t chi2 = res->GetChisquare();
555 Int_t ndf = res->GetNDF();
557 // Store results of best fit in output histograms
558 res->SetLineWidth(4);
559 hChi2 ->SetBinContent(i+1, ndf > 0 ? chi2 / ndf : 0);
560 hC ->SetBinContent(i+1, res->GetParameter(kC));
561 hDelta ->SetBinContent(i+1, res->GetParameter(kDelta));
562 hXi ->SetBinContent(i+1, res->GetParameter(kXi));
563 hSigma ->SetBinContent(i+1, res->GetParameter(kSigma));
564 hSigmaN ->SetBinContent(i+1, res->GetParameter(kSigmaN));
565 hN ->SetBinContent(i+1, res->GetParameter(kN));
567 hC ->SetBinError(i+1, res->GetParError(kC));
568 hDelta ->SetBinError(i+1, res->GetParError(kDelta));
569 hXi ->SetBinError(i+1, res->GetParError(kXi));
570 hSigma ->SetBinError(i+1, res->GetParError(kSigma));
571 hSigmaN->SetBinError(i+1, res->GetParError(kSigmaN));
572 hN ->SetBinError(i+1, res->GetParError(kN));
574 for (UShort_t j = 0; j < nParticles-1; j++) {
575 hA[j]->SetBinContent(i+1, res->GetParameter(kA+j));
576 hA[j]->SetBinError(i+1, res->GetParError(kA+j));
580 // Fit the full-ring histogram
581 TH1* total = GetOutputHist(l, Form("%s_edist", fName.Data()));
582 if (total && total->GetEntries() >= minEntries) {
583 TF1* res = FitHist(total,lowCut,nParticles,minusBins,
584 relErrorCut,chi2nuCut);
586 // Make histograms for the result of this fit
587 Double_t chi2 = res->GetChisquare();
588 Int_t ndf = res->GetNDF();
589 pars->Add(MakeTotal("t_chi2", "#chi^{2}/#nu", eta, low, high,
590 ndf > 0 ? chi2/ndf : 0, 0));
591 pars->Add(MakeTotal("t_c", "Constant", eta, low, high,
592 res->GetParameter(kC),
593 res->GetParError(kC)));
594 pars->Add(MakeTotal("t_delta", "#Delta_{p}", eta, low, high,
595 res->GetParameter(kDelta),
596 res->GetParError(kDelta)));
597 pars->Add(MakeTotal("t_xi", "#xi", eta, low, high,
598 res->GetParameter(kXi),
599 res->GetParError(kXi)));
600 pars->Add(MakeTotal("t_sigma", "#sigma", eta, low, high,
601 res->GetParameter(kSigma),
602 res->GetParError(kSigma)));
603 pars->Add(MakeTotal("t_sigman", "#sigma_{n}", eta, low, high,
604 res->GetParameter(kSigmaN),
605 res->GetParError(kSigmaN)));
606 pars->Add(MakeTotal("t_n", "N", eta, low, high,
607 res->GetParameter(kN),0));
608 for (UShort_t j = 0; j < nParticles-1; j++)
609 pars->Add(MakeTotal(Form("t_a%d",j+2),
610 Form("a_{%d}",j+2), eta, low, high,
611 res->GetParameter(kA+j),
612 res->GetParError(kA+j)));
616 // Clean up list of histogram. Histograms with no entries or
617 // no functions are deleted. We have to do this using the TObjLink
618 // objects stored in the list since ROOT cannot guaranty the validity
619 // of iterators when removing from a list - tsck. Should just implement
621 TObjLink* lnk = dists->FirstLink();
623 TH1* h = static_cast<TH1*>(lnk->GetObject());
624 if (h->GetEntries() <= 0 ||
625 h->GetListOfFunctions()->GetEntries() <= 0) {
626 TObjLink* keep = lnk->Next();
637 //____________________________________________________________________
639 AliFMDEnergyFitter::RingHistos::FitHist(TH1* dist,
643 Double_t relErrorCut,
644 Double_t chi2nuCut) const
646 Double_t maxRange = 10;
648 // Create a fitter object
649 AliForwardUtil::ELossFitter f(lowCut, maxRange, minusBins);
653 // If we are only asked to fit a single particle, return this fit,
655 if (nParticles == 1) {
656 TF1* r = f.Fit1Particle(dist, 0);
661 // Fit from 2 upto n particles
662 for (Int_t i = 2; i <= nParticles; i++) f.FitNParticle(dist, i, 0);
665 // Now, we need to select the best fit
666 Int_t nFits = f.fFitResults.GetEntriesFast();
668 for (Int_t i = nFits-1; i >= 0; i--) {
670 TF1* ff = static_cast<TF1*>(f.fFunctions.At(i));
671 // ff->SetLineColor(Color());
672 ff->SetRange(0, maxRange);
673 dist->GetListOfFunctions()->Add(new TF1(*ff));
674 if (CheckResult(static_cast<TFitResult*>(f.fFitResults.At(i)),
675 relErrorCut, chi2nuCut)) {
678 // f.fFitResults.At(i)->Print("V");
681 // If all else fails, use the 1 particle fit
682 TF1* ret = static_cast<TF1*>(f.fFunctions.At(0));
684 // Find the fit with the most valid particles
685 for (Int_t i = nFits-1; i > 0; i--) {
686 if (!good[i]) continue;
688 AliInfo(Form("Choosing fit with n=%d", i+1));
689 f.fFitResults.At(i)->Print();
694 // Give a warning if we're using fall-back
695 if (ret == f.fFunctions.At(0))
696 AliWarning("Choosing fall-back 1 particle fit");
698 // Copy our result and return (the functions are owned by the fitter)
699 TF1* fret = new TF1(*ret);
703 //____________________________________________________________________
705 AliFMDEnergyFitter::RingHistos::CheckResult(TFitResult* r,
706 Double_t relErrorCut,
707 Double_t chi2nuCut) const
709 if (fDebug > 10) r->Print();
710 TString n = r->GetName();
711 n.ReplaceAll("TFitResult-", "");
712 Double_t chi2 = r->Chi2();
713 Int_t ndf = r->Ndf();
714 // Double_t prob = r.Prob();
717 // Check that the reduced chi square isn't larger than 5
718 if (ndf <= 0 || chi2 / ndf > chi2nuCut) {
720 AliWarning(Form("%s: chi^2/ndf=%12.5f/%3d=%12.5f>%12.5f",
721 n.Data(), chi2, ndf, (ndf<0 ? 0 : chi2/ndf),
726 // Check each parameter
727 UShort_t nPar = r->NPar();
728 for (UShort_t i = 0; i < nPar; i++) {
729 if (i == kN) continue; // Skip the number parameter
731 // Get value and error and check value
732 Double_t v = r->Parameter(i);
733 Double_t e = r->ParError(i);
734 if (v == 0) continue;
736 // Calculate the relative error and check it
738 Double_t cut = relErrorCut * (i < kN ? 1 : 2);
741 AliWarning(Form("%s: Delta %s/%s=%9.5f/%9.5f=%5.1f%%>%5.1f%%",
742 n.Data(), r->ParName(i).c_str(),
743 r->ParName(i).c_str(), e, v,
744 100*(v == 0 ? 0 : e/v),
750 // Check if we have scale parameters
753 // Check that the last particle has a significant contribution
754 Double_t lastScale = r->Parameter(nPar-1);
755 if (lastScale <= 1e-7) {
757 AliWarning(Form("%s: %s=%9.6f<1e-7",
758 n.Data(), r->ParName(nPar-1).c_str(), lastScale));
766 //____________________________________________________________________
768 AliFMDEnergyFitter::RingHistos::Output(TList* dir)
770 fList = DefineOutputList(dir);
773 //____________________________________________________________________