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"
18 #include <TStopwatch.h>
19 #include <TParameter.h>
24 ClassImp(AliFMDDensityCalculator)
29 //____________________________________________________________________
30 const char* AliFMDDensityCalculator::fgkFolderName = "fmdDensityCalculator";
32 //____________________________________________________________________
33 AliFMDDensityCalculator::AliFMDDensityCalculator()
41 fUsePhiAcceptance(kPhiCorrectNch),
55 fRecalculateEta(false),
56 fRecalculatePhi(false),
65 DGUARD(fDebug, 3, "Default CTOR of FMD density calculator");
68 //____________________________________________________________________
69 AliFMDDensityCalculator::AliFMDDensityCalculator(const char* title)
70 : TNamed(fgkFolderName, title),
77 fUsePhiAcceptance(kPhiCorrectNch),
91 fRecalculateEta(false),
92 fRecalculatePhi(false),
102 // name Name of object
104 DGUARD(fDebug, 3, "Named CTOR of FMD density calculator: %s", title);
105 fRingHistos.SetName(GetName());
106 fRingHistos.SetOwner();
107 fRingHistos.Add(new RingHistos(1, 'I'));
108 fRingHistos.Add(new RingHistos(2, 'I'));
109 fRingHistos.Add(new RingHistos(2, 'O'));
110 fRingHistos.Add(new RingHistos(3, 'I'));
111 fRingHistos.Add(new RingHistos(3, 'O'));
112 fSumOfWeights = new TH1D("sumOfWeights", "Sum of Landau weights",
114 fSumOfWeights->SetFillColor(kRed+1);
115 fSumOfWeights->SetXTitle("#sum_{i} a_{i} f_{i}(#Delta)");
116 fWeightedSum = new TH1D("weightedSum", "Weighted sum of Landau propability",
118 fWeightedSum->SetFillColor(kBlue+1);
119 fWeightedSum->SetXTitle("#sum_{i} i a_{i} f_{i}(#Delta)");
120 fCorrections = new TH1D("corrections", "Distribution of corrections",
122 fCorrections->SetFillColor(kBlue+1);
123 fCorrections->SetXTitle("correction");
125 fAccI = GenerateAcceptanceCorrection('I');
126 fAccO = GenerateAcceptanceCorrection('O');
128 fMaxWeights = new TH2D("maxWeights", "Maximum i of a_{i}'s to use",
130 fMaxWeights->SetXTitle("#eta");
131 fMaxWeights->SetDirectory(0);
133 fLowCuts = new TH2D("lowCuts", "Low cuts used", 1, 0, 1, 1, 0, 1);
134 fLowCuts->SetXTitle("#eta");
135 fLowCuts->SetDirectory(0);
139 //____________________________________________________________________
140 AliFMDDensityCalculator::AliFMDDensityCalculator(const
141 AliFMDDensityCalculator& o)
144 fSumOfWeights(o.fSumOfWeights),
145 fWeightedSum(o.fWeightedSum),
146 fCorrections(o.fCorrections),
147 fMaxParticles(o.fMaxParticles),
148 fUsePoisson(o.fUsePoisson),
149 fUsePhiAcceptance(o.fUsePhiAcceptance),
152 fFMD1iMax(o.fFMD1iMax),
153 fFMD2iMax(o.fFMD2iMax),
154 fFMD2oMax(o.fFMD2oMax),
155 fFMD3iMax(o.fFMD3iMax),
156 fFMD3oMax(o.fFMD3oMax),
157 fMaxWeights(o.fMaxWeights),
158 fLowCuts(o.fLowCuts),
159 fEtaLumping(o.fEtaLumping),
160 fPhiLumping(o.fPhiLumping),
163 fRecalculateEta(o.fRecalculateEta),
164 fRecalculatePhi(o.fRecalculatePhi),
165 fMinQuality(o.fMinQuality),
167 fDoTiming(o.fDoTiming),
174 // o Object to copy from
176 DGUARD(fDebug, 3, "Copy CTOR of FMD density calculator");
177 TIter next(&o.fRingHistos);
179 while ((obj = next())) fRingHistos.Add(obj);
182 //____________________________________________________________________
183 AliFMDDensityCalculator::~AliFMDDensityCalculator()
188 DGUARD(fDebug, 3, "DTOR of FMD density calculator");
189 // fRingHistos.Delete();
192 //____________________________________________________________________
193 AliFMDDensityCalculator&
194 AliFMDDensityCalculator::operator=(const AliFMDDensityCalculator& o)
197 // Assignement operator
200 // o Object to assign from
203 // Reference to this object
205 DGUARD(fDebug, 3, "Assignment of FMD density calculator");
206 if (&o == this) return *this;
207 TNamed::operator=(o);
210 fMaxParticles = o.fMaxParticles;
211 fUsePoisson = o.fUsePoisson;
212 fUsePhiAcceptance = o.fUsePhiAcceptance;
215 fFMD1iMax = o.fFMD1iMax;
216 fFMD2iMax = o.fFMD2iMax;
217 fFMD2oMax = o.fFMD2oMax;
218 fFMD3iMax = o.fFMD3iMax;
219 fFMD3oMax = o.fFMD3oMax;
220 fMaxWeights = o.fMaxWeights;
221 fLowCuts = o.fLowCuts;
222 fEtaLumping = o.fEtaLumping;
223 fPhiLumping = o.fPhiLumping;
225 fRecalculateEta = o.fRecalculateEta;
226 fRecalculatePhi = o.fRecalculatePhi;
227 fMinQuality = o.fMinQuality;
229 fDoTiming = o.fDoTiming;
230 fHTiming = o.fHTiming;
232 fRingHistos.Delete();
233 TIter next(&o.fRingHistos);
235 while ((obj = next())) fRingHistos.Add(obj);
240 //____________________________________________________________________
242 AliFMDDensityCalculator::SetupForData(const TAxis& axis)
244 // Intialize this sub-algorithm
248 DGUARD(fDebug, 1, "Initialize FMD density calculator");
249 CacheMaxWeights(axis);
253 TIter next(&fRingHistos);
255 while ((o = static_cast<RingHistos*>(next()))) {
256 o->SetupForData(axis);
257 // o->fMultCut = fCuts.GetFixedCut(o->fDet, o->fRing);
258 // o->fPoisson.Init(o->fDet,o->fRing,fEtaLumping, fPhiLumping);
262 //____________________________________________________________________
263 AliFMDDensityCalculator::RingHistos*
264 AliFMDDensityCalculator::GetRingHistos(UShort_t d, Char_t r) const
267 // Get the ring histogram container
274 // Ring histogram container
278 case 1: idx = 0; break;
279 case 2: idx = 1 + (r == 'I' || r == 'i' ? 0 : 1); break;
280 case 3: idx = 3 + (r == 'I' || r == 'i' ? 0 : 1); break;
282 if (idx < 0 || idx >= fRingHistos.GetEntries()) {
283 AliWarning(Form("Index %d of FMD%d%c out of range", idx, d, r));
287 return static_cast<RingHistos*>(fRingHistos.At(idx));
290 //____________________________________________________________________
292 AliFMDDensityCalculator::GetMultCut(UShort_t d, Char_t r, Int_t ieta,
296 // Get the multiplicity cut. If the user has set fMultCut (via
297 // SetMultCut) then that value is used. If not, then the lower
298 // value of the fit range for the enery loss fits is returned.
301 // Lower cut on multiplicity
303 return fCuts.GetMultCut(d,r,ieta,errors);
306 //____________________________________________________________________
308 AliFMDDensityCalculator::GetMultCut(UShort_t d, Char_t r, Double_t eta,
312 // Get the multiplicity cut. If the user has set fMultCut (via
313 // SetMultCut) then that value is used. If not, then the lower
314 // value of the fit range for the enery loss fits is returned.
317 // Lower cut on multiplicity
319 return fCuts.GetMultCut(d,r,eta,errors);
322 //____________________________________________________________________
324 AliFMDDensityCalculator::Calculate(const AliESDFMD& fmd,
325 AliForwardUtil::Histos& hists,
331 // Do the calculations
334 // fmd AliESDFMD object (possibly) corrected for sharing
335 // hists Histogram cache
337 // lowFlux Low flux flag.
341 DGUARD(fDebug, 1, "Calculate density in FMD density calculator");
346 // First measurements of timing
347 // Re-calculation : fraction of sum 32.0% of total 18.1%
348 // N_{particle} : fraction of sum 15.2% of total 8.6%
349 // Correction : fraction of sum 26.4% of total 14.9%
350 // #phi acceptance : fraction of sum 0.2% of total 0.1%
351 // Copy to cache : fraction of sum 3.9% of total 2.2%
352 // Poisson calculation : fraction of sum 18.7% of total 10.6%
353 // Diagnostics : fraction of sum 3.7% of total 2.1%
354 Double_t reEtaTime = 0;
355 Double_t nPartTime = 0;
356 Double_t corrTime = 0;
357 Double_t rePhiTime = 0;
358 Double_t copyTime = 0;
359 Double_t poissonTime= 0;
360 Double_t diagTime = 0;
361 if (fDoTiming) totalT.Start(true);
363 Double_t etaCache[20*512]; // Same number of strips per ring
364 Double_t phiCache[20*512]; // whether it is inner our outer.
365 // We do not use TArrayD because we do not wont a bounds check
366 // TArrayD etaCache(20*512); // Same number of strips per ring
367 // TArrayD phiCache(20*512); // whether it is inner our outer.
369 // --- Loop over detectors -----------------------------------------
370 for (UShort_t d=1; d<=3; d++) {
371 UShort_t nr = (d == 1 ? 1 : 2);
372 for (UShort_t q=0; q<nr; q++) {
373 Char_t r = (q == 0 ? 'I' : 'O');
374 UShort_t ns= (q == 0 ? 20 : 40);
375 UShort_t nt= (q == 0 ? 512 : 256);
376 TH2D* h = hists.Get(d,r);
377 RingHistos* rh= GetRingHistos(d,r);
379 AliError(Form("No ring histogram found for FMD%d%c", d, r));
383 // rh->fPoisson.SetObject(d,r,vtxbin,cent);
384 rh->fPoisson.Reset(0);
387 // rh->ResetPoissonHistos(h, fEtaLumping, fPhiLumping);
389 // Reset our eta cache
390 // for (Int_t i = 0; i < 20*512; i++)
391 // etaCache[i] = phiCache[i] = AliESDFMD::kInvalidEta;
392 memset(etaCache, 0, sizeof(Double_t)*20*512);
393 memset(phiCache, 0, sizeof(Double_t)*20*512);
394 // etaCache.Reset(AliESDFMD::kInvalidEta);
395 // phiCache.Reset(AliESDFMD::kInvalidEta);
397 // --- Loop over sectors and strips ----------------------------
398 for (UShort_t s=0; s<ns; s++) {
399 for (UShort_t t=0; t<nt; t++) {
401 Float_t mult = fmd.Multiplicity(d,r,s,t);
402 Float_t phi = fmd.Phi(d,r,s,t) * TMath::DegToRad();
403 Float_t eta = fmd.Eta(d,r,s,t);
404 Double_t oldPhi = phi;
406 // --- Re-calculate eta - needed for satelittes ------------
407 if (fDoTiming) timer.Start(true);
408 if (eta == AliESDFMD::kInvalidEta || fRecalculateEta)
409 eta = AliForwardUtil::GetEtaFromStrip(d,r,s,t,ip.Z());
410 if (fDoTiming) reEtaTime += timer.CpuTime();
411 etaCache[s*nt+t] = eta;
413 // --- Check this strip ------------------------------------
414 rh->fTotal->Fill(eta);
415 if (mult == AliESDFMD::kInvalidMult) { // || mult > 20) {
416 // Do not count invalid stuff
417 rh->fELoss->Fill(-1);
418 // rh->fEvsN->Fill(mult,-1);
419 // rh->fEvsM->Fill(mult,-1);
423 AliWarningF("Raw multiplicity of FMD%d%c[%02d,%03d] = %f > 20",
425 // --- Automatic calculation of acceptance -----------------
426 rh->fGood->Fill(eta);
428 // --- If we asked to re-calculate phi for (x,y) IP --------
429 if (fDoTiming) timer.Start(true);
430 if (fRecalculatePhi) {
432 phi = AliForwardUtil::GetPhiFromStrip(r, t, phi, ip.X(), ip.Y());
434 phiCache[s*nt+t] = phi;
435 if (fDoTiming) rePhiTime += timer.CpuTime();
437 // --- Apply phi corner correction to eloss ----------------
438 if (fUsePhiAcceptance == kPhiCorrectELoss)
439 mult *= AcceptanceCorrection(r,t);
441 // --- Get the low multiplicity cut ------------------------
443 if (eta != AliESDFMD::kInvalidEta) cut = GetMultCut(d, r, eta,false);
444 else AliWarningF("Eta for FMD%d%c[%02d,%03d] is invalid: %f",
447 // --- Now caluculate Nch for this strip using fits --------
448 if (fDoTiming) timer.Start(true);
450 if (cut > 0 && mult > cut) n = NParticles(mult,d,r,eta,lowFlux);
451 rh->fELoss->Fill(mult);
452 // rh->fEvsN->Fill(mult,n);
453 // rh->fEtaVsN->Fill(eta, n);
454 if (fDoTiming) nPartTime += timer.CpuTime();
456 // --- Calculate correction if needed ----------------------
457 if (fDoTiming) timer.Start(true);
458 // Temporary stuff - remove Correction call
460 if (fUsePhiAcceptance == kPhiCorrectNch)
461 c = AcceptanceCorrection(r,t);
462 // Double_t c = Correction(d,r,t,eta,lowFlux);
463 if (fDoTiming) corrTime += timer.CpuTime();
464 fCorrections->Fill(c);
466 // rh->fEvsM->Fill(mult,n);
467 // rh->fEtaVsM->Fill(eta, n);
468 rh->fCorr->Fill(eta, c);
470 // --- Accumulate Poisson statistics -----------------------
471 Bool_t hit = (n > 0.9 && c > 0);
473 rh->fELossUsed->Fill(mult);
474 if (fRecalculatePhi) {
475 rh->fPhiBefore->Fill(oldPhi);
476 rh->fPhiAfter->Fill(phi);
479 rh->fPoisson.Fill(t,s,hit,1./c);
482 // --- If we use ELoss fits, apply now ---------------------
483 if (!fUsePoisson) rh->fDensity->Fill(eta,phi,n);
487 // --- Automatic acceptance - Calculate as an efficiency -------
488 // This is very fast, so we do not bother to time it
489 rh->fGood->Divide(rh->fGood, rh->fTotal, 1, 1, "B");
491 // --- Make a copy and reset as needed -------------------------
492 if (fDoTiming) timer.Start(true);
493 TH2D* hclone = fCache.Get(d,r);
495 // TH2D* hclone = static_cast<TH2D*>(h->Clone("hclone"));
496 if (!fUsePoisson) hclone->Reset();
498 for (Int_t i = 0; i <= h->GetNbinsX()+1; i++) {
499 for (Int_t j = 0; j <= h->GetNbinsY()+1; j++) {
500 hclone->SetBinContent(i,j,h->GetBinContent(i,j));
501 hclone->SetBinError(i,j,h->GetBinError(i,j));
507 if (fDoTiming) copyTime += timer.CpuTime();
509 // --- Store Poisson result ------------------------------------
510 if (fDoTiming) timer.Start(true);
511 TH2D* poisson = rh->fPoisson.Result();
512 for (Int_t t=0; t < poisson->GetNbinsX(); t++) {
513 for (Int_t s=0; s < poisson->GetNbinsY(); s++) {
515 Double_t poissonV = poisson->GetBinContent(t+1,s+1);
516 // Use cached eta - since the calls to GetEtaFromStrip and
517 // GetPhiFromStrip are _very_ expensive
518 Double_t phi = phiCache[s*nt+t];
519 Double_t eta = etaCache[s*nt+t];
520 // Double_t phi = fmd.Phi(d,r,s,t) * TMath::DegToRad();
521 // Double_t eta = fmd.Eta(d,r,s,t);
522 // if (fRecalculateEta)
523 // eta = AliForwardUtil::GetEtaFromStrip(d,r,s,t,ip.Z());
524 // if (fRecalculatePhi)
525 // phi = AliForwardUtil::GetPhiFromStrip(r, t, phi, ip.X(), ip.Y());
527 h->Fill(eta,phi,poissonV);
528 rh->fDensity->Fill(eta, phi, poissonV);
531 hclone->Fill(eta,phi,poissonV);
534 if (fDoTiming) poissonTime += timer.CpuTime();
536 // --- Make diagnostics - eloss vs poisson ---------------------
537 if (fDoTiming) timer.Start(true);
538 Int_t nY = h->GetNbinsY();
539 for (Int_t ieta=1; ieta <= h->GetNbinsX(); ieta++) {
540 // Set the overflow bin to contain the phi acceptance
541 Double_t phiAcc = rh->fGood->GetBinContent(ieta);
542 Double_t phiAccE = rh->fGood->GetBinError(ieta);
543 h->SetBinContent(ieta, nY+1, phiAcc);
544 h->SetBinError(ieta, nY+1, phiAccE);
545 Double_t eta = h->GetXaxis()->GetBinCenter(ieta);
546 rh->fPhiAcc->Fill(eta, ip.Z(), phiAcc);
547 for (Int_t iphi=1; iphi<= nY; iphi++) {
549 Double_t poissonV = 0; //h->GetBinContent(,s+1);
552 poissonV = h->GetBinContent(ieta,iphi);
553 eLossV = hclone->GetBinContent(ieta,iphi);
556 poissonV = hclone->GetBinContent(ieta,iphi);
557 eLossV = h->GetBinContent(ieta,iphi);
560 rh->fELossVsPoisson->Fill(eLossV, poissonV);
561 rh->fDiffELossPoisson->Fill(poissonV < 1e-12 ? 0 :
562 (eLossV - poissonV) / poissonV);
566 if (fDoTiming) diagTime += timer.CpuTime();
573 fHTiming->Fill(1,reEtaTime);
574 fHTiming->Fill(2,nPartTime);
575 fHTiming->Fill(3,corrTime);
576 fHTiming->Fill(4,rePhiTime);
577 fHTiming->Fill(5,copyTime);
578 fHTiming->Fill(6,poissonTime);
579 fHTiming->Fill(7,diagTime);
580 fHTiming->Fill(8,totalT.CpuTime());
586 //_____________________________________________________________________
588 AliFMDDensityCalculator::FindMaxWeight(const AliFMDCorrELossFit* cor,
589 UShort_t d, Char_t r, Int_t iEta) const
592 // Find the max weight to use for FMD<i>dr</i> in eta bin @a iEta
600 DGUARD(fDebug, 10, "Find maximum weight in FMD density calculator");
603 AliFMDCorrELossFit::ELossFit* fit = cor->FindFit(d,r,iEta, -1);
605 // AliWarning(Form("No energy loss fit for FMD%d%c at eta=%f", d, r, eta));
608 return fit->FindMaxWeight(2*AliFMDCorrELossFit::ELossFit::fgMaxRelError,
609 AliFMDCorrELossFit::ELossFit::fgLeastWeight,
613 //_____________________________________________________________________
615 AliFMDDensityCalculator::CacheMaxWeights(const TAxis& axis)
618 // Find the max weights and cache them
620 DGUARD(fDebug, 2, "Cache maximum weights in FMD density calculator");
621 AliForwardCorrectionManager& fcm = AliForwardCorrectionManager::Instance();
622 const AliFMDCorrELossFit* cor = fcm.GetELossFit();
623 cor->CacheBins(fMinQuality);
625 TAxis eta(axis.GetNbins(),
630 eta.Set(cor->GetEtaAxis().GetNbins(),
631 cor->GetEtaAxis().GetXmin(),
632 cor->GetEtaAxis().GetXmax());
634 Int_t nEta = eta.GetNbins();
641 fMaxWeights->SetBins(nEta, eta.GetXmin(), eta.GetXmax(), 5, .5, 5.5);
642 fMaxWeights->GetYaxis()->SetBinLabel(1, "FMD1i");
643 fMaxWeights->GetYaxis()->SetBinLabel(2, "FMD2i");
644 fMaxWeights->GetYaxis()->SetBinLabel(3, "FMD2o");
645 fMaxWeights->GetYaxis()->SetBinLabel(4, "FMD3i");
646 fMaxWeights->GetYaxis()->SetBinLabel(5, "FMD3o");
648 AliInfo(Form("Get eta axis with %d bins from %f to %f",
649 nEta, eta.GetXmin(), eta.GetXmax()));
650 fLowCuts->SetBins(nEta, eta.GetXmin(), eta.GetXmax(), 5, .5, 5.5);
651 fLowCuts->GetYaxis()->SetBinLabel(1, "FMD1i");
652 fLowCuts->GetYaxis()->SetBinLabel(2, "FMD2i");
653 fLowCuts->GetYaxis()->SetBinLabel(3, "FMD2o");
654 fLowCuts->GetYaxis()->SetBinLabel(4, "FMD3i");
655 fLowCuts->GetYaxis()->SetBinLabel(5, "FMD3o");
657 for (Int_t i = 0; i < nEta; i++) {
659 w[0] = fFMD1iMax[i] = FindMaxWeight(cor, 1, 'I', i+1);
660 w[1] = fFMD2iMax[i] = FindMaxWeight(cor, 2, 'I', i+1);
661 w[2] = fFMD2oMax[i] = FindMaxWeight(cor, 2, 'O', i+1);
662 w[3] = fFMD3iMax[i] = FindMaxWeight(cor, 3, 'I', i+1);
663 w[4] = fFMD3oMax[i] = FindMaxWeight(cor, 3, 'O', i+1);
665 l[0] = GetMultCut(1, 'I', i+1, false);
666 l[1] = GetMultCut(2, 'I', i+1, false);
667 l[2] = GetMultCut(2, 'O', i+1, false);
668 l[3] = GetMultCut(3, 'I', i+1, false);
669 l[4] = GetMultCut(3, 'O', i+1, false);
670 for (Int_t j = 0; j < 5; j++) {
671 if (w[j] > 0) fMaxWeights->SetBinContent(i+1, j+1, w[j]);
672 if (l[j] > 0) fLowCuts->SetBinContent(i+1, j+1, l[j]);
677 //_____________________________________________________________________
679 AliFMDDensityCalculator::GetMaxWeight(UShort_t d, Char_t r, Int_t iEta) const
682 // Find the (cached) maximum weight for FMD<i>dr</i> in
683 // @f$\eta@f$ bin @a iEta
691 // max weight or <= 0 in case of problems
693 if (iEta < 0) return -1;
695 const TArrayI* max = 0;
697 case 1: max = &fFMD1iMax; break;
698 case 2: max = (r == 'I' || r == 'i' ? &fFMD2iMax : &fFMD2oMax); break;
699 case 3: max = (r == 'I' || r == 'i' ? &fFMD3iMax : &fFMD3oMax); break;
702 AliWarning(Form("No array for FMD%d%c", d, r));
706 if (iEta >= max->fN) {
707 AliWarning(Form("Eta bin %3d out of bounds [0,%d]",
712 AliDebug(30,Form("Max weight for FMD%d%c eta bin %3d: %d", d, r, iEta,
714 return max->At(iEta);
717 //_____________________________________________________________________
719 AliFMDDensityCalculator::GetMaxWeight(UShort_t d, Char_t r, Float_t eta) const
722 // Find the (cached) maximum weight for FMD<i>dr</i> iat
731 // max weight or <= 0 in case of problems
733 AliForwardCorrectionManager& fcm = AliForwardCorrectionManager::Instance();
734 Int_t iEta = fcm.GetELossFit()->FindEtaBin(eta) -1;
736 return GetMaxWeight(d, r, iEta);
739 //_____________________________________________________________________
741 AliFMDDensityCalculator::NParticles(Float_t mult,
745 Bool_t lowFlux) const
748 // Get the number of particles corresponding to the signal mult
755 // t Strip (not used)
757 // eta Pseudo-rapidity
758 // lowFlux Low-flux flag
761 // The number of particles
763 // if (mult <= GetMultCut()) return 0;
764 DGUARD(fDebug, 3, "Calculate Nch in FMD density calculator");
765 if (lowFlux) return 1;
767 AliForwardCorrectionManager& fcm = AliForwardCorrectionManager::Instance();
768 AliFMDCorrELossFit::ELossFit* fit = fcm.GetELossFit()->FindFit(d,r,eta, -1);
770 AliWarning(Form("No energy loss fit for FMD%d%c at eta=%f qual=%d",
771 d, r, eta, fMinQuality));
775 Int_t m = GetMaxWeight(d,r,eta); // fit->FindMaxWeight();
777 AliWarning(Form("No good fits for FMD%d%c at eta=%f", d, r, eta));
781 UShort_t n = TMath::Min(fMaxParticles, UShort_t(m));
782 Double_t ret = fit->EvaluateWeighted(mult, n);
785 AliInfo(Form("FMD%d%c, eta=%7.4f, %8.5f -> %8.5f", d, r, eta, mult, ret));
788 fWeightedSum->Fill(ret);
789 fSumOfWeights->Fill(ret);
794 //_____________________________________________________________________
796 AliFMDDensityCalculator::Correction(UShort_t d,
800 Bool_t lowFlux) const
803 // Get the inverse correction factor. This consist of
805 // - acceptance correction (corners of sensors)
806 // - double hit correction (for low-flux events)
807 // - dead strip correction
813 // t Strip (not used)
815 // eta Pseudo-rapidity
816 // lowFlux Low-flux flag
821 DGUARD(fDebug, 10, "Apply correction in FMD density calculator");
822 Float_t correction = 1;
823 if (fUsePhiAcceptance == kPhiCorrectNch)
824 correction = AcceptanceCorrection(r,t);
826 AliForwardCorrectionManager& fcm = AliForwardCorrectionManager::Instance();
829 if (fcm.GetDoubleHit())
830 dblHitCor = fcm.GetDoubleHit()->GetCorrection(d,r);
833 Double_t dblC = dblHitCor->GetBinContent(dblHitCor->FindBin(eta));
834 if (dblC > 0) correction *= dblC;
837 // AliWarning(Form("Missing double hit correction for FMD%d%c",d,r));
843 //_____________________________________________________________________
845 AliFMDDensityCalculator::GenerateAcceptanceCorrection(Char_t r) const
848 // Generate the acceptance corrections
851 // r Ring to generate for
854 // Newly allocated histogram of acceptance corrections
856 DGUARD(fDebug, 3, "Make acceptance correction in FMD density calculator");
857 const Double_t ic1[] = { 4.9895, 15.3560 };
858 const Double_t ic2[] = { 1.8007, 17.2000 };
859 const Double_t oc1[] = { 4.2231, 26.6638 };
860 const Double_t oc2[] = { 1.8357, 27.9500 };
861 const Double_t* c1 = (r == 'I' || r == 'i' ? ic1 : oc1);
862 const Double_t* c2 = (r == 'I' || r == 'i' ? ic2 : oc2);
863 Double_t minR = (r == 'I' || r == 'i' ? 4.5213 : 15.4);
864 Double_t maxR = (r == 'I' || r == 'i' ? 17.2 : 28.0);
865 Int_t nStrips = (r == 'I' || r == 'i' ? 512 : 256);
866 Int_t nSec = (r == 'I' || r == 'i' ? 20 : 40);
867 Float_t basearc = 2 * TMath::Pi() / nSec;
868 Double_t rad = maxR - minR;
869 Float_t segment = rad / nStrips;
870 Float_t cr = TMath::Sqrt(c1[0]*c1[0]+c1[1]*c1[1]);
872 // Numbers used to find end-point of strip.
873 // (See http://mathworld.wolfram.com/Circle-LineIntersection.html)
874 Float_t D = c1[0] * c2[1] - c1[1] * c2[0];
875 Float_t dx = c2[0] - c1[0];
876 Float_t dy = c2[1] - c1[1];
877 Float_t dr = TMath::Sqrt(dx*dx+dy*dy);
879 TH1D* ret = new TH1D(Form("acc%c", r),
880 Form("Acceptance correction for FMDx%c", r),
881 nStrips, -.5, nStrips-.5);
882 ret->SetXTitle("Strip");
883 ret->SetYTitle("#varphi acceptance");
884 ret->SetDirectory(0);
885 ret->SetFillColor(r == 'I' || r == 'i' ? kRed+1 : kBlue+1);
886 ret->SetFillStyle(3001);
888 for (Int_t t = 0; t < nStrips; t++) {
889 Float_t radius = minR + t * segment;
891 // If the radius of the strip is smaller than the radius corresponding
892 // to the first corner we have a full strip length
894 ret->SetBinContent(t+1, 1);
898 // Next, we should find the end-point of the strip - that is,
899 // the coordinates where the line from c1 to c2 intersects a circle
900 // with radius given by the strip.
901 // (See http://mathworld.wolfram.com/Circle-LineIntersection.html)
902 // Calculate the determinant
903 Float_t det = radius * radius * dr * dr - D*D;
906 // <0 means No intersection
907 // =0 means Exactly tangent
908 ret->SetBinContent(t+1, 1);
912 // Calculate end-point and the corresponding opening angle
913 Float_t x = (+D * dy + dx * TMath::Sqrt(det)) / dr / dr;
914 Float_t y = (-D * dx + dy * TMath::Sqrt(det)) / dr / dr;
915 Float_t th = TMath::ATan2(x, y);
917 ret->SetBinContent(t+1, th / basearc);
922 //_____________________________________________________________________
924 AliFMDDensityCalculator::AcceptanceCorrection(Char_t r, UShort_t t) const
927 // Get the acceptance correction for strip @a t in an ring of type @a r
930 // r Ring type ('I' or 'O')
934 // Inverse acceptance correction
936 TH1D* acc = (r == 'I' || r == 'i' ? fAccI : fAccO);
937 return acc->GetBinContent(t+1);
940 //____________________________________________________________________
942 AliFMDDensityCalculator::Terminate(const TList* dir, TList* output,
946 // Scale the histograms to the total number of events
949 // dir where to put the output
950 // nEvents Number of events
952 DGUARD(fDebug, 1, "Scale histograms in FMD density calculator");
953 if (nEvents <= 0) return;
954 TList* d = static_cast<TList*>(dir->FindObject(GetName()));
957 TList* out = new TList;
958 out->SetName(d->GetName());
961 TIter next(&fRingHistos);
963 THStack* sums = new THStack("sums", "sums of ring signals");
964 while ((o = static_cast<RingHistos*>(next()))) {
965 o->Terminate(d, nEvents);
967 Warning("Terminate", "No density in %s", o->GetName());
970 TH1D* sum = o->fDensity->ProjectionX(o->GetName(), 1,
971 o->fDensity->GetNbinsY(),"e");
972 sum->Scale(1., "width");
973 sum->SetTitle(o->GetName());
974 sum->SetDirectory(0);
975 sum->SetYTitle("#sum N_{ch,incl}");
982 //____________________________________________________________________
984 AliFMDDensityCalculator::CreateOutputObjects(TList* dir)
987 // Output diagnostic histograms to directory
990 // dir List to write in
992 DGUARD(fDebug, 1, "Define output FMD density calculator");
993 TList* d = new TList;
995 d->SetName(GetName());
997 d->Add(fWeightedSum);
998 d->Add(fSumOfWeights);
999 d->Add(fCorrections);
1002 d->Add(fMaxWeights);
1005 // TNamed* sigma = new TNamed("sigma",
1006 // (fIncludeSigma ? "included" : "excluded"));
1007 TObject* maxP = AliForwardUtil::MakeParameter("maxParticle", fMaxParticles);
1008 TObject* method = AliForwardUtil::MakeParameter("method", fUsePoisson);
1009 TObject* phiA = AliForwardUtil::MakeParameter("phiAcceptance",
1011 TObject* etaL = AliForwardUtil::MakeParameter("etaLumping", fEtaLumping);
1012 TObject* phiL = AliForwardUtil::MakeParameter("phiLumping", fPhiLumping);
1013 TObject* reEt = AliForwardUtil::MakeParameter("recalcEta", fRecalculateEta);
1014 TObject* rePh = AliForwardUtil::MakeParameter("recalcPhi", fRecalculatePhi);
1016 TParameter<int>* nFiles = new TParameter<int>("nFiles", 1);
1017 nFiles->SetMergeMode('+');
1029 fCuts.Output(d,"lCuts");
1031 TIter next(&fRingHistos);
1033 while ((o = static_cast<RingHistos*>(next()))) {
1034 o->fPoisson.SetLumping(fEtaLumping, fPhiLumping);
1035 o->CreateOutputObjects(d);
1038 if (!fDoTiming) return;
1040 fHTiming = new TProfile("timing", "#LTt_{part}#GT", 8, .5, 8.5);
1041 fHTiming->SetDirectory(0);
1042 fHTiming->SetYTitle("#LTt_{part}#GT");
1043 fHTiming->SetXTitle("Part");
1044 fHTiming->SetFillColor(kRed+1);
1045 fHTiming->SetFillStyle(3001);
1046 fHTiming->SetMarkerStyle(20);
1047 fHTiming->SetMarkerColor(kBlack);
1048 fHTiming->SetLineColor(kBlack);
1049 fHTiming->SetStats(0);
1050 TAxis* xaxis = fHTiming->GetXaxis();
1051 xaxis->SetBinLabel(1, "Re-calculation of #eta");
1052 xaxis->SetBinLabel(2, "N_{particle}");
1053 xaxis->SetBinLabel(3, "Correction");
1054 xaxis->SetBinLabel(4, "Re-calculation of #phi");
1055 xaxis->SetBinLabel(5, "Copy to cache");
1056 xaxis->SetBinLabel(6, "Poisson calculation");
1057 xaxis->SetBinLabel(7, "Diagnostics");
1058 xaxis->SetBinLabel(8, "Total");
1061 #define PF(N,V,...) \
1062 AliForwardUtil::PrintField(N,V, ## __VA_ARGS__)
1063 #define PFB(N,FLAG) \
1065 AliForwardUtil::PrintName(N); \
1066 std::cout << std::boolalpha << (FLAG) << std::noboolalpha << std::endl; \
1068 #define PFV(N,VALUE) \
1070 AliForwardUtil::PrintName(N); \
1071 std::cout << (VALUE) << std::endl; } while(false)
1073 //____________________________________________________________________
1075 AliFMDDensityCalculator::Print(Option_t* option) const
1078 // Print information
1083 AliForwardUtil::PrintTask(*this);
1084 gROOT->IncreaseDirLevel();
1086 TString phiM("none");
1087 switch (fUsePhiAcceptance) {
1088 case kPhiNoCorrect: phiM = "none"; break;
1089 case kPhiCorrectNch: phiM = "correct Nch"; break;
1090 case kPhiCorrectELoss: phiM = "correct energy loss"; break;
1093 PFV("Max(particles)", fMaxParticles );
1094 PFV("Poisson method", fUsePoisson );
1095 PFV("Eta lumping", fEtaLumping );
1096 PFV("Phi lumping", fPhiLumping );
1097 PFV("Recalculate eta", fRecalculateEta );
1098 PFV("Recalculate phi", fRecalculatePhi );
1099 PFV("Use phi acceptance", phiM);
1100 PFV("Lower cut", "");
1103 TString opt(option);
1105 if (!opt.Contains("nomax")) {
1106 PFV("Max weights", "");
1109 for (Int_t i = 0; i < gROOT->GetDirLevel(); i++) ind[i] = ' ';
1110 ind[gROOT->GetDirLevel()] = '\0';
1111 for (UShort_t d=1; d<=3; d++) {
1112 UShort_t nr = (d == 1 ? 1 : 2);
1113 for (UShort_t q=0; q<nr; q++) {
1114 ind[gROOT->GetDirLevel()] = ' ';
1115 ind[gROOT->GetDirLevel()+1] = '\0';
1116 Char_t r = (q == 0 ? 'I' : 'O');
1117 std::cout << ind << " FMD" << d << r << ":";
1118 ind[gROOT->GetDirLevel()+1] = ' ';
1119 ind[gROOT->GetDirLevel()+2] = '\0';
1121 const TArrayI& a = (d == 1 ? fFMD1iMax :
1122 (d == 2 ? (r == 'I' ? fFMD2iMax : fFMD2oMax) :
1123 (r == 'I' ? fFMD3iMax : fFMD3oMax)));
1125 for (Int_t i = 0; i < a.fN; i++) {
1126 if (a.fArray[i] < 1) continue;
1127 if (j % 6 == 0) std::cout << "\n " << ind;
1129 std::cout << " " << std::setw(3) << i << ": " << a.fArray[i];
1131 std::cout << std::endl;
1135 gROOT->DecreaseDirLevel();
1138 //====================================================================
1139 AliFMDDensityCalculator::RingHistos::RingHistos()
1140 : AliForwardUtil::RingHistos(),
1149 fDiffELossPoisson(0),
1165 //____________________________________________________________________
1166 AliFMDDensityCalculator::RingHistos::RingHistos(UShort_t d, Char_t r)
1167 : AliForwardUtil::RingHistos(d,r),
1176 fDiffELossPoisson(0),
1177 fPoisson("ignored"),
1195 fEvsN = new TH2D("elossVsNnocorr",
1196 "#Delta E/#Delta E_{mip} vs uncorrected inclusive N_{ch}",
1197 250, -.5, 24.5, 251, -1.5, 24.5);
1198 fEvsN->SetXTitle("#Delta E/#Delta E_{mip}");
1199 fEvsN->SetYTitle("Inclusive N_{ch} (uncorrected)");
1201 fEvsN->SetDirectory(0);
1203 fEvsM = static_cast<TH2D*>(fEvsN->Clone("elossVsNcorr"));
1204 fEvsM->SetTitle("#Delta E/#Delta E_{mip} vs corrected inclusive N_{ch}");
1205 fEvsM->SetDirectory(0);
1207 fEtaVsN = new TProfile("etaVsNnocorr",
1208 "Average inclusive N_{ch} vs #eta (uncorrected)",
1210 fEtaVsN->SetXTitle("#eta");
1211 fEtaVsN->SetYTitle("#LT N_{ch,incl}#GT (uncorrected)");
1212 fEtaVsN->SetDirectory(0);
1213 fEtaVsN->SetLineColor(Color());
1214 fEtaVsN->SetFillColor(Color());
1216 fEtaVsM = static_cast<TProfile*>(fEtaVsN->Clone("etaVsNcorr"));
1217 fEtaVsM->SetTitle("Average inclusive N_{ch} vs #eta (corrected)");
1218 fEtaVsM->SetYTitle("#LT N_{ch,incl}#GT (corrected)");
1219 fEtaVsM->SetDirectory(0);
1222 fCorr = new TProfile("corr", "Average correction", 200, -4, 6);
1223 fCorr->SetXTitle("#eta");
1224 fCorr->SetYTitle("#LT correction#GT");
1225 fCorr->SetDirectory(0);
1226 fCorr->SetLineColor(Color());
1227 fCorr->SetFillColor(Color());
1229 fDensity = new TH2D("inclDensity", "Inclusive N_{ch} density",
1230 200, -4, 6, (r == 'I' || r == 'i' ? 20 : 40),
1232 fDensity->SetDirectory(0);
1233 fDensity->Sumw2(); fDensity->SetMarkerColor(Color());
1234 fDensity->SetXTitle("#eta");
1235 fDensity->SetYTitle("#phi [radians]");
1236 fDensity->SetZTitle("Inclusive N_{ch} density");
1238 fELossVsPoisson = new TH2D("elossVsPoisson",
1239 "N_{ch} from energy loss vs from Poission",
1240 500, 0, 100, 500, 0, 100);
1241 fELossVsPoisson->SetDirectory(0);
1242 fELossVsPoisson->SetXTitle("N_{ch} from #DeltaE");
1243 fELossVsPoisson->SetYTitle("N_{ch} from Poisson");
1244 fELossVsPoisson->SetZTitle("Correlation");
1246 fDiffELossPoisson = new TH1D("diffElossPoisson",
1247 "(N_{ch,#DeltaE}-N_{ch,Poisson})/N_{ch,Poisson}",
1249 fDiffELossPoisson->SetDirectory(0);
1250 fDiffELossPoisson->SetXTitle(fDiffELossPoisson->GetTitle());
1251 fDiffELossPoisson->SetYTitle("Frequency");
1252 fDiffELossPoisson->SetMarkerColor(Color());
1253 fDiffELossPoisson->SetFillColor(Color());
1254 fDiffELossPoisson->SetFillStyle(3001);
1255 fDiffELossPoisson->Sumw2();
1257 fELoss = new TH1D("eloss", "#Delta/#Delta_{mip} in all strips",
1259 fELoss->SetXTitle("#Delta/#Delta_{mip} (selected)");
1260 fELoss->SetYTitle("P(#Delta/#Delta_{mip})");
1261 fELoss->SetFillColor(Color()-2);
1262 fELoss->SetFillStyle(3003);
1263 fELoss->SetLineColor(kBlack);
1264 fELoss->SetLineStyle(2);
1265 fELoss->SetLineWidth(2);
1266 fELoss->SetDirectory(0);
1268 fELossUsed = static_cast<TH1D*>(fELoss->Clone("elossUsed"));
1269 fELossUsed->SetTitle("#Delta/#Delta_{mip} in used strips");
1270 fELossUsed->SetFillStyle(3002);
1271 fELossUsed->SetLineStyle(1);
1272 fELossUsed->SetDirectory(0);
1274 fPhiBefore = new TH1D("phiBefore", "#phi distribution (before recalc)",
1275 (r == 'I' || r == 'i' ? 20 : 40), 0, 2*TMath::Pi());
1276 fPhiBefore->SetDirectory(0);
1277 fPhiBefore->SetXTitle("#phi");
1278 fPhiBefore->SetYTitle("Events");
1279 fPhiBefore->SetMarkerColor(Color());
1280 fPhiBefore->SetLineColor(Color());
1281 fPhiBefore->SetFillColor(Color());
1282 fPhiBefore->SetFillStyle(3001);
1283 fPhiBefore->SetMarkerStyle(20);
1285 fPhiAfter = static_cast<TH1D*>(fPhiBefore->Clone("phiAfter"));
1286 fPhiAfter->SetTitle("#phi distribution (after re-calc)");
1287 fPhiAfter->SetDirectory(0);
1290 //____________________________________________________________________
1291 AliFMDDensityCalculator::RingHistos::RingHistos(const RingHistos& o)
1292 : AliForwardUtil::RingHistos(o),
1296 // fEtaVsN(o.fEtaVsN),
1297 // fEtaVsM(o.fEtaVsM),
1299 fDensity(o.fDensity),
1300 fELossVsPoisson(o.fELossVsPoisson),
1301 fDiffELossPoisson(o.fDiffELossPoisson),
1302 fPoisson(o.fPoisson),
1304 fELossUsed(o.fELossUsed),
1305 fMultCut(o.fMultCut),
1309 fPhiBefore(o.fPhiBefore),
1310 fPhiAfter(o.fPhiAfter)
1316 // o Object to copy from
1320 //____________________________________________________________________
1321 AliFMDDensityCalculator::RingHistos&
1322 AliFMDDensityCalculator::RingHistos::operator=(const RingHistos& o)
1325 // Assignment operator
1328 // o Object to assign from
1331 // Reference to this
1333 if (&o == this) return *this;
1334 AliForwardUtil::RingHistos::operator=(o);
1336 // if (fEvsN) delete fEvsN;
1337 // if (fEvsM) delete fEvsM;
1338 // if (fEtaVsN) delete fEtaVsN;
1339 // if (fEtaVsM) delete fEtaVsM;
1340 if (fCorr) delete fCorr;
1341 if (fDensity) delete fDensity;
1342 if (fELossVsPoisson) delete fELossVsPoisson;
1343 if (fDiffELossPoisson) delete fDiffELossPoisson;
1344 if (fTotal) delete fTotal;
1345 if (fGood) delete fGood;
1346 if (fPhiAcc) delete fPhiAcc;
1347 if (fPhiBefore) delete fPhiBefore;
1348 if (fPhiAfter) delete fPhiAfter;
1350 // fEvsN = static_cast<TH2D*>(o.fEvsN->Clone());
1351 // fEvsM = static_cast<TH2D*>(o.fEvsM->Clone());
1352 // fEtaVsN = static_cast<TProfile*>(o.fEtaVsN->Clone());
1353 // fEtaVsM = static_cast<TProfile*>(o.fEtaVsM->Clone());
1354 fCorr = static_cast<TProfile*>(o.fCorr->Clone());
1355 fDensity = static_cast<TH2D*>(o.fDensity->Clone());
1356 fELossVsPoisson = static_cast<TH2D*>(o.fELossVsPoisson->Clone());
1357 fDiffELossPoisson = static_cast<TH1D*>(o.fDiffELossPoisson->Clone());
1358 fPoisson = o.fPoisson;
1359 fELoss = static_cast<TH1D*>(o.fELoss->Clone());
1360 fELossUsed = static_cast<TH1D*>(o.fELossUsed->Clone());
1361 fTotal = static_cast<TH1D*>(o.fTotal->Clone());
1362 fGood = static_cast<TH1D*>(o.fGood->Clone());
1363 fPhiAcc = static_cast<TH2D*>(o.fPhiAcc->Clone());
1364 fPhiBefore = static_cast<TH1D*>(o.fPhiBefore->Clone());
1365 fPhiAfter = static_cast<TH1D*>(o.fPhiAfter->Clone());
1368 //____________________________________________________________________
1369 AliFMDDensityCalculator::RingHistos::~RingHistos()
1377 //____________________________________________________________________
1379 AliFMDDensityCalculator::RingHistos::SetupForData(const TAxis& eAxis)
1382 // This is called on first event
1383 fPoisson.Init(-1,-1);
1384 fTotal = new TH1D("total", "Total # of strips per #eta",
1385 eAxis.GetNbins(), eAxis.GetXmin(), eAxis.GetXmax());
1386 fTotal->SetDirectory(0);
1387 fTotal->SetXTitle("#eta");
1388 fTotal->SetYTitle("# of strips");
1389 fGood = static_cast<TH1D*>(fTotal->Clone("good"));
1390 fGood->SetTitle("# of good strips per #eta");
1391 fGood->SetDirectory(0);
1393 fPhiAcc = new TH2D("phiAcc", "#phi acceptance vs Ip_{z}",
1394 eAxis.GetNbins(), eAxis.GetXmin(), eAxis.GetXmax(),
1396 fPhiAcc->SetXTitle("#eta");
1397 fPhiAcc->SetYTitle("v_{z} [cm]");
1398 fPhiAcc->SetZTitle("#phi acceptance");
1399 fPhiAcc->SetDirectory(0);
1401 if (fList) fList->Add(fPhiAcc);
1404 //____________________________________________________________________
1406 AliFMDDensityCalculator::RingHistos::CreateOutputObjects(TList* dir)
1409 // Make output. This is called as part of SlaveBegin
1412 // dir Where to put it
1414 TList* d = DefineOutputList(dir);
1421 d->Add(fELossVsPoisson);
1422 d->Add(fDiffELossPoisson);
1424 fPoisson.GetOccupancy()->SetFillColor(Color());
1425 fPoisson.GetMean()->SetFillColor(Color());
1426 fPoisson.GetOccupancy()->SetFillColor(Color());
1432 Bool_t inner = (fRing == 'I' || fRing == 'i');
1433 Int_t nStr = inner ? 512 : 256;
1434 Int_t nSec = inner ? 20 : 40;
1435 TAxis x(nStr, -.5, nStr-.5);
1436 TAxis y(nSec, -.5, nSec-.5);
1437 x.SetTitle("strip");
1438 y.SetTitle("sector");
1439 fPoisson.Define(x, y);
1441 d->Add(AliForwardUtil::MakeParameter("cut", fMultCut));
1445 //____________________________________________________________________
1447 AliFMDDensityCalculator::RingHistos::Terminate(TList* dir, Int_t nEvents)
1450 // Scale the histograms to the total number of events
1453 // dir Where the output is
1454 // nEvents Number of events
1456 TList* l = GetOutputList(dir);
1459 TH2D* density = static_cast<TH2D*>(GetOutputHist(l,"inclDensity"));
1460 if (density) density->Scale(1./nEvents);
1464 //____________________________________________________________________