1 // Object holding the Energy loss fit 'correction'
3 // These are generated from Monte-Carlo or real ESDs.
5 #include "AliFMDCorrELossFit.h"
6 #include "AliForwardUtil.h"
7 #include "AliLandauGaus.h"
11 #include <TVirtualPad.h>
26 Double_t AliFMDCorrELossFit::ELossFit::fgMaxRelError = .25;
27 Double_t AliFMDCorrELossFit::ELossFit::fgLeastWeight = 1e-7;
28 Double_t AliFMDCorrELossFit::ELossFit::fgMaxChi2nu = 20;
30 //____________________________________________________________________
31 AliFMDCorrELossFit::ELossFit::ELossFit()
54 // Default constructor
58 //____________________________________________________________________
59 AliFMDCorrELossFit::ELossFit::ELossFit(Int_t quality, const TF1& f)
60 : fN(f.GetNpar() > AliLandauGaus::kN ?
61 Int_t(f.GetParameter(AliLandauGaus::kN)) :
64 fChi2(f.GetChisquare()),
65 fC(f.GetParameter(AliLandauGaus::kC)),
66 fDelta(f.GetParameter(AliLandauGaus::kDelta)),
67 fXi(f.GetParameter(AliLandauGaus::kXi)),
68 fSigma(f.GetParameter(AliLandauGaus::kSigma)),
69 fSigmaN(f.GetParameter(AliLandauGaus::kSigmaN)),
71 fEC(f.GetParError(AliLandauGaus::kC)),
72 fEDelta(f.GetParError(AliLandauGaus::kDelta)),
73 fEXi(f.GetParError(AliLandauGaus::kXi)),
74 fESigma(f.GetParError(AliLandauGaus::kSigma)),
75 fESigmaN(f.GetParError(AliLandauGaus::kSigmaN)),
84 // Construct from a function
87 // quality Quality flag
91 fA = new Double_t[fN];
92 fEA = new Double_t[fN];
93 for (Int_t i = 0; i < fN-1; i++) {
94 fA[i] = f.GetParameter(AliLandauGaus::kA+i);
95 fEA[i] = f.GetParError(AliLandauGaus::kA+i);
101 //____________________________________________________________________
102 AliFMDCorrELossFit::ELossFit::ELossFit(Int_t quality,UShort_t n,
103 Double_t chi2, UShort_t nu,
104 Double_t c, Double_t ec,
105 Double_t delta, Double_t edelta,
106 Double_t xi, Double_t exi,
107 Double_t sigma, Double_t esigma,
108 Double_t sigman, Double_t esigman,
109 const Double_t* a,const Double_t* ea)
132 // Constructor with full parameter set
135 // quality Quality flag
136 // n @f$ N@f$ - Number of fitted peaks
137 // chi2 @f$ \chi^2 @f$
138 // nu @f$ \nu @f$ - number degrees of freedom
139 // c @f$ C@f$ - scale constant
140 // ec @f$ \delta C@f$ - error on @f$ C@f$
141 // delta @f$ \Delta@f$ - Most probable value
142 // edelta @f$ \delta\Delta@f$ - error on @f$\Delta@f$
143 // xi @f$ \xi@f$ - width
144 // exi @f$ \delta\xi@f$ - error on @f$\xi@f$
145 // sigma @f$ \sigma@f$ - Width of Gaussian
146 // esigma @f$ \delta\sigma@f$ - error on @f$\sigma@f$
147 // sigman @f$ \sigma_n@f$ - Noise width
148 // esigman @f$ \delta\sigma_n@f$ - error on @f$\sigma_n@f$
149 // a Array of @f$ N-1@f$ weights @f$ a_i@f$ for
151 // ea Array of @f$ N-1@f$ error on the weights @f$ a_i@f$ for
155 fA = new Double_t[fN];
156 fEA = new Double_t[fN];
157 for (Int_t i = 0; i < fN-1; i++) {
164 //____________________________________________________________________
165 AliFMDCorrELossFit::ELossFit::ELossFit(const ELossFit& o)
180 fESigmaN(o.fESigmaN),
182 fQuality(o.fQuality),
186 fMaxWeight(o.fMaxWeight)
192 // o Object to copy from
195 fA = new Double_t[fN];
196 fEA = new Double_t[fN];
197 for (Int_t i = 0; i < fN-1; i++) {
205 //____________________________________________________________________
206 AliFMDCorrELossFit::ELossFit&
207 AliFMDCorrELossFit::ELossFit::operator=(const ELossFit& o)
210 // Assignment operator
213 // o Object to assign from
216 // Reference to this object
218 if (&o == this) return *this;
231 fESigmaN = o.fESigmaN;
232 fQuality = o.fQuality;
236 fMaxWeight = o.fMaxWeight;
237 if (fA) delete [] fA;
238 if (fEA) delete [] fEA;
242 if (fN <= 0) return *this;
243 fA = new Double_t[fN];
244 fEA = new Double_t[fN];
245 for (Int_t i = 0; i < fN; i++) {
253 //____________________________________________________________________
254 AliFMDCorrELossFit::ELossFit::~ELossFit()
257 if (fEA) delete[] fEA;
261 //____________________________________________________________________
263 AliFMDCorrELossFit::ELossFit::FindMaxWeight(Double_t maxRelError,
264 Double_t leastWeight,
268 // Find the maximum weight to use. The maximum weight is the
269 // largest i for which
271 // - @f$ i \leq \max{N}@f$
272 // - @f$ a_i > \min{a}@f$
273 // - @f$ \delta a_i/a_i > \delta_{max}@f$
276 // maxRelError @f$ \min{a}@f$
277 // leastWeight @f$ \delta_{max}@f$
278 // maxN @f$ \max{N}@f$
281 // The largest index @f$ i@f$ for which the above
282 // conditions hold. Will never return less than 1.
284 if (fMaxWeight > 0) return fMaxWeight;
285 Int_t n = TMath::Min(maxN, UShort_t(fN-1));
287 // fN is one larger than we have data
288 for (Int_t i = 0; i < n-1; i++, m++) {
289 if (fA[i] < leastWeight) break;
290 if (fEA[i] / fA[i] > maxRelError) break;
292 return fMaxWeight = m;
295 //____________________________________________________________________
297 AliFMDCorrELossFit::ELossFit::Evaluate(Double_t x,
303 // f_N(x;\Delta,\xi,\sigma') =
304 // \sum_{i=1}^{n} a_i f(x;\Delta_i,\xi_i,\sigma_i')
307 // (see AliLandauGaus::NLandauGaus) for the maximum @f$ N @f$
308 // that fulfills the requirements
311 // x Where to evaluate
312 // maxN @f$ \max{N}@f$
315 // @f$ f_N(x;\Delta,\xi,\sigma')@f$
317 return AliLandauGaus::Fn(x, fDelta, fXi, fSigma, fSigmaN,
318 TMath::Min(maxN, UShort_t(fN)), fA);
321 //____________________________________________________________________
323 AliFMDCorrELossFit::ELossFit::EvaluateWeighted(Double_t x,
329 // f_W(x;\Delta,\xi,\sigma') =
330 // \frac{\sum_{i=1}^{n} i a_i f_i(x;\Delta,\xi,\sigma')}{
331 // f_N(x;\Delta,\xi,\sigma')} =
332 // \frac{\sum_{i=1}^{n} i a_i f(x;\Delta_i,\xi_i,\sigma_i')}{
333 // \sum_{i=1}^{n} a_i f(x;\Delta_i,\xi_i,\sigma_i')}
335 // where @f$ n@f$ fulfills the requirements (see FindMaxWeight).
337 // If the denominator is zero, then 1 is returned.
339 // See also AliLandauGaus::Fi and AliLandauGaus::NLandauGaus
340 // for more information on the evaluated functions.
343 // x Where to evaluate
344 // maxN @f$ \max{N}@f$
347 // @f$ f_W(x;\Delta,\xi,\sigma')@f$.
349 UShort_t n = TMath::Min(maxN, UShort_t(fN-1));
352 for (Int_t i = 1; i <= n; i++) {
353 Double_t a = (i == 1 ? 1 : fA[i-1]);
354 if (fA[i-1] < 0) break;
355 Double_t f = AliLandauGaus::Fi(x,fDelta,fXi,fSigma,fSigmaN,i);
359 if (den <= 0) return 1;
364 #define OUTPAR(N,V,E) \
365 std::setprecision(9) << \
366 std::setw(12) << N << ": " << \
367 std::setw(14) << V << " +/- " << \
368 std::setw(14) << E << " (" << \
369 std::setprecision(-1) << \
370 std::setw(5) << 100*(V>0?E/V:1) << "%)\n"
373 //____________________________________________________________________
375 AliFMDCorrELossFit::ELossFit::Compare(const TObject* o) const
378 // Compare to another ELossFit object.
380 // - +1, if this quality is better (larger) than other objects quality
381 // - -1, if this quality is worse (smaller) than other objects quality
382 // - +1, if this @f$|\chi^2/\nu-1|@f$ is smaller than the same for other
383 // - -1, if this @f$|\chi^2/\nu-1|@f$ is larger than the same for other
387 // o Other object to compare to
389 const ELossFit* other = static_cast<const ELossFit*>(o);
390 if (this->fQuality < other->fQuality) return -1;
391 if (this->fQuality > other->fQuality) return +1;
392 Double_t chi2nu = (fNu == 0 ? 1000 : fChi2 / fNu);
393 Double_t oChi2nu = (other->fNu == 0 ? 1000 : other->fChi2 / other->fNu);
394 if (TMath::Abs(chi2nu-1) < TMath::Abs(oChi2nu-1)) return +1;
395 if (TMath::Abs(chi2nu-1) > TMath::Abs(oChi2nu-1)) return -1;
399 //____________________________________________________________________
401 AliFMDCorrELossFit::ELossFit::Print(Option_t* option) const
404 // Information to standard output
410 if (o.Contains("S", TString::kIgnoreCase)) {
411 Printf("%15s: q=%2d n=%1d chi2/nu=%6.3f",
412 GetName(), fQuality, fN, (fNu <= 0 ? 999 : fChi2 / fNu));
416 std::cout << GetName() << ":\n"
417 << " chi^2/nu = " << fChi2 << "/" << fNu << " = "
418 << (fNu == 0 ? 999 : fChi2 / fNu) << "\n"
419 << " Quality: " << fQuality << "\n"
420 << " NParticles: " << fN << " (" << FindMaxWeight() << ")\n"
421 << OUTPAR("Delta", fDelta, fEDelta)
422 << OUTPAR("xi", fXi, fEXi)
423 << OUTPAR("sigma", fSigma, fESigma)
424 << OUTPAR("sigma_n", fSigmaN, fESigmaN);
425 for (Int_t i = 0; i < fN-1; i++)
426 std::cout << OUTPAR(Form("a%d", i+2), fA[i], fEA[i]);
427 std::cout << std::flush;
429 //____________________________________________________________________
431 AliFMDCorrELossFit::ELossFit::GetF1(Int_t i, Double_t max) const
433 const Double_t lowX = 0.001;
434 const Double_t upX = (max < 0 ? 10 : max);
435 Int_t maxW = FindMaxWeight();
439 ret = AliLandauGaus::MakeFn(fC * 1, fDelta, fXi,
440 fSigma, fSigmaN, maxW/*fN*/, fA, lowX, upX);
442 ret = AliLandauGaus::MakeF1(fC, fDelta, fXi, fSigma, fSigmaN, lowX, upX);
444 ret = AliLandauGaus::MakeFi(fC*(i == 1 ? 1 : fA[i-2]),
445 fDelta, fXi, fSigma, fSigmaN, i, lowX, upX);
449 //____________________________________________________________________
451 AliFMDCorrELossFit::ELossFit::FindProbabilityCut(Double_t low) const
457 if (!(f = GetF1(1,5))) // First landau up to Delta/Delta_{mip}=5
458 throw TString("Didn't TF1 object");
459 if (!(g = new TGraph(f, "i")))
460 throw TString("Failed to integrate function");
463 Double_t total = g->GetY()[n-1];
465 throw TString::Format("Invalid integral: %lf", total);
467 for (Int_t i = 0; i < n; i++) {
468 Double_t prob = g->GetY()[i] / total;
475 throw TString::Format("Couldn't find x value for cut %lf", low);
477 catch (const TString& str) {
478 AliWarningF("%s: %s", GetName(), str.Data());
486 //____________________________________________________________________
488 AliFMDCorrELossFit::ELossFit::GetName() const
491 // Get the name of this object
497 return Form("FMD%d%c_etabin%03d", fDet, fRing, fBin);
500 //____________________________________________________________________
502 AliFMDCorrELossFit::ELossFit::Browse(TBrowser* b)
505 // Browse this object
510 Draw(b ? b->GetDrawOption() : "comp values");
515 //____________________________________________________________________
517 AliFMDCorrELossFit::ELossFit::Draw(Option_t* option)
524 // - COMP Draw components too
533 if (opt.Contains("COMP")) {
534 opt.ReplaceAll("COMP","");
537 if (opt.Contains("GOOD")) {
538 opt.ReplaceAll("GOOD","");
541 if (opt.Contains("VALUES")) {
542 opt.ReplaceAll("VALUES","");
545 if (opt.Contains("LEGEND")) {
546 opt.ReplaceAll("LEGEND","");
549 if (!opt.Contains("SAME")) {
552 if (opt.Contains("PEAK")) {
557 l = new TLegend(.3, .5, .59, .94);
563 Int_t maxW = FindMaxWeight();
564 TF1* tot = AliLandauGaus::MakeFn(fC * 1, fDelta, fXi, fSigma, fSigmaN,
565 maxW/*fN*/, fA, 0.01, 10);
566 tot->SetLineColor(kBlack);
567 tot->SetLineWidth(2);
568 tot->SetLineStyle(1);
569 tot->SetTitle(GetName());
570 if (l) l->AddEntry(tot, "Total", "l");
571 Double_t max = tot->GetMaximum();
574 if (!opt.Contains("SAME")) {
575 TH1* frame = new TH1F(GetName(),
576 Form("FMD%d%c, eta bin %d",fDet,fRing,fBin),
578 frame->SetMinimum(max/10000);
579 frame->SetMaximum(max*1.4);
580 frame->SetXTitle("#Delta / #Delta_{mip}");
584 TF1* cpy = tot->DrawCopy(opt.Data());
592 TLatex* ltx1 = new TLatex(x1, y, "");
593 TLatex* ltx2 = new TLatex(x2, y, "");
595 ltx1->SetTextAlign(33);
596 ltx1->SetTextFont(132);
597 ltx1->SetTextSize(dy-.01);
599 ltx2->SetTextAlign(13);
600 ltx2->SetTextFont(132);
601 ltx2->SetTextSize(dy-.01);
603 ltx1->DrawLatex(x1, y, "Quality");
604 ltx2->DrawLatex(x2, y, Form("%d", fQuality));
607 ltx1->DrawLatex(x1, y, "#chi^{2}/#nu");
608 ltx2->DrawLatex(x2, y, Form("%7.3f", (fNu > 0 ? fChi2 / fNu : -1)));
611 const Char_t* pn[] = { "C", "#Delta", "#xi", "#sigma" };
612 Double_t pv[] = { fC, fDelta, fXi, fSigma };
613 Double_t pe[] = { fEC, fEDelta, fEXi, fESigma };
614 for (Int_t i = 0; i < 4; i++) {
615 ltx1->DrawLatex(x1, y, pn[i]);
616 ltx2->DrawLatex(x2, y, Form("%6.4f#pm%6.4f", pv[i], pe[i]));
619 for (Int_t i=2; i <= fN; i++) {
621 ltx1->SetTextColor(kRed+3);
622 ltx2->SetTextColor(kRed+3);
624 ltx1->DrawLatex(x1, y, Form("a_{%d}", i));
625 ltx2->DrawLatex(x2, y, Form("%6.4f#pm%6.4f", fA[i-2], fEA[i-2]));
632 TLine* pl = new TLine(fDelta, 0.01*max, fDelta, 1.5*max);
634 pl->SetLineColor(kBlack);
644 for (Int_t i=1; i <= fN; i++) {
645 if (good && i > maxW) break;
646 TF1* f = AliLandauGaus::MakeFi(fC*(i == 1 ? 1 : fA[i-2]),
651 f->SetLineStyle(i > maxW ? 2 : 1);
652 min = TMath::Min(f->GetMaximum(), min);
653 f->DrawCopy(opt.Data());
654 if (l) l->AddEntry(f, Form("%d MIP%s", i, (i>1 ? "s" : "")), "l");
659 if (max <= 0) max = 0.1;
660 if (min <= 0) min = 1e-4;
661 cpy->SetMaximum(max);
662 cpy->SetMinimum(min);
663 cpy->GetHistogram()->SetMaximum(max);
664 cpy->GetHistogram()->SetMinimum(min);
665 cpy->GetHistogram()->GetYaxis()->SetRangeUser(min, max);
672 //____________________________________________________________________
673 #define CHECKPAR(V,E,T) ((V > 0) && (E / V < T))
675 //____________________________________________________________________
677 AliFMDCorrELossFit::ELossFit::GetLowerBound(Double_t f) const
684 //____________________________________________________________________
686 AliFMDCorrELossFit::ELossFit::GetLowerBound(Double_t f,
687 Bool_t includeSigma) const
691 // Delta - f * (xi + sigma)
692 return fDelta - f * (fXi + (includeSigma ? fSigma : 0));
695 //____________________________________________________________________
697 AliFMDCorrELossFit::ELossFit::CalculateQuality(Double_t maxChi2nu,
698 Double_t maxRelError,
699 Double_t leastWeight)
702 // Calculate the quality
704 Double_t decline = maxChi2nu;
707 Double_t red = fChi2 / fNu;
708 if (red < maxChi2nu) qual += 4;
710 Int_t q = Int_t((maxChi2nu+decline - red) / decline * 4);
711 if (q > 0) qual += q;
714 if (CHECKPAR(fDelta, fEDelta, maxRelError)) qual++;
715 if (CHECKPAR(fXi, fEXi, maxRelError)) qual++;
716 if (CHECKPAR(fSigma, fESigma, maxRelError)) qual++;
717 if (CHECKPAR(fSigmaN, fESigmaN, maxRelError)) qual++;
718 // Large penalty for large sigma - often a bad fit.
719 if (fSigma > 10*fXi) qual -= 4;
720 qual += FindMaxWeight(2*maxRelError, leastWeight, fN);
724 //____________________________________________________________________
725 AliFMDCorrELossFit::AliFMDCorrELossFit()
733 // Default constructor
735 fRings.SetOwner(kTRUE);
736 fEtaAxis.SetTitle("#eta");
737 fEtaAxis.SetName("etaAxis");
738 fRings.SetName("rings");
741 //____________________________________________________________________
742 AliFMDCorrELossFit::AliFMDCorrELossFit(const AliFMDCorrELossFit& o)
745 fEtaAxis(o.fEtaAxis.GetNbins(),o.fEtaAxis.GetXmin(),o.fEtaAxis.GetXmax()),
753 // o Object to copy from
755 fEtaAxis.SetTitle("#eta");
756 fEtaAxis.SetName("etaAxis");
759 //____________________________________________________________________
760 AliFMDCorrELossFit::~AliFMDCorrELossFit()
768 //____________________________________________________________________
770 AliFMDCorrELossFit::operator=(const AliFMDCorrELossFit& o)
773 // Assignment operator
776 // o Object to assign from
779 // Reference to this object
781 if (&o == this) return *this;
785 SetEtaAxis(o.fEtaAxis.GetNbins(), o.fEtaAxis.GetXmin(), o.fEtaAxis.GetXmax());
789 #define CACHE(BIN,IDX,OFFSET) fCache[IDX*OFFSET+BIN-1]
790 #define CACHEDR(BIN,D,R,OFFSET) \
791 CACHE(BIN,(D == 1 ? 0 : (D - 2) * 2 + 1 + (R=='I' || R=='i' ? 0 : 1)),OFFSET)
793 //____________________________________________________________________
795 AliFMDCorrELossFit::CacheBins(UShort_t minQuality) const
797 AliLandauGaus::EnableSigmaShift(TestBit(kHasShift));
798 if (fCache.GetSize() > 0) return;
800 Int_t nRings = fRings.GetEntriesFast();
801 Int_t offset = fEtaAxis.GetNbins();
803 fCache.Set(nRings*offset);
806 for (Int_t i = 0; i < nRings; i++) {
807 TObjArray* ringArray = static_cast<TObjArray*>(fRings.At(i));
809 // First loop to find where we actually have fits
812 Int_t minBin = offset+1;
814 Int_t realMinBin = offset+1;
815 Int_t realMaxBin = -1;
816 for (Int_t j = 1; j < ringArray->GetEntriesFast(); j++) {
817 ELossFit* fit = static_cast<ELossFit*>(ringArray->At(j));
821 // Update our range off possible fits
822 realMinBin = TMath::Min(j, realMinBin);
823 realMaxBin = TMath::Max(j, realMaxBin);
825 // Check the quality of the fit
826 fit->CalculateQuality(AliFMDCorrELossFit::ELossFit::fgMaxChi2nu,
827 AliFMDCorrELossFit::ELossFit::fgMaxRelError,
828 AliFMDCorrELossFit::ELossFit::fgLeastWeight);
829 if (minQuality > 0 && fit->fQuality < minQuality) continue;
833 CACHE(j,i,offset) = j;
834 minBin = TMath::Min(j, minBin);
835 maxBin = TMath::Max(j, maxBin);
837 AliInfoF("Out of %d bins, %d had fits, of which %d are good (%5.1f%%)",
838 offset, nFits, nGood, (nFits > 0 ? 100*float(nGood)/nFits : 0));
840 // Now loop and set neighbors
841 realMinBin = TMath::Max(1, realMinBin-1); // Include one more
842 realMaxBin = TMath::Min(offset, realMaxBin+1); // Include one more
843 for (Int_t j = realMinBin; j <= realMaxBin; j++) {
844 if (CACHE(j,i,offset) > 0) continue;
846 Int_t nK = TMath::Max(realMaxBin - j, j - realMinBin);
848 for (Int_t k = 1; k <= nK; k++) {
851 if (left > realMinBin &&
852 CACHE(left,i,offset) == left) found = left;
853 else if (right < realMaxBin &&
854 CACHE(right,i,offset) == right) found = right;
855 if (found > 0) break;
857 // Now check that we found something
858 if (found) CACHE(j,i,offset) = CACHE(found,i,offset);
859 else AliWarningF("No fit found for etabin=%d in ring=%d", j, i);
865 //____________________________________________________________________
867 AliFMDCorrELossFit::FindEtaBin(Double_t eta) const
870 // Find the eta bin corresponding to the given eta
876 // Bin (in @f$[1,N_{bins}]@f$) corresponding to the given
877 // eta, or 0 if out of range.
879 if (TMath::Abs(fEtaAxis.GetXmin() - fEtaAxis.GetXmax()) < 1e-6
880 || fEtaAxis.GetNbins() == 0) {
881 AliWarning("No eta axis defined");
884 Int_t bin = const_cast<TAxis&>(fEtaAxis).FindBin(eta);
885 if (bin <= 0 || bin > fEtaAxis.GetNbins()) return 0;
889 //____________________________________________________________________
891 AliFMDCorrELossFit::SetFit(UShort_t d, Char_t r, Int_t etaBin, ELossFit* fit)
894 // Set the fit parameters from a function
899 // etaBin Eta (bin number, 1->nBins)
900 // f ELoss fit result - note, the object will take ownership
902 TObjArray* ringArray = GetOrMakeRingArray(d, r);
904 AliError(Form("Failed to make ring array for FMD%d%c", d, r));
907 if (etaBin <= 0 || etaBin >= fEtaAxis.GetNbins()+1) {
908 AliError(Form("bin=%d is out of range [%d,%d]",
909 etaBin, 1, fEtaAxis.GetNbins()));
912 // AliInfo(Form("Adding fit %p at %3d", fit, etaBin));
913 ringArray->AddAtAndExpand(fit, etaBin);
917 //____________________________________________________________________
919 AliFMDCorrELossFit::SetFit(UShort_t d, Char_t r, Double_t eta, ELossFit* fit)
922 // Set the fit parameters from a function
928 // f ELoss fit result - note, the object will take ownership
930 Int_t bin = FindEtaBin(eta);
932 AliError(Form("eta=%f is out of range [%f,%f]",
933 eta, fEtaAxis.GetXmin(), fEtaAxis.GetXmax()));
937 return SetFit(d, r, bin, fit);
939 //____________________________________________________________________
941 AliFMDCorrELossFit::SetFit(UShort_t d, Char_t r,
943 Int_t quality,UShort_t n,
944 Double_t chi2, UShort_t nu,
945 Double_t c, Double_t ec,
946 Double_t delta, Double_t edelta,
947 Double_t xi, Double_t exi,
948 Double_t sigma, Double_t esigma,
949 Double_t sigman, Double_t esigman,
950 Double_t* a, Double_t* ea)
953 // Set the fit parameters from a function
959 // quality Quality flag
960 // n @f$ N@f$ - Number of fitted peaks
961 // chi2 @f$ \chi^2 @f$
962 // nu @f$ \nu @f$ - number degrees of freedom
963 // c @f$ C@f$ - scale constant
964 // ec @f$ \delta C@f$ - error on @f$ C@f$
965 // delta @f$ \Delta@f$ - most probable value
966 // edelta @f$ \delta\Delta@f$ - error on @f$\Delta@f$
967 // xi @f$ \xi@f$ - Landau width
968 // exi @f$ \delta\xi@f$ - error on @f$\xi@f$
969 // sigma @f$ \sigma@f$ - Gaussian width
970 // esigma @f$ \delta\sigma@f$ - error on @f$\sigma@f$
971 // sigman @f$ \sigma_n@f$ - Noise width
972 // esigman @f$ \delta\sigma_n@f$ - error on @f$\sigma_n@f$
973 // a Array of @f$ N-1@f$ weights @f$ a_i@f$ for
975 // ea Array of @f$ N-1@f$ errors on weights @f$ a_i@f$ for
978 ELossFit* e = new ELossFit(quality, n,
986 if (!SetFit(d, r, eta, e)) {
992 //____________________________________________________________________
994 AliFMDCorrELossFit::SetFit(UShort_t d, Char_t r, Double_t eta,
995 Int_t quality, const TF1& f)
998 // Set the fit parameters from a function
1004 // quality Quality flag
1005 // f Function from fit
1007 ELossFit* e = new ELossFit(quality, f);
1008 if (!SetFit(d, r, eta, e)) {
1014 //____________________________________________________________________
1015 AliFMDCorrELossFit::ELossFit*
1016 AliFMDCorrELossFit::GetFit(UShort_t d, Char_t r, Int_t etabin) const
1019 // Get the fit corresponding to the specified parameters
1024 // etabin Eta bin (1 based)
1027 // Fit parameters or null in case of problems
1029 TObjArray* ringArray = GetRingArray(d, r);
1030 if (!ringArray) return 0;
1031 if (etabin <= 0 || etabin >= fEtaAxis.GetNbins()) return 0;
1032 if (etabin > ringArray->GetEntriesFast()) return 0;
1033 else if (etabin >= ringArray->GetEntriesFast()) etabin--;
1034 else if (!ringArray->At(etabin)) etabin++;
1035 return static_cast<ELossFit*>(ringArray->At(etabin));
1037 //____________________________________________________________________
1038 AliFMDCorrELossFit::ELossFit*
1039 AliFMDCorrELossFit::GetFit(UShort_t d, Char_t r, Double_t eta) const
1042 // Find the fit corresponding to the specified parameters
1050 // Fit parameters or null in case of problems
1052 Int_t etabin = FindEtaBin(eta);
1053 return GetFit(d, r, etabin);
1056 //____________________________________________________________________
1057 AliFMDCorrELossFit::ELossFit*
1058 AliFMDCorrELossFit::FindFit(UShort_t d, Char_t r, Int_t etabin,
1059 UShort_t minQ) const
1062 // Find the fit corresponding to the specified parameters
1067 // etabin Eta bin (1 based)
1070 // Fit parameters or null in case of problems
1072 if (etabin <= 0 || etabin >= fEtaAxis.GetNbins()) {
1073 // AliError(Form("Eta bin=%3d out of bounds [%d,%d] for FMD%d%c",
1074 // etabin, 1, fEtaAxis.GetNbins(), d, r));
1078 TObjArray* ringArray = GetRingArray(d, r);
1080 AliError(Form("Failed to make ring array for FMD%d%c", d, r));
1083 DMSG(fDebug, 10, "Got ringArray %s for FMD%d%c", ringArray->GetName(), d, r);
1084 if (fCache.GetSize() <= 0) CacheBins(minQ);
1086 Int_t idx = (d == 1 ? 0 :
1087 (d - 2) * 2 + 1 + (r=='I' || r=='i' ? 0 : 1));
1089 Int_t bin = CACHEDR(etabin, d, r, fEtaAxis.GetNbins());
1091 if (bin < 0 || bin > ringArray->GetEntriesFast()) return 0;
1093 return static_cast<ELossFit*>(ringArray->At(bin));
1095 //____________________________________________________________________
1096 AliFMDCorrELossFit::ELossFit*
1097 AliFMDCorrELossFit::FindFit(UShort_t d, Char_t r, Double_t eta,
1098 UShort_t minQ) const
1101 // Find the fit corresponding to the specified parameters
1109 // Fit parameters or null in case of problems
1111 Int_t etabin = FindEtaBin(eta);
1112 return FindFit(d, r, etabin, minQ);
1114 //____________________________________________________________________
1116 AliFMDCorrELossFit::GetRingArray(UShort_t d, Char_t r) const
1119 // Get the ring array corresponding to the specified ring
1126 // Pointer to ring array, or null in case of problems
1130 case 1: idx = 0; break;
1131 case 2: idx = (r == 'i' || r == 'I') ? 1 : 2; break;
1132 case 3: idx = (r == 'i' || r == 'I') ? 3 : 4; break;
1134 if (idx < 0 || idx >= fRings.GetEntriesFast()) return 0;
1135 return static_cast<TObjArray*>(fRings.At(idx));
1137 //____________________________________________________________________
1139 AliFMDCorrELossFit::GetOrMakeRingArray(UShort_t d, Char_t r)
1142 // Get the ring array corresponding to the specified ring
1149 // Pointer to ring array, or newly created container
1153 case 1: idx = 0; break;
1154 case 2: idx = (r == 'i' || r == 'I') ? 1 : 2; break;
1155 case 3: idx = (r == 'o' || r == 'I') ? 3 : 4; break;
1157 if (idx < 0) return 0;
1158 if (idx >= fRings.GetEntriesFast() || !fRings.At(idx)) {
1159 TObjArray* a = new TObjArray(0);
1160 // TOrdCollection* a = new TOrdCollection(fEtaAxis.GetNbins());
1161 a->SetName(Form("FMD%d%c", d, r));
1163 fRings.AddAtAndExpand(a, idx);
1165 return static_cast<TObjArray*>(fRings.At(idx));
1168 //____________________________________________________________________
1170 AliFMDCorrELossFit::GetLowerBound(UShort_t d, Char_t r, Int_t etabin,
1173 ELossFit* fit = FindFit(d, r, etabin, 20);
1174 if (!fit) return -1024;
1175 return fit->GetLowerBound(f);
1177 //____________________________________________________________________
1179 AliFMDCorrELossFit::GetLowerBound(UShort_t d, Char_t r, Double_t eta,
1182 Int_t bin = FindEtaBin(eta);
1183 if (bin <= 0) return -1024;
1184 return GetLowerBound(d, r, Int_t(bin), f);
1186 //____________________________________________________________________
1188 AliFMDCorrELossFit::GetLowerBound(UShort_t d, Char_t r, Int_t etabin,
1189 Double_t p, Bool_t) const
1191 DGUARD(fDebug, 10, "Get probability cut for FMD%d%c etabin=%d", d, r, etabin);
1192 ELossFit* fit = FindFit(d, r, etabin, 20);
1193 if (!fit) return -1024;
1194 return fit->FindProbabilityCut(p);
1196 //____________________________________________________________________
1198 AliFMDCorrELossFit::GetLowerBound(UShort_t d, Char_t r, Double_t eta,
1199 Double_t p, Bool_t dummy) const
1201 DGUARD(fDebug, 10, "Get probability cut for FMD%d%c eta=%8.4f", d, r, eta);
1202 Int_t bin = FindEtaBin(eta);
1203 DMSG(fDebug, 10, "bin=%4d", bin);
1204 if (bin <= 0) return -1024;
1205 return GetLowerBound(d, r, Int_t(bin), p, dummy);
1207 //____________________________________________________________________
1209 AliFMDCorrELossFit::GetLowerBound(UShort_t d, Char_t r, Int_t etabin,
1210 Double_t f, Bool_t showErrors,
1211 Bool_t includeSigma) const
1213 ELossFit* fit = FindFit(d, r, etabin, 20);
1216 AliWarning(Form("No fit for FMD%d%c @ etabin=%d", d, r, etabin));
1220 return fit->GetLowerBound(f, includeSigma);
1223 //____________________________________________________________________
1225 AliFMDCorrELossFit::GetLowerBound(UShort_t d, Char_t r, Double_t eta,
1226 Double_t f, Bool_t showErrors,
1227 Bool_t includeSigma) const
1229 Int_t bin = FindEtaBin(eta);
1232 AliError(Form("eta=%f out of bounds for FMD%d%c", eta, d, r));
1235 return GetLowerBound(d, r, bin, f, showErrors, includeSigma);
1238 //____________________________________________________________________
1240 TH1D* MakeHist(const TAxis& axis, const char* name, const char* title,
1243 TH1D* h = new TH1D(Form("%s_%s", name, title),
1244 Form("%s %s", name, title),
1245 axis.GetNbins(), axis.GetXmin(), axis.GetXmax());
1247 h->SetMarkerStyle(20);
1248 h->SetMarkerColor(color);
1249 h->SetMarkerSize(0.5);
1250 h->SetFillColor(color);
1251 h->SetFillStyle(3001);
1252 h->SetLineColor(color);
1259 #define IDX2RING(I) (i == 0 || i == 1 || i == 3 ? 'I' : 'O')
1260 #define IDX2DET(I) (i == 0 ? 1 : (i == 1 || i == 2 ? 2 : 3))
1261 //____________________________________________________________________
1263 AliFMDCorrELossFit::GetStacks(Bool_t err,
1266 UShort_t maxN) const
1268 // Get a list of THStacks
1269 Int_t nRings = fRings.GetEntriesFast();
1270 // Int_t nPad = 6+maxN-1; // 7 regular params, and maxN-1 weights
1288 TList* stacks = new TList;
1289 stacks->AddAt(sChi2nu= new THStack("chi2", "#chi^{2}/#nu"), kChi2nu);
1290 stacks->AddAt(sC = new THStack("c", "C"), kC);
1291 stacks->AddAt(sDelta = new THStack("delta", "#Delta_{mp}"), kDelta);
1292 stacks->AddAt(sXi = new THStack("xi", "#xi"), kXi);
1293 stacks->AddAt(sSigma = new THStack("sigma", "#sigma"), kSigma);
1294 //stacks->AddAt(sigman= new THStack("sigman", "#sigma_{n}"), 5);
1295 stacks->AddAt(n = new THStack("n", "N"), kN);
1297 sChi2nu->SetName("qual");
1298 sChi2nu->SetTitle("Quality");
1300 n->SetTitle("Bin map");
1302 for (Int_t i = 1; i <= maxN; i++) {
1303 stacks->AddAt(new THStack(Form("a_%02d", i+1), Form("a_{%d}", i+1)), kN+i);
1306 // TArrayD min(nPad);
1307 // TArrayD max(nPad);
1308 // min.Reset(100000);
1309 // max.Reset(-100000);
1311 for (Int_t i = 0; i < nRings; i++) {
1312 if (!fRings.At(i)) continue;
1313 TObjArray* a = static_cast<TObjArray*>(fRings.At(i));
1314 Int_t nFits = a->GetEntriesFast();
1315 UShort_t d = IDX2DET(i);
1316 Char_t r = IDX2RING(i);
1317 Int_t color = AliForwardUtil::RingColor(d, r);
1319 TH1* hChi = MakeHist(fEtaAxis,a->GetName(), "chi2", color);
1320 TH1* hC = MakeHist(fEtaAxis,a->GetName(), "c", color);
1321 TH1* hDelta = MakeHist(fEtaAxis,a->GetName(), "delta", color);
1322 TH1* hXi = MakeHist(fEtaAxis,a->GetName(), "xi", color);
1323 TH1* hSigma = MakeHist(fEtaAxis,a->GetName(), "sigma", color);
1324 // TH1D* hSigmaN = MakeHist(fEtaAxis,a->GetName(), "sigman", color);
1325 TH1* hN = MakeHist(fEtaAxis,a->GetName(), "n", color);
1327 const char* ho = (rel || !err ? "hist" : "e");
1328 sChi2nu->Add(hChi, "hist"); // 0
1329 sC ->Add(hC, ho); // 1
1330 sDelta ->Add(hDelta, ho); // 2
1331 sXi ->Add(hXi, ho); // 3
1332 sSigma ->Add(hSigma, ho); // 4
1333 // sigman->Add(hSigmaN,ho); // 5
1334 n ->Add(hN, "hist"); // 5
1335 hChi->SetFillColor(color);
1336 hChi->SetFillStyle(3001);
1337 hN->SetFillColor(color);
1338 hN->SetFillStyle(3001);
1340 for (Int_t k = 1; k <= maxN; k++) {
1341 hA[k-1] = MakeHist(fEtaAxis,a->GetName(), Form("a%02d",k+1), color);
1342 static_cast<THStack*>(stacks->At(kN+k))->Add(hA[k-1], ho);
1346 for (Int_t j = 1; j <= fEtaAxis.GetNbins(); j++) {
1347 ELossFit* f = FindFit(d, r, j, 20);
1350 UpdateStackHist(f, rel, j, hChi, hN, hC, hDelta, hXi, hSigma, maxN, hA);
1354 for (Int_t j = 0; j < nFits; j++) {
1355 ELossFit* f = static_cast<ELossFit*>(a->At(j));
1358 UpdateStackHist(f, rel, CACHE(j,i,fEtaAxis.GetNbins()),
1359 hChi, hN, hC, hDelta, hXi, hSigma, maxN, hA);
1365 //____________________________________________________________________
1367 AliFMDCorrELossFit::UpdateStackHist(ELossFit* f, Bool_t rel,
1370 TH1* hC, TH1* hDelta,
1371 TH1* hXi, TH1* hSigma,
1372 Int_t maxN, TH1** hA) const
1375 Double_t chi2nu =(rel ? f->fQuality : (f->fNu <= 0 ? 0 : f->fChi2 / f->fNu));
1376 Double_t c =(rel ? (f->fC >0 ?f->fEC /f->fC :0) : f->fC);
1377 Double_t delta =(rel ? (f->fDelta >0 ?f->fEDelta /f->fDelta :0) : f->fDelta);
1378 Double_t xi =(rel ? (f->fXi >0 ?f->fEXi /f->fXi :0) : f->fXi);
1379 Double_t sigma =(rel ? (f->fSigma >0 ?f->fESigma /f->fSigma :0) : f->fSigma);
1380 Int_t w =(rel ? used : f->FindMaxWeight());
1381 // Double_t sigman = (rel ? (f->fSigmaN>0 ?f->fESigmaN/f->fSigmaN :0)
1383 hChi ->SetBinContent(b, chi2nu);
1384 hN ->SetBinContent(b, w);
1385 hC ->SetBinContent(b, c);
1386 hDelta ->SetBinContent(b, delta);
1387 hXi ->SetBinContent(b, xi);
1388 hSigma ->SetBinContent(b, sigma);
1391 hC ->SetBinError(b, f->fEC);
1392 hDelta ->SetBinError(b, f->fEDelta);
1393 hXi ->SetBinError(b, f->fEXi);
1394 hSigma ->SetBinError(b, f->fESigma);
1395 // hSigmaN->SetBinError(b, f->fESigmaN);
1397 for (Int_t k = 0; k < f->fN-1 && k < maxN; k++) {
1398 Double_t a = (rel ? (f->fA[k] > 0 ? f->fEA[k] / f->fA[k] : 0) : f->fA[k]);
1399 hA[k]->SetBinContent(b, a);
1400 if (!rel) hA[k]->SetBinError(b, f->fEA[k]);
1404 //____________________________________________________________________
1406 AliFMDCorrELossFit::Draw(Option_t* option)
1412 // option Options. Possible values are
1413 // - err Plot error bars
1415 TString opt(Form("nostack %s", option));
1417 Bool_t rel = (opt.Contains("relative"));
1418 Bool_t err = (opt.Contains("error"));
1419 Bool_t clr = (opt.Contains("clear"));
1420 Bool_t gdd = (opt.Contains("good"));
1421 if (rel) opt.ReplaceAll("relative","");
1422 if (err) opt.ReplaceAll("error","");
1423 if (clr) opt.ReplaceAll("clear", "");
1424 if (gdd) opt.ReplaceAll("good", "");
1427 Int_t nRings = fRings.GetEntriesFast();
1428 for (Int_t i = 0; i < nRings; i++) {
1429 if (!fRings.At(i)) continue;
1430 TObjArray* a = static_cast<TObjArray*>(fRings.At(i));
1431 Int_t nFits = a->GetEntriesFast();
1433 for (Int_t j = 0; j < nFits; j++) {
1434 ELossFit* fit = static_cast<ELossFit*>(a->At(j));
1436 maxN = TMath::Max(maxN, UShort_t(fit->fN));
1439 // AliInfo(Form("Maximum N is %d", maxN));
1440 Int_t nPad = 6+maxN-1; // 7 regular params, and maxN-1 weights
1441 TVirtualPad* pad = gPad;
1444 pad->SetTopMargin(0.02);
1445 pad->SetRightMargin(0.02);
1446 pad->SetBottomMargin(0.15);
1447 pad->SetLeftMargin(0.10);
1449 pad->Divide(2, (nPad+1)/2, 0.1, 0, 0);
1451 TList* stacks = GetStacks(err, rel, gdd, maxN);
1453 Int_t nPad2 = (nPad+1) / 2;
1454 for (Int_t i = 0; i < nPad; i++) {
1455 Int_t iPad = 1 + i/nPad2 + 2 * (i % nPad2);
1456 TVirtualPad* p = pad->cd(iPad);
1457 p->SetLeftMargin(.15);
1462 if (rel && i != 0 && i != 6 && i != 5 && i != 4) p->SetLogy();
1465 THStack* stack = static_cast<THStack*>(stacks->At(i));
1466 if (!stack->GetHists() || stack->GetHists()->GetEntries() <= 0) {
1467 AliWarningF("No histograms in %s", stack->GetName());
1470 // Double_t powMax = TMath::Log10(max[i]);
1471 // Double_t powMin = min[i] <= 0 ? powMax : TMath::Log10(min[i]);
1472 // if (powMax-powMin > 2. && min[i] != 0) p->SetLogy();
1474 // stack->SetMinimum(min[i]);
1475 // stack->SetMaximum(max[i]);
1476 stack->Draw(opt.Data());
1478 TString tit(stack->GetTitle());
1479 if (rel && i != 0 && i != 5)
1480 tit = Form("#delta %s/%s", tit.Data(), tit.Data());
1481 TH1* hist = stack->GetHistogram();
1482 TAxis* yaxis = hist->GetYaxis();
1483 yaxis->SetTitle(tit.Data());
1484 yaxis->SetTitleSize(0.15);
1485 yaxis->SetLabelSize(0.08);
1486 yaxis->SetTitleOffset(0.35);
1487 yaxis->SetTitleFont(132);
1488 yaxis->SetLabelFont(132);
1489 yaxis->SetNdivisions(5);
1492 TAxis* xaxis = stack->GetHistogram()->GetXaxis();
1493 xaxis->SetTitle("#eta");
1494 xaxis->SetTitleSize(0.15);
1495 xaxis->SetLabelSize(0.08);
1496 xaxis->SetTitleOffset(0.35);
1497 xaxis->SetTitleFont(132);
1498 xaxis->SetLabelFont(132);
1499 xaxis->SetNdivisions(10);
1501 stack->Draw(opt.Data());
1506 //____________________________________________________________________
1508 AliFMDCorrELossFit::Print(Option_t* option) const
1511 // Print this object.
1515 // - R Print recursive
1518 TString opt(option);
1520 Int_t nRings = fRings.GetEntriesFast();
1521 bool recurse = opt.Contains("R");
1522 bool cache = opt.Contains("C") && fCache.GetSize() > 0;
1523 Int_t nBins = fEtaAxis.GetNbins();
1525 std::cout << "Low cut in fit range: " << fLowCut << "\n"
1526 << "Eta axis: " << nBins
1527 << " bins, range [" << fEtaAxis.GetXmin() << ","
1528 << fEtaAxis.GetXmax() << "]" << std::endl;
1530 for (Int_t i = 0; i < nRings; i++) {
1531 if (!fRings.At(i)) continue;
1532 TObjArray* a = static_cast<TObjArray*>(fRings.At(i));
1533 Int_t nFits = a->GetEntriesFast();
1535 std::cout << a->GetName() << " [" << nFits << " entries]"
1536 << (recurse ? ":\n" : "\t");
1537 Int_t min = fEtaAxis.GetNbins()+1;
1539 for (Int_t j = 0; j < nFits; j++) {
1540 if (!a->At(j)) continue;
1542 min = TMath::Min(j, min);
1543 max = TMath::Max(j, max);
1546 std::cout << "Bin # " << j << "\t";
1547 ELossFit* fit = static_cast<ELossFit*>(a->At(j));
1552 std::cout << " bin range: " << std::setw(3) << min
1553 << "-" << std::setw(3) << max << " " << std::setw(3)
1554 << (max-min+1) << " bins" << std::endl;
1559 std::cout << " eta bin | Fit bin \n"
1560 << " # range | FMD1i FMD2i FMD2o FMD3i FMD3o"
1561 // << "----+-----+++------+-----------------------------------"
1563 size_t oldPrec = std::cout.precision();
1564 std::cout.precision(3);
1565 for (Int_t i = 1; i <= nBins; i++) {
1566 std::cout << std::setw(4) << i << " "
1567 << std::setw(5) << std::showpos << fEtaAxis.GetBinLowEdge(i)
1568 << " - " << std::setw(5) << fEtaAxis.GetBinUpEdge(i)
1569 << std::noshowpos << " | ";
1570 for (Int_t j = 0; j < 5; j++) {
1571 Int_t bin = CACHE(i,j,nBins);
1572 if (bin <= 0) std::cout << " ";
1573 else std::cout << std::setw(5) << bin
1574 << (bin == i ? ' ' : '*') << ' ';
1576 std::cout << std::endl;
1578 std::cout.precision(oldPrec);
1581 //____________________________________________________________________
1583 AliFMDCorrELossFit::Browse(TBrowser* b)
1586 // Browse this object
1597 //____________________________________________________________________