1 // This class calculates the inclusive charged particle density
2 // in each for the 5 FMD rings.
4 #include "AliFMDDensityCalculator.h"
9 #include "AliForwardCorrectionManager.h"
10 #include "AliFMDCorrDoubleHit.h"
11 #include "AliFMDCorrELossFit.h"
13 #include "AliForwardUtil.h"
19 #include <TStopwatch.h>
20 #include <TParameter.h>
25 ClassImp(AliFMDDensityCalculator)
30 //____________________________________________________________________
31 const char* AliFMDDensityCalculator::fgkFolderName = "fmdDensityCalculator";
33 //____________________________________________________________________
34 AliFMDDensityCalculator::AliFMDDensityCalculator()
42 fUsePhiAcceptance(kPhiCorrectNch),
56 fRecalculatePhi(false),
67 DGUARD(fDebug, 3, "Default CTOR of FMD density calculator");
70 //____________________________________________________________________
71 AliFMDDensityCalculator::AliFMDDensityCalculator(const char* title)
72 : TNamed(fgkFolderName, title),
79 fUsePhiAcceptance(kPhiCorrectNch),
93 fRecalculatePhi(false),
105 // name Name of object
107 DGUARD(fDebug, 3, "Named CTOR of FMD density calculator: %s", title);
108 fRingHistos.SetName(GetName());
109 fRingHistos.SetOwner();
110 fRingHistos.Add(new RingHistos(1, 'I'));
111 fRingHistos.Add(new RingHistos(2, 'I'));
112 fRingHistos.Add(new RingHistos(2, 'O'));
113 fRingHistos.Add(new RingHistos(3, 'I'));
114 fRingHistos.Add(new RingHistos(3, 'O'));
115 fSumOfWeights = new TH1D("sumOfWeights", "Sum of Landau weights",
117 fSumOfWeights->SetFillColor(kRed+1);
118 fSumOfWeights->SetXTitle("#sum_{i} a_{i} f_{i}(#Delta)");
119 fWeightedSum = new TH1D("weightedSum", "Weighted sum of Landau propability",
121 fWeightedSum->SetFillColor(kBlue+1);
122 fWeightedSum->SetXTitle("#sum_{i} i a_{i} f_{i}(#Delta)");
123 fCorrections = new TH1D("corrections", "Distribution of corrections",
125 fCorrections->SetFillColor(kBlue+1);
126 fCorrections->SetXTitle("correction");
128 fAccI = GenerateAcceptanceCorrection('I');
129 fAccO = GenerateAcceptanceCorrection('O');
131 fMaxWeights = new TH2D("maxWeights", "Maximum i of a_{i}'s to use",
133 fMaxWeights->SetXTitle("#eta");
134 fMaxWeights->SetDirectory(0);
136 fLowCuts = new TH2D("lowCuts", "Low cuts used", 1, 0, 1, 1, 0, 1);
137 fLowCuts->SetXTitle("#eta");
138 fLowCuts->SetDirectory(0);
142 //____________________________________________________________________
143 AliFMDDensityCalculator::AliFMDDensityCalculator(const
144 AliFMDDensityCalculator& o)
147 fSumOfWeights(o.fSumOfWeights),
148 fWeightedSum(o.fWeightedSum),
149 fCorrections(o.fCorrections),
150 fMaxParticles(o.fMaxParticles),
151 fUsePoisson(o.fUsePoisson),
152 fUsePhiAcceptance(o.fUsePhiAcceptance),
155 fFMD1iMax(o.fFMD1iMax),
156 fFMD2iMax(o.fFMD2iMax),
157 fFMD2oMax(o.fFMD2oMax),
158 fFMD3iMax(o.fFMD3iMax),
159 fFMD3oMax(o.fFMD3oMax),
160 fMaxWeights(o.fMaxWeights),
161 fLowCuts(o.fLowCuts),
162 fEtaLumping(o.fEtaLumping),
163 fPhiLumping(o.fPhiLumping),
166 fRecalculatePhi(o.fRecalculatePhi),
167 fMinQuality(o.fMinQuality),
169 fDoTiming(o.fDoTiming),
170 fHTiming(o.fHTiming),
171 fMaxOutliers(o.fMaxOutliers),
172 fOutlierCut(o.fOutlierCut)
178 // o Object to copy from
180 DGUARD(fDebug, 3, "Copy CTOR of FMD density calculator");
181 TIter next(&o.fRingHistos);
183 while ((obj = next())) fRingHistos.Add(obj);
186 //____________________________________________________________________
187 AliFMDDensityCalculator::~AliFMDDensityCalculator()
192 DGUARD(fDebug, 3, "DTOR of FMD density calculator");
193 // fRingHistos.Delete();
196 //____________________________________________________________________
197 AliFMDDensityCalculator&
198 AliFMDDensityCalculator::operator=(const AliFMDDensityCalculator& o)
201 // Assignement operator
204 // o Object to assign from
207 // Reference to this object
209 DGUARD(fDebug, 3, "Assignment of FMD density calculator");
210 if (&o == this) return *this;
211 TNamed::operator=(o);
214 fMaxParticles = o.fMaxParticles;
215 fUsePoisson = o.fUsePoisson;
216 fUsePhiAcceptance = o.fUsePhiAcceptance;
219 fFMD1iMax = o.fFMD1iMax;
220 fFMD2iMax = o.fFMD2iMax;
221 fFMD2oMax = o.fFMD2oMax;
222 fFMD3iMax = o.fFMD3iMax;
223 fFMD3oMax = o.fFMD3oMax;
224 fMaxWeights = o.fMaxWeights;
225 fLowCuts = o.fLowCuts;
226 fEtaLumping = o.fEtaLumping;
227 fPhiLumping = o.fPhiLumping;
229 fRecalculatePhi = o.fRecalculatePhi;
230 fMinQuality = o.fMinQuality;
232 fDoTiming = o.fDoTiming;
233 fHTiming = o.fHTiming;
234 fMaxOutliers = o.fMaxOutliers;
235 fOutlierCut = o.fOutlierCut;
237 fRingHistos.Delete();
238 TIter next(&o.fRingHistos);
240 while ((obj = next())) fRingHistos.Add(obj);
245 //____________________________________________________________________
247 AliFMDDensityCalculator::SetupForData(const TAxis& axis)
249 // Intialize this sub-algorithm
253 DGUARD(fDebug, 1, "Initialize FMD density calculator");
254 CacheMaxWeights(axis);
258 TIter next(&fRingHistos);
260 while ((o = static_cast<RingHistos*>(next()))) {
261 o->SetupForData(axis);
262 // o->fMultCut = fCuts.GetFixedCut(o->fDet, o->fRing);
263 // o->fPoisson.Init(o->fDet,o->fRing,fEtaLumping, fPhiLumping);
267 //____________________________________________________________________
268 AliFMDDensityCalculator::RingHistos*
269 AliFMDDensityCalculator::GetRingHistos(UShort_t d, Char_t r) const
272 // Get the ring histogram container
279 // Ring histogram container
283 case 1: idx = 0; break;
284 case 2: idx = 1 + (r == 'I' || r == 'i' ? 0 : 1); break;
285 case 3: idx = 3 + (r == 'I' || r == 'i' ? 0 : 1); break;
287 if (idx < 0 || idx >= fRingHistos.GetEntries()) {
288 AliWarning(Form("Index %d of FMD%d%c out of range", idx, d, r));
292 return static_cast<RingHistos*>(fRingHistos.At(idx));
296 Double_t Rng2Cut(UShort_t d, Char_t r, Int_t xbin, TH2* h)
299 if (xbin < 1 && xbin > h->GetXaxis()->GetNbins()) return ret;
302 case 1: ybin = 1; break;
303 case 2: ybin = (r=='i' || r=='I') ? 2 : 3; break;
304 case 3: ybin = (r=='i' || r=='I') ? 4 : 5; break;
307 ret = h->GetBinContent(xbin,ybin);
312 //____________________________________________________________________
314 AliFMDDensityCalculator::GetMultCut(UShort_t d, Char_t r, Int_t ieta,
315 Bool_t /*errors*/) const
318 // Get the multiplicity cut. If the user has set fMultCut (via
319 // SetMultCut) then that value is used. If not, then the lower
320 // value of the fit range for the enery loss fits is returned.
323 // Lower cut on multiplicity
325 return Rng2Cut(d, r, ieta, fLowCuts);
326 // return fCuts.GetMultCut(d,r,ieta,errors);
329 //____________________________________________________________________
331 AliFMDDensityCalculator::GetMultCut(UShort_t d, Char_t r, Double_t eta,
332 Bool_t /*errors*/) const
335 // Get the multiplicity cut. If the user has set fMultCut (via
336 // SetMultCut) then that value is used. If not, then the lower
337 // value of the fit range for the enery loss fits is returned.
340 // Lower cut on multiplicity
342 Int_t ieta = fLowCuts->GetXaxis()->FindBin(eta);
343 return Rng2Cut(d, r, ieta, fLowCuts);
344 // return fCuts.GetMultCut(d,r,eta,errors);
348 # define START_TIMER(T) if (fDoTiming) T.Start(true)
349 # define GET_TIMER(T,V) if (fDoTiming) V = T.CpuTime()
350 # define ADD_TIMER(T,V) if (fDoTiming) V += T.CpuTime()
352 # define START_TIMER(T) do {} while (false)
353 # define GET_TIMER(T,V) do {} while (false)
354 # define ADD_TIMER(T,V) do {} while (false)
357 //____________________________________________________________________
359 AliFMDDensityCalculator::Calculate(const AliESDFMD& fmd,
360 AliForwardUtil::Histos& hists,
366 // Do the calculations
369 // fmd AliESDFMD object (possibly) corrected for sharing
370 // hists Histogram cache
372 // lowFlux Low flux flag.
376 DGUARD(fDebug, 1, "Calculate density in FMD density calculator");
381 // First measurements of timing
382 // Re-calculation : fraction of sum 32.0% of total 18.1%
383 // N_{particle} : fraction of sum 15.2% of total 8.6%
384 // Correction : fraction of sum 26.4% of total 14.9%
385 // #phi acceptance : fraction of sum 0.2% of total 0.1%
386 // Copy to cache : fraction of sum 3.9% of total 2.2%
387 // Poisson calculation : fraction of sum 18.7% of total 10.6%
388 // Diagnostics : fraction of sum 3.7% of total 2.1%
389 Double_t nPartTime = 0;
390 Double_t corrTime = 0;
391 Double_t rePhiTime = 0;
392 Double_t copyTime = 0;
393 Double_t poissonTime= 0;
394 Double_t diagTime = 0;
397 Double_t etaCache[20*512]; // Same number of strips per ring
398 Double_t phiCache[20*512]; // whether it is inner our outer.
399 // We do not use TArrayD because we do not wont a bounds check
400 // TArrayD etaCache(20*512); // Same number of strips per ring
401 // TArrayD phiCache(20*512); // whether it is inner our outer.
403 // --- Loop over detectors -----------------------------------------
404 for (UShort_t d=1; d<=3; d++) {
405 UShort_t nr = (d == 1 ? 1 : 2);
406 for (UShort_t q=0; q<nr; q++) {
407 Char_t r = (q == 0 ? 'I' : 'O');
408 UShort_t ns= (q == 0 ? 20 : 40);
409 UShort_t nt= (q == 0 ? 512 : 256);
410 TH2D* h = hists.Get(d,r);
411 RingHistos* rh= GetRingHistos(d,r);
413 AliError(Form("No ring histogram found for FMD%d%c", d, r));
417 // rh->fPoisson.SetObject(d,r,vtxbin,cent);
418 rh->fPoisson.Reset(0);
421 // rh->ResetPoissonHistos(h, fEtaLumping, fPhiLumping);
423 // Reset our eta cache
424 // for (Int_t i = 0; i < 20*512; i++)
425 // etaCache[i] = phiCache[i] = AliESDFMD::kInvalidEta;
426 memset(etaCache, 0, sizeof(Double_t)*20*512);
427 memset(phiCache, 0, sizeof(Double_t)*20*512);
428 // etaCache.Reset(AliESDFMD::kInvalidEta);
429 // phiCache.Reset(AliESDFMD::kInvalidEta);
431 // --- Loop over sectors and strips ----------------------------
432 for (UShort_t s=0; s<ns; s++) {
433 for (UShort_t t=0; t<nt; t++) {
435 Float_t mult = fmd.Multiplicity(d,r,s,t);
436 Float_t phi = fmd.Phi(d,r,s,t) * TMath::DegToRad();
437 Float_t eta = fmd.Eta(d,r,s,t);
438 Double_t oldPhi = phi;
440 // --- Re-calculate eta - needed for satelittes ------------
442 etaCache[s*nt+t] = eta;
444 // --- Check this strip ------------------------------------
445 rh->fTotal->Fill(eta);
446 if (mult == AliESDFMD::kInvalidMult) { // || mult > 20) {
447 // Do not count invalid stuff
448 rh->fELoss->Fill(-1);
449 // rh->fEvsN->Fill(mult,-1);
450 // rh->fEvsM->Fill(mult,-1);
454 AliWarningF("Raw multiplicity of FMD%d%c[%02d,%03d] = %f > 20",
456 // --- Automatic calculation of acceptance -----------------
457 rh->fGood->Fill(eta);
459 // --- If we asked to re-calculate phi for (x,y) IP --------
461 if (fRecalculatePhi) {
463 phi = AliForwardUtil::GetPhiFromStrip(r, t, phi, ip.X(), ip.Y());
465 phiCache[s*nt+t] = phi;
466 ADD_TIMER(timer,rePhiTime);
468 // --- Apply phi corner correction to eloss ----------------
469 if (fUsePhiAcceptance == kPhiCorrectELoss)
470 mult *= AcceptanceCorrection(r,t);
472 // --- Get the low multiplicity cut ------------------------
474 if (eta != AliESDFMD::kInvalidEta) cut = GetMultCut(d, r, eta,false);
475 else AliWarningF("Eta for FMD%d%c[%02d,%03d] is invalid: %f",
478 // --- Now caluculate Nch for this strip using fits --------
481 if (cut > 0 && mult > cut) n = NParticles(mult,d,r,eta,lowFlux);
482 rh->fELoss->Fill(mult);
483 // rh->fEvsN->Fill(mult,n);
484 // rh->fEtaVsN->Fill(eta, n);
485 ADD_TIMER(timer,nPartTime);
487 // --- Calculate correction if needed ----------------------
489 // Temporary stuff - remove Correction call
491 if (fUsePhiAcceptance == kPhiCorrectNch)
492 c = AcceptanceCorrection(r,t);
493 // Double_t c = Correction(d,r,t,eta,lowFlux);
494 ADD_TIMER(timer,corrTime);
495 fCorrections->Fill(c);
497 // rh->fEvsM->Fill(mult,n);
498 // rh->fEtaVsM->Fill(eta, n);
499 rh->fCorr->Fill(eta, c);
501 // --- Accumulate Poisson statistics -----------------------
502 Bool_t hit = (n > 0.9 && c > 0);
504 rh->fELossUsed->Fill(mult);
505 if (fRecalculatePhi) {
506 rh->fPhiBefore->Fill(oldPhi);
507 rh->fPhiAfter->Fill(phi);
510 rh->fPoisson.Fill(t,s,hit,1./c);
513 // --- If we use ELoss fits, apply now ---------------------
514 if (!fUsePoisson) rh->fDensity->Fill(eta,phi,n);
518 // --- Automatic acceptance - Calculate as an efficiency -------
519 // This is very fast, so we do not bother to time it
520 rh->fGood->Divide(rh->fGood, rh->fTotal, 1, 1, "B");
522 // --- Make a copy and reset as needed -------------------------
524 TH2D* hclone = fCache.Get(d,r);
526 // TH2D* hclone = static_cast<TH2D*>(h->Clone("hclone"));
527 if (!fUsePoisson) hclone->Reset();
529 for (Int_t i = 0; i <= h->GetNbinsX()+1; i++) {
530 for (Int_t j = 0; j <= h->GetNbinsY()+1; j++) {
531 hclone->SetBinContent(i,j,h->GetBinContent(i,j));
532 hclone->SetBinError(i,j,h->GetBinError(i,j));
538 ADD_TIMER(timer,copyTime);
540 // --- Store Poisson result ------------------------------------
542 TH2D* poisson = rh->fPoisson.Result();
543 for (Int_t t=0; t < poisson->GetNbinsX(); t++) {
544 for (Int_t s=0; s < poisson->GetNbinsY(); s++) {
546 Double_t poissonV = poisson->GetBinContent(t+1,s+1);
547 // Use cached eta - since the calls to GetEtaFromStrip and
548 // GetPhiFromStrip are _very_ expensive
549 Double_t phi = phiCache[s*nt+t];
550 Double_t eta = etaCache[s*nt+t];
551 // Double_t phi = fmd.Phi(d,r,s,t) * TMath::DegToRad();
552 // Double_t eta = fmd.Eta(d,r,s,t);
554 h->Fill(eta,phi,poissonV);
555 rh->fDensity->Fill(eta, phi, poissonV);
558 hclone->Fill(eta,phi,poissonV);
561 ADD_TIMER(timer,poissonTime);
563 // --- Make diagnostics - eloss vs poisson ---------------------
565 Int_t nY = h->GetNbinsY();
566 Int_t nIn = 0; // Count non-outliers
567 Int_t nOut = 0; // Count outliers
568 for (Int_t ieta=1; ieta <= h->GetNbinsX(); ieta++) {
569 // Set the overflow bin to contain the phi acceptance
570 Double_t phiAcc = rh->fGood->GetBinContent(ieta);
571 Double_t phiAccE = rh->fGood->GetBinError(ieta);
572 h->SetBinContent(ieta, nY+1, phiAcc);
573 h->SetBinError(ieta, nY+1, phiAccE);
574 Double_t eta = h->GetXaxis()->GetBinCenter(ieta);
575 rh->fPhiAcc->Fill(eta, ip.Z(), phiAcc);
576 for (Int_t iphi=1; iphi<= nY; iphi++) {
578 Double_t poissonV = 0; //h->GetBinContent(,s+1);
581 poissonV = h->GetBinContent(ieta,iphi);
582 eLossV = hclone->GetBinContent(ieta,iphi);
585 poissonV = hclone->GetBinContent(ieta,iphi);
586 eLossV = h->GetBinContent(ieta,iphi);
589 if (poissonV < 1e-12 && eLossV < 1e-12)
590 // we do not care about trivially empty bins
593 Bool_t outlier = CheckOutlier(eLossV, poissonV, fOutlierCut);
594 Double_t rel = eLossV < 1e-12 ? 0 : (poissonV - eLossV) / eLossV;
596 rh->fELossVsPoissonOut->Fill(eLossV, poissonV);
597 rh->fDiffELossPoissonOut->Fill(rel);
601 rh->fELossVsPoisson->Fill(eLossV, poissonV);
602 rh->fDiffELossPoisson->Fill(rel);
607 Int_t nTotal = (nIn+nOut);
608 Double_t outRatio = (nTotal > 0 ? Double_t(nOut) / nTotal : 0);
609 rh->fOutliers->Fill(outRatio);
610 if (outRatio < fMaxOutliers) rh->fPoisson.FillDiagnostics();
611 else h->SetBit(AliForwardUtil::kSkipRing);
612 ADD_TIMER(timer,diagTime);
619 // fHTiming->Fill(1,reEtaTime);
620 fHTiming->Fill(2,nPartTime);
621 fHTiming->Fill(3,corrTime);
622 fHTiming->Fill(4,rePhiTime);
623 fHTiming->Fill(5,copyTime);
624 fHTiming->Fill(6,poissonTime);
625 fHTiming->Fill(7,diagTime);
626 fHTiming->Fill(8,totalT.CpuTime());
632 //_____________________________________________________________________
634 AliFMDDensityCalculator::CheckOutlier(Double_t eloss,
638 if (eloss < 1e-6) return true;
639 Double_t diff = TMath::Abs(poisson - eloss) / eloss;
642 //_____________________________________________________________________
644 AliFMDDensityCalculator::FindMaxWeight(const AliFMDCorrELossFit* cor,
645 UShort_t d, Char_t r, Int_t iEta) const
648 // Find the max weight to use for FMD<i>dr</i> in eta bin @a iEta
656 DGUARD(fDebug, 10, "Find maximum weight in FMD density calculator");
659 AliFMDCorrELossFit::ELossFit* fit = cor->FindFit(d,r,iEta, -1);
661 // AliWarning(Form("No energy loss fit for FMD%d%c at eta=%f", d, r, eta));
664 return fit->FindMaxWeight(2*AliFMDCorrELossFit::ELossFit::fgMaxRelError,
665 AliFMDCorrELossFit::ELossFit::fgLeastWeight,
668 //_____________________________________________________________________
670 AliFMDDensityCalculator::FindMaxWeight(const AliFMDCorrELossFit* cor,
671 UShort_t d, Char_t r, Double_t eta) const
674 // Find the max weight to use for FMD<i>dr</i> in eta bin @a iEta
682 DGUARD(fDebug, 10, "Find maximum weight in FMD density calculator");
685 AliFMDCorrELossFit::ELossFit* fit = cor->FindFit(d,r,eta, -1);
687 // AliWarning(Form("No energy loss fit for FMD%d%c at eta=%f", d, r, eta));
690 return fit->FindMaxWeight(2*AliFMDCorrELossFit::ELossFit::fgMaxRelError,
691 AliFMDCorrELossFit::ELossFit::fgLeastWeight,
695 //_____________________________________________________________________
697 AliFMDDensityCalculator::CacheMaxWeights(const TAxis& axis)
700 // Find the max weights and cache them
702 DGUARD(fDebug, 2, "Cache maximum weights in FMD density calculator");
703 AliForwardCorrectionManager& fcm = AliForwardCorrectionManager::Instance();
704 const AliFMDCorrELossFit* cor = fcm.GetELossFit();
705 cor->CacheBins(fMinQuality);
706 cor->Print(fDebug > 5 ? "RCS" : "C");
708 TAxis eta(axis.GetNbins(),
712 eta.Set(cor->GetEtaAxis().GetNbins(),
713 cor->GetEtaAxis().GetXmin(),
714 cor->GetEtaAxis().GetXmax());
716 Int_t nEta = eta.GetNbins();
723 fMaxWeights->SetBins(nEta, eta.GetXmin(), eta.GetXmax(), 5, .5, 5.5);
724 fMaxWeights->GetYaxis()->SetBinLabel(1, "FMD1i");
725 fMaxWeights->GetYaxis()->SetBinLabel(2, "FMD2i");
726 fMaxWeights->GetYaxis()->SetBinLabel(3, "FMD2o");
727 fMaxWeights->GetYaxis()->SetBinLabel(4, "FMD3i");
728 fMaxWeights->GetYaxis()->SetBinLabel(5, "FMD3o");
730 AliInfo(Form("Get eta axis with %d bins from %f to %f",
731 nEta, eta.GetXmin(), eta.GetXmax()));
732 fLowCuts->SetBins(nEta, eta.GetXmin(), eta.GetXmax(), 5, .5, 5.5);
733 fLowCuts->GetYaxis()->SetBinLabel(1, "FMD1i");
734 fLowCuts->GetYaxis()->SetBinLabel(2, "FMD2i");
735 fLowCuts->GetYaxis()->SetBinLabel(3, "FMD2o");
736 fLowCuts->GetYaxis()->SetBinLabel(4, "FMD3i");
737 fLowCuts->GetYaxis()->SetBinLabel(5, "FMD3o");
739 for (Int_t i = 0; i < nEta; i++) {
740 Double_t leta = fMaxWeights->GetXaxis()->GetBinCenter(i+1);
742 w[0] = fFMD1iMax[i] = FindMaxWeight(cor, 1, 'I', leta);
743 w[1] = fFMD2iMax[i] = FindMaxWeight(cor, 2, 'I', leta);
744 w[2] = fFMD2oMax[i] = FindMaxWeight(cor, 2, 'O', leta);
745 w[3] = fFMD3iMax[i] = FindMaxWeight(cor, 3, 'I', leta);
746 w[4] = fFMD3oMax[i] = FindMaxWeight(cor, 3, 'O', leta);
747 for (Int_t j = 0; j < 5; j++)
748 if (w[j] > 0) fMaxWeights->SetBinContent(i+1, j+1, w[j]);
751 // Cache cuts in histogram
752 fCuts.FillHistogram(fLowCuts);
755 //_____________________________________________________________________
757 AliFMDDensityCalculator::GetMaxWeight(UShort_t d, Char_t r, Int_t iEta) const
760 // Find the (cached) maximum weight for FMD<i>dr</i> in
761 // @f$\eta@f$ bin @a iEta
769 // max weight or <= 0 in case of problems
771 if (iEta < 0) return -1;
773 const TArrayI* max = 0;
775 case 1: max = &fFMD1iMax; break;
776 case 2: max = (r == 'I' || r == 'i' ? &fFMD2iMax : &fFMD2oMax); break;
777 case 3: max = (r == 'I' || r == 'i' ? &fFMD3iMax : &fFMD3oMax); break;
780 AliWarning(Form("No array for FMD%d%c", d, r));
784 if (iEta >= max->fN) {
785 AliWarning(Form("Eta bin %3d out of bounds [0,%d]",
790 AliDebug(30,Form("Max weight for FMD%d%c eta bin %3d: %d", d, r, iEta,
792 return max->At(iEta);
795 //_____________________________________________________________________
797 AliFMDDensityCalculator::GetMaxWeight(UShort_t d, Char_t r, Float_t eta) const
800 // Find the (cached) maximum weight for FMD<i>dr</i> iat
809 // max weight or <= 0 in case of problems
811 AliForwardCorrectionManager& fcm = AliForwardCorrectionManager::Instance();
812 Int_t iEta = fcm.GetELossFit()->FindEtaBin(eta) -1;
814 return GetMaxWeight(d, r, iEta);
817 //_____________________________________________________________________
819 AliFMDDensityCalculator::NParticles(Float_t mult,
823 Bool_t lowFlux) const
826 // Get the number of particles corresponding to the signal mult
833 // t Strip (not used)
835 // eta Pseudo-rapidity
836 // lowFlux Low-flux flag
839 // The number of particles
841 // if (mult <= GetMultCut()) return 0;
842 DGUARD(fDebug, 3, "Calculate Nch in FMD density calculator");
843 if (lowFlux) return 1;
845 AliForwardCorrectionManager& fcm = AliForwardCorrectionManager::Instance();
846 AliFMDCorrELossFit::ELossFit* fit = fcm.GetELossFit()->FindFit(d,r,eta, -1);
848 AliWarning(Form("No energy loss fit for FMD%d%c at eta=%f qual=%d",
849 d, r, eta, fMinQuality));
853 Int_t m = GetMaxWeight(d,r,eta); // fit->FindMaxWeight();
855 AliWarning(Form("No good fits for FMD%d%c at eta=%f", d, r, eta));
859 UShort_t n = TMath::Min(fMaxParticles, UShort_t(m));
860 Double_t ret = fit->EvaluateWeighted(mult, n);
863 AliInfo(Form("FMD%d%c, eta=%7.4f, %8.5f -> %8.5f", d, r, eta, mult, ret));
866 fWeightedSum->Fill(ret);
867 fSumOfWeights->Fill(ret);
872 //_____________________________________________________________________
874 AliFMDDensityCalculator::Correction(UShort_t d,
878 Bool_t lowFlux) const
881 // Get the inverse correction factor. This consist of
883 // - acceptance correction (corners of sensors)
884 // - double hit correction (for low-flux events)
885 // - dead strip correction
891 // t Strip (not used)
893 // eta Pseudo-rapidity
894 // lowFlux Low-flux flag
899 DGUARD(fDebug, 10, "Apply correction in FMD density calculator");
900 Float_t correction = 1;
901 if (fUsePhiAcceptance == kPhiCorrectNch)
902 correction = AcceptanceCorrection(r,t);
904 AliForwardCorrectionManager& fcm = AliForwardCorrectionManager::Instance();
907 if (fcm.GetDoubleHit())
908 dblHitCor = fcm.GetDoubleHit()->GetCorrection(d,r);
911 Double_t dblC = dblHitCor->GetBinContent(dblHitCor->FindBin(eta));
912 if (dblC > 0) correction *= dblC;
915 // AliWarning(Form("Missing double hit correction for FMD%d%c",d,r));
921 //_____________________________________________________________________
923 AliFMDDensityCalculator::GenerateAcceptanceCorrection(Char_t r) const
926 // Generate the acceptance corrections
929 // r Ring to generate for
932 // Newly allocated histogram of acceptance corrections
934 DGUARD(fDebug, 3, "Make acceptance correction in FMD density calculator");
935 const Double_t ic1[] = { 4.9895, 15.3560 };
936 const Double_t ic2[] = { 1.8007, 17.2000 };
937 const Double_t oc1[] = { 4.2231, 26.6638 };
938 const Double_t oc2[] = { 1.8357, 27.9500 };
939 const Double_t* c1 = (r == 'I' || r == 'i' ? ic1 : oc1);
940 const Double_t* c2 = (r == 'I' || r == 'i' ? ic2 : oc2);
941 Double_t minR = (r == 'I' || r == 'i' ? 4.5213 : 15.4);
942 Double_t maxR = (r == 'I' || r == 'i' ? 17.2 : 28.0);
943 Int_t nStrips = (r == 'I' || r == 'i' ? 512 : 256);
944 Int_t nSec = (r == 'I' || r == 'i' ? 20 : 40);
945 Float_t basearc = 2 * TMath::Pi() / nSec;
946 Double_t rad = maxR - minR;
947 Float_t segment = rad / nStrips;
948 Float_t cr = TMath::Sqrt(c1[0]*c1[0]+c1[1]*c1[1]);
950 // Numbers used to find end-point of strip.
951 // (See http://mathworld.wolfram.com/Circle-LineIntersection.html)
952 Float_t D = c1[0] * c2[1] - c1[1] * c2[0];
953 Float_t dx = c2[0] - c1[0];
954 Float_t dy = c2[1] - c1[1];
955 Float_t dr = TMath::Sqrt(dx*dx+dy*dy);
957 TH1D* ret = new TH1D(Form("acc%c", r),
958 Form("Acceptance correction for FMDx%c", r),
959 nStrips, -.5, nStrips-.5);
960 ret->SetXTitle("Strip");
961 ret->SetYTitle("#varphi acceptance");
962 ret->SetDirectory(0);
963 ret->SetFillColor(r == 'I' || r == 'i' ? kRed+1 : kBlue+1);
964 ret->SetFillStyle(3001);
966 for (Int_t t = 0; t < nStrips; t++) {
967 Float_t radius = minR + t * segment;
969 // If the radius of the strip is smaller than the radius corresponding
970 // to the first corner we have a full strip length
972 ret->SetBinContent(t+1, 1);
976 // Next, we should find the end-point of the strip - that is,
977 // the coordinates where the line from c1 to c2 intersects a circle
978 // with radius given by the strip.
979 // (See http://mathworld.wolfram.com/Circle-LineIntersection.html)
980 // Calculate the determinant
981 Float_t det = radius * radius * dr * dr - D*D;
984 // <0 means No intersection
985 // =0 means Exactly tangent
986 ret->SetBinContent(t+1, 1);
990 // Calculate end-point and the corresponding opening angle
991 Float_t x = (+D * dy + dx * TMath::Sqrt(det)) / dr / dr;
992 Float_t y = (-D * dx + dy * TMath::Sqrt(det)) / dr / dr;
993 Float_t th = TMath::ATan2(x, y);
995 ret->SetBinContent(t+1, th / basearc);
1000 //_____________________________________________________________________
1002 AliFMDDensityCalculator::AcceptanceCorrection(Char_t r, UShort_t t) const
1005 // Get the acceptance correction for strip @a t in an ring of type @a r
1008 // r Ring type ('I' or 'O')
1012 // Inverse acceptance correction
1014 TH1D* acc = (r == 'I' || r == 'i' ? fAccI : fAccO);
1015 return acc->GetBinContent(t+1);
1018 //____________________________________________________________________
1020 AliFMDDensityCalculator::Terminate(const TList* dir, TList* output,
1024 // Scale the histograms to the total number of events
1027 // dir where to put the output
1028 // nEvents Number of events
1030 DGUARD(fDebug, 1, "Scale histograms in FMD density calculator");
1031 if (nEvents <= 0) return;
1032 TList* d = static_cast<TList*>(dir->FindObject(GetName()));
1035 TList* out = new TList;
1036 out->SetName(d->GetName());
1039 TIter next(&fRingHistos);
1041 THStack* sums = new THStack("sums", "sums of ring signals");
1042 while ((o = static_cast<RingHistos*>(next()))) {
1043 o->Terminate(d, nEvents);
1045 Warning("Terminate", "No density in %s", o->GetName());
1048 TH1D* sum = o->fDensity->ProjectionX(o->GetName(), 1,
1049 o->fDensity->GetNbinsY(),"e");
1050 sum->Scale(1., "width");
1051 sum->SetTitle(o->GetName());
1052 sum->SetDirectory(0);
1053 sum->SetYTitle("#sum N_{ch,incl}");
1060 //____________________________________________________________________
1062 AliFMDDensityCalculator::CreateOutputObjects(TList* dir)
1065 // Output diagnostic histograms to directory
1068 // dir List to write in
1070 DGUARD(fDebug, 1, "Define output FMD density calculator");
1071 TList* d = new TList;
1073 d->SetName(GetName());
1075 d->Add(fWeightedSum);
1076 d->Add(fSumOfWeights);
1077 d->Add(fCorrections);
1080 d->Add(fMaxWeights);
1083 TParameter<int>* nFiles = new TParameter<int>("nFiles", 1);
1084 nFiles->SetMergeMode('+');
1087 d->Add(AliForwardUtil::MakeParameter("maxParticle", fMaxParticles));
1088 d->Add(AliForwardUtil::MakeParameter("minQuality", fMinQuality));
1089 d->Add(AliForwardUtil::MakeParameter("method", fUsePoisson));
1090 d->Add(AliForwardUtil::MakeParameter("phiAcceptance",fUsePhiAcceptance));
1091 d->Add(AliForwardUtil::MakeParameter("etaLumping", fEtaLumping));
1092 d->Add(AliForwardUtil::MakeParameter("phiLumping", fPhiLumping));
1093 d->Add(AliForwardUtil::MakeParameter("recalcPhi", fRecalculatePhi));
1094 d->Add(AliForwardUtil::MakeParameter("maxOutliers", fMaxOutliers));
1095 d->Add(AliForwardUtil::MakeParameter("outlierCut", fOutlierCut));
1098 fCuts.Output(d,"lCuts");
1100 TIter next(&fRingHistos);
1102 while ((o = static_cast<RingHistos*>(next()))) {
1103 o->fPoisson.SetLumping(fEtaLumping, fPhiLumping);
1104 o->CreateOutputObjects(d);
1107 if (!fDoTiming) return;
1109 fHTiming = new TProfile("timing", "#LTt_{part}#GT", 8, .5, 8.5);
1110 fHTiming->SetDirectory(0);
1111 fHTiming->SetYTitle("#LTt_{part}#GT");
1112 fHTiming->SetXTitle("Part");
1113 fHTiming->SetFillColor(kRed+1);
1114 fHTiming->SetFillStyle(3001);
1115 fHTiming->SetMarkerStyle(20);
1116 fHTiming->SetMarkerColor(kBlack);
1117 fHTiming->SetLineColor(kBlack);
1118 fHTiming->SetStats(0);
1119 TAxis* xaxis = fHTiming->GetXaxis();
1120 xaxis->SetBinLabel(1, "Re-calculation of #eta");
1121 xaxis->SetBinLabel(2, "N_{particle}");
1122 xaxis->SetBinLabel(3, "Correction");
1123 xaxis->SetBinLabel(4, "Re-calculation of #phi");
1124 xaxis->SetBinLabel(5, "Copy to cache");
1125 xaxis->SetBinLabel(6, "Poisson calculation");
1126 xaxis->SetBinLabel(7, "Diagnostics");
1127 xaxis->SetBinLabel(8, "Total");
1130 #define PF(N,V,...) \
1131 AliForwardUtil::PrintField(N,V, ## __VA_ARGS__)
1132 #define PFB(N,FLAG) \
1134 AliForwardUtil::PrintName(N); \
1135 std::cout << std::boolalpha << (FLAG) << std::noboolalpha << std::endl; \
1137 #define PFV(N,VALUE) \
1139 AliForwardUtil::PrintName(N); \
1140 std::cout << (VALUE) << std::endl; } while(false)
1142 //____________________________________________________________________
1144 AliFMDDensityCalculator::Print(Option_t* option) const
1147 // Print information
1152 AliForwardUtil::PrintTask(*this);
1153 gROOT->IncreaseDirLevel();
1155 TString phiM("none");
1156 switch (fUsePhiAcceptance) {
1157 case kPhiNoCorrect: phiM = "none"; break;
1158 case kPhiCorrectNch: phiM = "correct Nch"; break;
1159 case kPhiCorrectELoss: phiM = "correct energy loss"; break;
1162 PFV("Max(particles)", fMaxParticles );
1163 PFV("Min(quality)", fMinQuality );
1164 PFB("Poisson method", fUsePoisson );
1165 PFV("Eta lumping", fEtaLumping );
1166 PFV("Phi lumping", fPhiLumping );
1167 PFB("Recalculate phi", fRecalculatePhi );
1168 PFB("Use phi acceptance", phiM);
1169 PFV("Lower cut", "");
1172 TString opt(option);
1174 if (!opt.Contains("nomax")) {
1175 PFV("Max weights", "");
1178 for (Int_t i = 0; i < gROOT->GetDirLevel(); i++) ind[i] = ' ';
1179 ind[gROOT->GetDirLevel()] = '\0';
1180 for (UShort_t d=1; d<=3; d++) {
1181 UShort_t nr = (d == 1 ? 1 : 2);
1182 for (UShort_t q=0; q<nr; q++) {
1183 ind[gROOT->GetDirLevel()] = ' ';
1184 ind[gROOT->GetDirLevel()+1] = '\0';
1185 Char_t r = (q == 0 ? 'I' : 'O');
1186 std::cout << ind << " FMD" << d << r << ":";
1187 ind[gROOT->GetDirLevel()+1] = ' ';
1188 ind[gROOT->GetDirLevel()+2] = '\0';
1190 const TArrayI& a = (d == 1 ? fFMD1iMax :
1191 (d == 2 ? (r == 'I' ? fFMD2iMax : fFMD2oMax) :
1192 (r == 'I' ? fFMD3iMax : fFMD3oMax)));
1194 for (Int_t i = 0; i < a.fN; i++) {
1195 if (a.fArray[i] < 1) continue;
1196 if (j % 6 == 0) std::cout << "\n " << ind;
1198 std::cout << " " << std::setw(3) << i << ": " << a.fArray[i];
1200 std::cout << std::endl;
1204 gROOT->DecreaseDirLevel();
1207 //====================================================================
1208 AliFMDDensityCalculator::RingHistos::RingHistos()
1209 : AliForwardUtil::RingHistos(),
1218 fDiffELossPoisson(0),
1219 fELossVsPoissonOut(0),
1220 fDiffELossPoissonOut(0),
1237 //____________________________________________________________________
1238 AliFMDDensityCalculator::RingHistos::RingHistos(UShort_t d, Char_t r)
1239 : AliForwardUtil::RingHistos(d,r),
1248 fDiffELossPoisson(0),
1249 fELossVsPoissonOut(0),
1250 fDiffELossPoissonOut(0),
1252 fPoisson("ignored"),
1270 fEvsN = new TH2D("elossVsNnocorr",
1271 "#Delta E/#Delta E_{mip} vs uncorrected inclusive N_{ch}",
1272 250, -.5, 24.5, 251, -1.5, 24.5);
1273 fEvsN->SetXTitle("#Delta E/#Delta E_{mip}");
1274 fEvsN->SetYTitle("Inclusive N_{ch} (uncorrected)");
1276 fEvsN->SetDirectory(0);
1278 fEvsM = static_cast<TH2D*>(fEvsN->Clone("elossVsNcorr"));
1279 fEvsM->SetTitle("#Delta E/#Delta E_{mip} vs corrected inclusive N_{ch}");
1280 fEvsM->SetDirectory(0);
1282 fEtaVsN = new TProfile("etaVsNnocorr",
1283 "Average inclusive N_{ch} vs #eta (uncorrected)",
1285 fEtaVsN->SetXTitle("#eta");
1286 fEtaVsN->SetYTitle("#LT N_{ch,incl}#GT (uncorrected)");
1287 fEtaVsN->SetDirectory(0);
1288 fEtaVsN->SetLineColor(Color());
1289 fEtaVsN->SetFillColor(Color());
1291 fEtaVsM = static_cast<TProfile*>(fEtaVsN->Clone("etaVsNcorr"));
1292 fEtaVsM->SetTitle("Average inclusive N_{ch} vs #eta (corrected)");
1293 fEtaVsM->SetYTitle("#LT N_{ch,incl}#GT (corrected)");
1294 fEtaVsM->SetDirectory(0);
1297 fCorr = new TProfile("corr", "Average correction", 200, -4, 6);
1298 fCorr->SetXTitle("#eta");
1299 fCorr->SetYTitle("#LT correction#GT");
1300 fCorr->SetDirectory(0);
1301 fCorr->SetLineColor(Color());
1302 fCorr->SetFillColor(Color());
1304 fDensity = new TH2D("inclDensity", "Inclusive N_{ch} density",
1305 200, -4, 6, (r == 'I' || r == 'i' ? 20 : 40),
1307 fDensity->SetDirectory(0);
1308 fDensity->Sumw2(); fDensity->SetMarkerColor(Color());
1309 fDensity->SetXTitle("#eta");
1310 fDensity->SetYTitle("#phi [radians]");
1311 fDensity->SetZTitle("Inclusive N_{ch} density");
1313 // --- Create increasing sized bins --------------------------------
1315 // bins, lowest order, higest order, return array
1316 const char* nchP = "N_{ch}^{Poisson}";
1317 const char* nchE = "N_{ch}^{#Delta}";
1318 AliForwardUtil::MakeLogScale(300, 0, 2, bins);
1319 fELossVsPoisson = new TH2D("elossVsPoisson",
1320 "N_{ch} from energy loss vs from Poisson",
1321 bins.GetSize()-1, bins.GetArray(),
1322 bins.GetSize()-1, bins.GetArray());
1323 fELossVsPoisson->SetDirectory(0);
1324 fELossVsPoisson->SetXTitle(nchE);
1325 fELossVsPoisson->SetYTitle(nchP);
1326 fELossVsPoisson->SetZTitle("Correlation");
1327 fELossVsPoissonOut =
1328 static_cast<TH2D*>(fELossVsPoisson
1329 ->Clone(Form("%sOutlier",
1330 fELossVsPoisson->GetName())));
1331 fELossVsPoissonOut->SetDirectory(0);
1332 fELossVsPoissonOut->SetMarkerStyle(20);
1333 fELossVsPoissonOut->SetMarkerSize(0.3);
1334 fELossVsPoissonOut->SetMarkerColor(kBlack);
1335 fELossVsPoissonOut->SetTitle(Form("%s for outliers",
1336 fELossVsPoisson->GetTitle()));
1338 fDiffELossPoisson = new TH1D("diffElossPoisson",
1339 Form("(%s-%s)/%s", nchP, nchE, nchE),
1341 fDiffELossPoisson->SetDirectory(0);
1342 fDiffELossPoisson->SetXTitle(fDiffELossPoisson->GetTitle());
1343 fDiffELossPoisson->SetYTitle("Frequency");
1344 fDiffELossPoisson->SetMarkerColor(Color());
1345 fDiffELossPoisson->SetFillColor(Color());
1346 fDiffELossPoisson->SetFillStyle(3001);
1347 fDiffELossPoisson->Sumw2();
1349 fDiffELossPoissonOut =
1350 static_cast<TH1D*>(fDiffELossPoisson
1351 ->Clone(Form("%sOutlier",fDiffELossPoisson->GetName())));
1352 fDiffELossPoissonOut->SetDirectory(0);
1353 fDiffELossPoissonOut->SetTitle(Form("%s for outliers",
1354 fDiffELossPoisson->GetTitle()));
1355 fDiffELossPoissonOut->SetMarkerColor(Color()-2);
1356 fDiffELossPoissonOut->SetFillColor(Color()-2);
1357 fDiffELossPoissonOut->SetFillStyle(3002);
1359 fOutliers = new TH1D("outliers", "Fraction of outliers", 100, 0, 1);
1360 fOutliers->SetDirectory(0);
1361 fOutliers->SetXTitle("N_{outlier}/(N_{outlier}+N_{inside})");
1362 fOutliers->SetYTitle("#sum_{events}#sum_{bins}");
1363 fOutliers->SetFillColor(Color());
1364 fOutliers->SetFillStyle(3001);
1365 fOutliers->SetLineColor(kBlack);
1367 fELoss = new TH1D("eloss", "#Delta/#Delta_{mip} in all strips",
1369 fELoss->SetXTitle("#Delta/#Delta_{mip} (selected)");
1370 fELoss->SetYTitle("P(#Delta/#Delta_{mip})");
1371 fELoss->SetFillColor(Color()-2);
1372 fELoss->SetFillStyle(3003);
1373 fELoss->SetLineColor(kBlack);
1374 fELoss->SetLineStyle(2);
1375 fELoss->SetLineWidth(1);
1376 fELoss->SetDirectory(0);
1378 fELossUsed = static_cast<TH1D*>(fELoss->Clone("elossUsed"));
1379 fELossUsed->SetTitle("#Delta/#Delta_{mip} in used strips");
1380 fELossUsed->SetFillStyle(3002);
1381 fELossUsed->SetLineStyle(1);
1382 fELossUsed->SetDirectory(0);
1384 fPhiBefore = new TH1D("phiBefore", "#phi distribution (before recalc)",
1385 (r == 'I' || r == 'i' ? 20 : 40), 0, 2*TMath::Pi());
1386 fPhiBefore->SetDirectory(0);
1387 fPhiBefore->SetXTitle("#phi");
1388 fPhiBefore->SetYTitle("Events");
1389 fPhiBefore->SetMarkerColor(Color());
1390 fPhiBefore->SetLineColor(Color());
1391 fPhiBefore->SetFillColor(Color());
1392 fPhiBefore->SetFillStyle(3001);
1393 fPhiBefore->SetMarkerStyle(20);
1395 fPhiAfter = static_cast<TH1D*>(fPhiBefore->Clone("phiAfter"));
1396 fPhiAfter->SetTitle("#phi distribution (after re-calc)");
1397 fPhiAfter->SetDirectory(0);
1400 //____________________________________________________________________
1401 AliFMDDensityCalculator::RingHistos::RingHistos(const RingHistos& o)
1402 : AliForwardUtil::RingHistos(o),
1406 // fEtaVsN(o.fEtaVsN),
1407 // fEtaVsM(o.fEtaVsM),
1409 fDensity(o.fDensity),
1410 fELossVsPoisson(o.fELossVsPoisson),
1411 fDiffELossPoisson(o.fDiffELossPoisson),
1412 fELossVsPoissonOut(o.fELossVsPoissonOut),
1413 fDiffELossPoissonOut(o.fDiffELossPoissonOut),
1414 fOutliers(o.fOutliers),
1415 fPoisson(o.fPoisson),
1417 fELossUsed(o.fELossUsed),
1418 fMultCut(o.fMultCut),
1422 fPhiBefore(o.fPhiBefore),
1423 fPhiAfter(o.fPhiAfter)
1429 // o Object to copy from
1433 //____________________________________________________________________
1434 AliFMDDensityCalculator::RingHistos&
1435 AliFMDDensityCalculator::RingHistos::operator=(const RingHistos& o)
1438 // Assignment operator
1441 // o Object to assign from
1444 // Reference to this
1446 if (&o == this) return *this;
1447 AliForwardUtil::RingHistos::operator=(o);
1449 // if (fEvsN) delete fEvsN;
1450 // if (fEvsM) delete fEvsM;
1451 // if (fEtaVsN) delete fEtaVsN;
1452 // if (fEtaVsM) delete fEtaVsM;
1453 if (fCorr) delete fCorr;
1454 if (fDensity) delete fDensity;
1455 if (fELossVsPoisson) delete fELossVsPoisson;
1456 if (fDiffELossPoisson) delete fDiffELossPoisson;
1457 if (fTotal) delete fTotal;
1458 if (fGood) delete fGood;
1459 if (fPhiAcc) delete fPhiAcc;
1460 if (fPhiBefore) delete fPhiBefore;
1461 if (fPhiAfter) delete fPhiAfter;
1463 // fEvsN = static_cast<TH2D*>(o.fEvsN->Clone());
1464 // fEvsM = static_cast<TH2D*>(o.fEvsM->Clone());
1465 // fEtaVsN = static_cast<TProfile*>(o.fEtaVsN->Clone());
1466 // fEtaVsM = static_cast<TProfile*>(o.fEtaVsM->Clone());
1467 fCorr = static_cast<TProfile*>(o.fCorr->Clone());
1468 fDensity = static_cast<TH2D*>(o.fDensity->Clone());
1469 fELossVsPoisson = static_cast<TH2D*>(o.fELossVsPoisson->Clone());
1470 fDiffELossPoisson = static_cast<TH1D*>(o.fDiffELossPoisson->Clone());
1471 fELossVsPoissonOut = static_cast<TH2D*>(o.fELossVsPoisson->Clone());
1472 fDiffELossPoissonOut = static_cast<TH1D*>(o.fDiffELossPoisson->Clone());
1473 fOutliers = static_cast<TH1D*>(o.fOutliers->Clone());
1474 fPoisson = o.fPoisson;
1475 fELoss = static_cast<TH1D*>(o.fELoss->Clone());
1476 fELossUsed = static_cast<TH1D*>(o.fELossUsed->Clone());
1477 fTotal = static_cast<TH1D*>(o.fTotal->Clone());
1478 fGood = static_cast<TH1D*>(o.fGood->Clone());
1479 fPhiAcc = static_cast<TH2D*>(o.fPhiAcc->Clone());
1480 fPhiBefore = static_cast<TH1D*>(o.fPhiBefore->Clone());
1481 fPhiAfter = static_cast<TH1D*>(o.fPhiAfter->Clone());
1484 //____________________________________________________________________
1485 AliFMDDensityCalculator::RingHistos::~RingHistos()
1493 //____________________________________________________________________
1495 AliFMDDensityCalculator::RingHistos::SetupForData(const TAxis& eAxis)
1498 // This is called on first event
1499 fPoisson.Init(-1,-1);
1500 fTotal = new TH1D("total", "Total # of strips per #eta",
1501 eAxis.GetNbins(), eAxis.GetXmin(), eAxis.GetXmax());
1502 fTotal->SetDirectory(0);
1503 fTotal->SetXTitle("#eta");
1504 fTotal->SetYTitle("# of strips");
1505 fGood = static_cast<TH1D*>(fTotal->Clone("good"));
1506 fGood->SetTitle("# of good strips per #eta");
1507 fGood->SetDirectory(0);
1509 fPhiAcc = new TH2D("phiAcc", "#phi acceptance vs Ip_{z}",
1510 eAxis.GetNbins(), eAxis.GetXmin(), eAxis.GetXmax(),
1512 fPhiAcc->SetXTitle("#eta");
1513 fPhiAcc->SetYTitle("v_{z} [cm]");
1514 fPhiAcc->SetZTitle("#phi acceptance");
1515 fPhiAcc->SetDirectory(0);
1517 if (fList) fList->Add(fPhiAcc);
1520 //____________________________________________________________________
1522 AliFMDDensityCalculator::RingHistos::CreateOutputObjects(TList* dir)
1525 // Make output. This is called as part of SlaveBegin
1528 // dir Where to put it
1530 TList* d = DefineOutputList(dir);
1537 d->Add(fELossVsPoisson);
1538 d->Add(fELossVsPoissonOut);
1539 d->Add(fDiffELossPoisson);
1540 d->Add(fDiffELossPoissonOut);
1543 fPoisson.GetOccupancy()->SetFillColor(Color());
1544 fPoisson.GetMean()->SetFillColor(Color());
1545 fPoisson.GetOccupancy()->SetFillColor(Color());
1551 TAxis x(NStrip(), -.5, NStrip()-.5);
1552 TAxis y(NSector(), -.5, NSector()-.5);
1553 x.SetTitle("strip");
1554 y.SetTitle("sector");
1555 fPoisson.Define(x, y);
1557 d->Add(AliForwardUtil::MakeParameter("cut", fMultCut));
1561 //____________________________________________________________________
1563 AliFMDDensityCalculator::RingHistos::Terminate(TList* dir, Int_t nEvents)
1566 // Scale the histograms to the total number of events
1569 // dir Where the output is
1570 // nEvents Number of events
1572 TList* l = GetOutputList(dir);
1575 TH2D* density = static_cast<TH2D*>(GetOutputHist(l,"inclDensity"));
1576 if (density) density->Scale(1./nEvents);
1580 //____________________________________________________________________