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"
10 #include <TVirtualPad.h>
24 Double_t AliFMDCorrELossFit::ELossFit::fgMaxRelError = .25;
25 Double_t AliFMDCorrELossFit::ELossFit::fgLeastWeight = 1e-7;
26 Double_t AliFMDCorrELossFit::ELossFit::fgMaxChi2nu = 20;
28 //____________________________________________________________________
29 AliFMDCorrELossFit::ELossFit::ELossFit()
52 // Default constructor
56 //____________________________________________________________________
57 AliFMDCorrELossFit::ELossFit::ELossFit(Int_t quality, const TF1& f)
58 : fN(f.GetNpar() > AliForwardUtil::ELossFitter::kN ?
59 Int_t(f.GetParameter(AliForwardUtil::ELossFitter::kN)) :
62 fChi2(f.GetChisquare()),
63 fC(f.GetParameter(AliForwardUtil::ELossFitter::kC)),
64 fDelta(f.GetParameter(AliForwardUtil::ELossFitter::kDelta)),
65 fXi(f.GetParameter(AliForwardUtil::ELossFitter::kXi)),
66 fSigma(f.GetParameter(AliForwardUtil::ELossFitter::kSigma)),
67 fSigmaN(f.GetParameter(AliForwardUtil::ELossFitter::kSigmaN)),
69 fEC(f.GetParError(AliForwardUtil::ELossFitter::kC)),
70 fEDelta(f.GetParError(AliForwardUtil::ELossFitter::kDelta)),
71 fEXi(f.GetParError(AliForwardUtil::ELossFitter::kXi)),
72 fESigma(f.GetParError(AliForwardUtil::ELossFitter::kSigma)),
73 fESigmaN(f.GetParError(AliForwardUtil::ELossFitter::kSigmaN)),
82 // Construct from a function
85 // quality Quality flag
89 fA = new Double_t[fN];
90 fEA = new Double_t[fN];
91 for (Int_t i = 0; i < fN-1; i++) {
92 fA[i] = f.GetParameter(AliForwardUtil::ELossFitter::kA+i);
93 fEA[i] = f.GetParError(AliForwardUtil::ELossFitter::kA+i);
99 //____________________________________________________________________
100 AliFMDCorrELossFit::ELossFit::ELossFit(Int_t quality,UShort_t n,
101 Double_t chi2, UShort_t nu,
102 Double_t c, Double_t ec,
103 Double_t delta, Double_t edelta,
104 Double_t xi, Double_t exi,
105 Double_t sigma, Double_t esigma,
106 Double_t sigman, Double_t esigman,
107 const Double_t* a,const Double_t* ea)
130 // Constructor with full parameter set
133 // quality Quality flag
134 // n @f$ N@f$ - Number of fitted peaks
135 // chi2 @f$ \chi^2 @f$
136 // nu @f$ \nu @f$ - number degrees of freedom
137 // c @f$ C@f$ - scale constant
138 // ec @f$ \delta C@f$ - error on @f$ C@f$
139 // delta @f$ \Delta@f$ - Most probable value
140 // edelta @f$ \delta\Delta@f$ - error on @f$\Delta@f$
141 // xi @f$ \xi@f$ - width
142 // exi @f$ \delta\xi@f$ - error on @f$\xi@f$
143 // sigma @f$ \sigma@f$ - Width of Gaussian
144 // esigma @f$ \delta\sigma@f$ - error on @f$\sigma@f$
145 // sigman @f$ \sigma_n@f$ - Noise width
146 // esigman @f$ \delta\sigma_n@f$ - error on @f$\sigma_n@f$
147 // a Array of @f$ N-1@f$ weights @f$ a_i@f$ for
149 // ea Array of @f$ N-1@f$ error on the weights @f$ a_i@f$ for
153 fA = new Double_t[fN];
154 fEA = new Double_t[fN];
155 for (Int_t i = 0; i < fN-1; i++) {
162 //____________________________________________________________________
163 AliFMDCorrELossFit::ELossFit::ELossFit(const ELossFit& o)
178 fESigmaN(o.fESigmaN),
180 fQuality(o.fQuality),
184 fMaxWeight(o.fMaxWeight)
190 // o Object to copy from
193 fA = new Double_t[fN];
194 fEA = new Double_t[fN];
195 for (Int_t i = 0; i < fN-1; i++) {
203 //____________________________________________________________________
204 AliFMDCorrELossFit::ELossFit&
205 AliFMDCorrELossFit::ELossFit::operator=(const ELossFit& o)
208 // Assignment operator
211 // o Object to assign from
214 // Reference to this object
216 if (&o == this) return *this;
229 fESigmaN = o.fESigmaN;
230 fQuality = o.fQuality;
234 fMaxWeight = o.fMaxWeight;
235 if (fA) delete [] fA;
236 if (fEA) delete [] fEA;
240 if (fN <= 0) return *this;
241 fA = new Double_t[fN];
242 fEA = new Double_t[fN];
243 for (Int_t i = 0; i < fN; i++) {
251 //____________________________________________________________________
252 AliFMDCorrELossFit::ELossFit::~ELossFit()
255 if (fEA) delete[] fEA;
259 //____________________________________________________________________
261 AliFMDCorrELossFit::ELossFit::FindMaxWeight(Double_t maxRelError,
262 Double_t leastWeight,
266 // Find the maximum weight to use. The maximum weight is the
267 // largest i for which
269 // - @f$ i \leq \max{N}@f$
270 // - @f$ a_i > \min{a}@f$
271 // - @f$ \delta a_i/a_i > \delta_{max}@f$
274 // maxRelError @f$ \min{a}@f$
275 // leastWeight @f$ \delta_{max}@f$
276 // maxN @f$ \max{N}@f$
279 // The largest index @f$ i@f$ for which the above
280 // conditions hold. Will never return less than 1.
282 if (fMaxWeight > 0) return fMaxWeight;
283 Int_t n = TMath::Min(maxN, UShort_t(fN-1));
285 // fN is one larger than we have data
286 for (Int_t i = 0; i < n-1; i++, m++) {
287 if (fA[i] < leastWeight) break;
288 if (fEA[i] / fA[i] > maxRelError) break;
290 return fMaxWeight = m;
293 //____________________________________________________________________
295 AliFMDCorrELossFit::ELossFit::Evaluate(Double_t x,
301 // f_N(x;\Delta,\xi,\sigma') =
302 // \sum_{i=1}^{n} a_i f(x;\Delta_i,\xi_i,\sigma_i')
305 // (see AliForwardUtil::NLandauGaus) for the maximum @f$ N @f$
306 // that fulfills the requirements
309 // x Where to evaluate
310 // maxN @f$ \max{N}@f$
313 // @f$ f_N(x;\Delta,\xi,\sigma')@f$
315 return AliForwardUtil::NLandauGaus(x, fDelta, fXi, fSigma, fSigmaN,
316 TMath::Min(maxN, UShort_t(fN)), fA);
319 //____________________________________________________________________
321 AliFMDCorrELossFit::ELossFit::EvaluateWeighted(Double_t x,
327 // f_W(x;\Delta,\xi,\sigma') =
328 // \frac{\sum_{i=1}^{n} i a_i f_i(x;\Delta,\xi,\sigma')}{
329 // f_N(x;\Delta,\xi,\sigma')} =
330 // \frac{\sum_{i=1}^{n} i a_i f(x;\Delta_i,\xi_i,\sigma_i')}{
331 // \sum_{i=1}^{n} a_i f(x;\Delta_i,\xi_i,\sigma_i')}
333 // where @f$ n@f$ fulfills the requirements (see FindMaxWeight).
335 // If the denominator is zero, then 1 is returned.
337 // See also AliForwardUtil::ILandauGaus and AliForwardUtil::NLandauGaus
338 // for more information on the evaluated functions.
341 // x Where to evaluate
342 // maxN @f$ \max{N}@f$
345 // @f$ f_W(x;\Delta,\xi,\sigma')@f$.
347 UShort_t n = TMath::Min(maxN, UShort_t(fN-1));
350 for (Int_t i = 1; i <= n; i++) {
351 Double_t a = (i == 1 ? 1 : fA[i-1]);
352 if (fA[i-1] < 0) break;
353 Double_t f = AliForwardUtil::ILandauGaus(x,fDelta,fXi,fSigma,fSigmaN,i);
357 if (den <= 0) return 1;
362 #define OUTPAR(N,V,E) \
363 std::setprecision(9) << \
364 std::setw(12) << N << ": " << \
365 std::setw(14) << V << " +/- " << \
366 std::setw(14) << E << " (" << \
367 std::setprecision(-1) << \
368 std::setw(5) << 100*(V>0?E/V:1) << "%)\n"
371 //____________________________________________________________________
373 AliFMDCorrELossFit::ELossFit::Compare(const TObject* o) const
376 // Compare to another ELossFit object.
378 // - +1, if this quality is better (larger) than other objects quality
379 // - -1, if this quality is worse (smaller) than other objects quality
380 // - +1, if this @f$|\chi^2/\nu-1|@f$ is smaller than the same for other
381 // - -1, if this @f$|\chi^2/\nu-1|@f$ is larger than the same for other
385 // o Other object to compare to
387 const ELossFit* other = static_cast<const ELossFit*>(o);
388 if (this->fQuality < other->fQuality) return -1;
389 if (this->fQuality > other->fQuality) return +1;
390 Double_t chi2nu = (fNu == 0 ? 1000 : fChi2 / fNu);
391 Double_t oChi2nu = (other->fNu == 0 ? 1000 : other->fChi2 / other->fNu);
392 if (TMath::Abs(chi2nu-1) < TMath::Abs(oChi2nu-1)) return +1;
393 if (TMath::Abs(chi2nu-1) > TMath::Abs(oChi2nu-1)) return -1;
397 //____________________________________________________________________
399 AliFMDCorrELossFit::ELossFit::Print(Option_t* option) const
402 // Information to standard output
408 if (o.Contains("S", TString::kIgnoreCase)) {
409 Printf("%15s: q=%2d n=%1d chi2/nu=%6.3f",
410 GetName(), fQuality, fN, (fNu <= 0 ? 999 : fChi2 / fNu));
414 std::cout << GetName() << ":\n"
415 << " chi^2/nu = " << fChi2 << "/" << fNu << " = "
416 << (fNu == 0 ? 999 : fChi2 / fNu) << "\n"
417 << " Quality: " << fQuality << "\n"
418 << " NParticles: " << fN << " (" << FindMaxWeight() << ")\n"
419 << OUTPAR("Delta", fDelta, fEDelta)
420 << OUTPAR("xi", fXi, fEXi)
421 << OUTPAR("sigma", fSigma, fESigma)
422 << OUTPAR("sigma_n", fSigmaN, fESigmaN);
423 for (Int_t i = 0; i < fN-1; i++)
424 std::cout << OUTPAR(Form("a%d", i+2), fA[i], fEA[i]);
425 std::cout << std::flush;
427 //____________________________________________________________________
429 AliFMDCorrELossFit::ELossFit::GetF1(Int_t i, Double_t max) const
431 const Double_t lowX = 0.001;
432 const Double_t upX = (max < 0 ? 10 : max);
433 Int_t maxW = FindMaxWeight();
437 ret = AliForwardUtil::MakeNLandauGaus(fC * 1, fDelta, fXi,
438 fSigma, fSigmaN, maxW/*fN*/,
441 ret = AliForwardUtil::MakeILandauGaus(fC*(i == 1 ? 1 : fA[i-2]),
443 fSigma, fSigmaN, i, lowX, upX);
447 //____________________________________________________________________
449 AliFMDCorrELossFit::ELossFit::FindProbabilityCut(Double_t low) const
456 throw TString("Didn't TF1 object");
457 if (!(g = new TGraph(f, "i")))
458 throw TString("Failed to integrate function");
461 Double_t total = g->GetY()[n-1];
463 throw TString::Format("Invalid integral: %lf", total);
465 for (Int_t i = 0; i < n; i++) {
466 Double_t prob = g->GetY()[i] / total;
473 throw TString::Format("Couldn't find x value for cut %lf", low);
475 catch (const TString& str) {
476 AliWarningF("%s: %s", GetName(), str.Data());
484 //____________________________________________________________________
486 AliFMDCorrELossFit::ELossFit::GetName() const
489 // Get the name of this object
495 return Form("FMD%d%c_etabin%03d", fDet, fRing, fBin);
498 //____________________________________________________________________
500 AliFMDCorrELossFit::ELossFit::Browse(TBrowser* b)
503 // Browse this object
508 Draw(b ? b->GetDrawOption() : "comp values");
513 //____________________________________________________________________
515 AliFMDCorrELossFit::ELossFit::Draw(Option_t* option)
522 // - COMP Draw components too
530 if (opt.Contains("COMP")) {
531 opt.ReplaceAll("COMP","");
534 if (opt.Contains("GOOD")) {
535 opt.ReplaceAll("GOOD","");
538 if (opt.Contains("VALUES")) {
539 opt.ReplaceAll("VALUES","");
542 if (opt.Contains("LEGEND")) {
543 opt.ReplaceAll("LEGEND","");
546 if (!opt.Contains("SAME")) {
552 l = new TLegend(.3, .5, .59, .94);
558 Int_t maxW = FindMaxWeight();
559 TF1* tot = AliForwardUtil::MakeNLandauGaus(fC * 1,
564 tot->SetLineColor(kBlack);
565 tot->SetLineWidth(2);
566 tot->SetLineStyle(1);
567 tot->SetTitle(GetName());
568 if (l) l->AddEntry(tot, "Total", "l");
569 Double_t max = tot->GetMaximum();
572 if (!opt.Contains("SAME")) {
573 TH1* frame = new TH1F(GetName(),
574 Form("FMD%d%c, eta bin %d",fDet,fRing,fBin),
576 frame->SetMinimum(max/10000);
577 frame->SetMaximum(max*1.4);
578 frame->SetXTitle("#Delta / #Delta_{mip}");
582 TF1* cpy = tot->DrawCopy(opt.Data());
590 TLatex* ltx1 = new TLatex(x1, y, "");
591 TLatex* ltx2 = new TLatex(x2, y, "");
593 ltx1->SetTextAlign(33);
594 ltx1->SetTextFont(132);
595 ltx1->SetTextSize(dy-.01);
597 ltx2->SetTextAlign(13);
598 ltx2->SetTextFont(132);
599 ltx2->SetTextSize(dy-.01);
601 ltx1->DrawLatex(x1, y, "Quality");
602 ltx2->DrawLatex(x2, y, Form("%d", fQuality));
605 ltx1->DrawLatex(x1, y, "#chi^{2}/#nu");
606 ltx2->DrawLatex(x2, y, Form("%7.3f", (fNu > 0 ? fChi2 / fNu : -1)));
609 const Char_t* pn[] = { "C", "#Delta", "#xi", "#sigma" };
610 Double_t pv[] = { fC, fDelta, fXi, fSigma };
611 Double_t pe[] = { fEC, fEDelta, fEXi, fESigma };
612 for (Int_t i = 0; i < 4; i++) {
613 ltx1->DrawLatex(x1, y, pn[i]);
614 ltx2->DrawLatex(x2, y, Form("%6.4f#pm%6.4f", pv[i], pe[i]));
617 for (Int_t i=2; i <= fN; i++) {
619 ltx1->SetTextColor(kRed+3);
620 ltx2->SetTextColor(kRed+3);
622 ltx1->DrawLatex(x1, y, Form("a_{%d}", i));
623 ltx2->DrawLatex(x2, y, Form("%6.4f#pm%6.4f", fA[i-2], fEA[i-2]));
636 for (Int_t i=1; i <= fN; i++) {
637 if (good && i > maxW) break;
638 TF1* f = AliForwardUtil::MakeILandauGaus(fC*(i == 1 ? 1 : fA[i-2]),
643 f->SetLineStyle(i > maxW ? 2 : 1);
644 min = TMath::Min(f->GetMaximum(), min);
645 f->DrawCopy(opt.Data());
646 if (l) l->AddEntry(f, Form("%d MIP%s", i, (i>1 ? "s" : "")), "l");
651 if (max <= 0) max = 0.1;
652 if (min <= 0) min = 1e-4;
653 cpy->SetMaximum(max);
654 cpy->SetMinimum(min);
655 cpy->GetHistogram()->SetMaximum(max);
656 cpy->GetHistogram()->SetMinimum(min);
657 cpy->GetHistogram()->GetYaxis()->SetRangeUser(min, max);
664 //____________________________________________________________________
665 #define CHECKPAR(V,E,T) ((V > 0) && (E / V < T))
667 //____________________________________________________________________
669 AliFMDCorrELossFit::ELossFit::GetLowerBound(Double_t f) const
676 //____________________________________________________________________
678 AliFMDCorrELossFit::ELossFit::GetLowerBound(Double_t f,
679 Bool_t includeSigma) const
683 // Delta - f * (xi + sigma)
684 return fDelta - f * (fXi + (includeSigma ? fSigma : 0));
687 //____________________________________________________________________
689 AliFMDCorrELossFit::ELossFit::CalculateQuality(Double_t maxChi2nu,
690 Double_t maxRelError,
691 Double_t leastWeight)
694 // Calculate the quality
696 Double_t decline = maxChi2nu;
699 Double_t red = fChi2 / fNu;
700 if (red < maxChi2nu) qual += 4;
702 Int_t q = Int_t((maxChi2nu+decline - red) / decline * 4);
703 if (q > 0) qual += q;
706 if (CHECKPAR(fDelta, fEDelta, maxRelError)) qual++;
707 if (CHECKPAR(fXi, fEXi, maxRelError)) qual++;
708 if (CHECKPAR(fSigma, fESigma, maxRelError)) qual++;
709 if (CHECKPAR(fSigmaN, fESigmaN, maxRelError)) qual++;
710 // Large penalty for large sigma - often a bad fit.
711 if (fSigma > 10*fXi) qual -= 4;
712 qual += FindMaxWeight(2*maxRelError, leastWeight, fN);
716 //____________________________________________________________________
717 AliFMDCorrELossFit::AliFMDCorrELossFit()
725 // Default constructor
727 fRings.SetOwner(kTRUE);
728 fEtaAxis.SetTitle("#eta");
729 fEtaAxis.SetName("etaAxis");
730 fRings.SetName("rings");
733 //____________________________________________________________________
734 AliFMDCorrELossFit::AliFMDCorrELossFit(const AliFMDCorrELossFit& o)
737 fEtaAxis(o.fEtaAxis.GetNbins(),o.fEtaAxis.GetXmin(),o.fEtaAxis.GetXmax()),
745 // o Object to copy from
747 fEtaAxis.SetTitle("#eta");
748 fEtaAxis.SetName("etaAxis");
751 //____________________________________________________________________
752 AliFMDCorrELossFit::~AliFMDCorrELossFit()
760 //____________________________________________________________________
762 AliFMDCorrELossFit::operator=(const AliFMDCorrELossFit& o)
765 // Assignment operator
768 // o Object to assign from
771 // Reference to this object
773 if (&o == this) return *this;
777 SetEtaAxis(o.fEtaAxis.GetNbins(), o.fEtaAxis.GetXmin(), o.fEtaAxis.GetXmax());
781 #define CACHE(BIN,IDX,OFFSET) fCache[IDX*OFFSET+BIN-1]
783 //____________________________________________________________________
785 AliFMDCorrELossFit::CacheBins(UShort_t minQuality) const
787 if (fCache.GetSize() > 0) return;
789 Int_t nRings = fRings.GetEntriesFast();
790 Int_t offset = fEtaAxis.GetNbins();
792 fCache.Set(nRings*offset);
795 for (Int_t i = 0; i < nRings; i++) {
796 TObjArray* ringArray = static_cast<TObjArray*>(fRings.At(i));
798 // First loop to find where we actually have fits
801 Int_t minBin = offset+1;
803 Int_t realMinBin = offset+1;
804 Int_t realMaxBin = -1;
805 for (Int_t j = 1; j < ringArray->GetEntriesFast(); j++) {
806 ELossFit* fit = static_cast<ELossFit*>(ringArray->At(j));
810 // Update our range off possible fits
811 realMinBin = TMath::Min(j, realMinBin);
812 realMaxBin = TMath::Max(j, realMaxBin);
814 // Check the quality of the fit
815 fit->CalculateQuality(AliFMDCorrELossFit::ELossFit::fgMaxChi2nu,
816 AliFMDCorrELossFit::ELossFit::fgMaxRelError,
817 AliFMDCorrELossFit::ELossFit::fgLeastWeight);
818 if (minQuality > 0 && fit->fQuality < minQuality) continue;
822 CACHE(j,i,offset) = j;
823 minBin = TMath::Min(j, minBin);
824 maxBin = TMath::Max(j, maxBin);
826 AliInfoF("Out of %d bins, %d had fits, of which %d are good (%5.1f%%)",
827 offset, nFits, nGood, (nFits > 0 ? 100*float(nGood)/nFits : 0));
829 // Now loop and set neighbors
830 realMinBin = TMath::Max(1, realMinBin-1); // Include one more
831 realMaxBin = TMath::Min(offset, realMaxBin+1); // Include one more
832 for (Int_t j = realMinBin; j <= realMaxBin; j++) {
833 if (CACHE(j,i,offset) > 0) continue;
835 Int_t nK = TMath::Max(realMaxBin - j, j - realMinBin);
837 for (Int_t k = 1; k <= nK; k++) {
840 if (left > realMinBin &&
841 CACHE(left,i,offset) == left) found = left;
842 else if (right < realMaxBin &&
843 CACHE(right,i,offset) == right) found = right;
844 if (found > 0) break;
846 // Now check that we found something
847 if (found) CACHE(j,i,offset) = CACHE(found,i,offset);
848 else AliWarningF("No fit found for etabin=%d in ring=%d", j, i);
854 //____________________________________________________________________
856 AliFMDCorrELossFit::FindEtaBin(Double_t eta) const
859 // Find the eta bin corresponding to the given eta
865 // Bin (in @f$[1,N_{bins}]@f$) corresponding to the given
866 // eta, or 0 if out of range.
868 if (TMath::Abs(fEtaAxis.GetXmin() - fEtaAxis.GetXmax()) < 1e-6
869 || fEtaAxis.GetNbins() == 0) {
870 AliWarning("No eta axis defined");
873 Int_t bin = const_cast<TAxis&>(fEtaAxis).FindBin(eta);
874 if (bin <= 0 || bin > fEtaAxis.GetNbins()) return 0;
878 //____________________________________________________________________
880 AliFMDCorrELossFit::SetFit(UShort_t d, Char_t r, Int_t etaBin, ELossFit* fit)
883 // Set the fit parameters from a function
888 // etaBin Eta (bin number, 1->nBins)
889 // f ELoss fit result - note, the object will take ownership
891 TObjArray* ringArray = GetOrMakeRingArray(d, r);
893 AliError(Form("Failed to make ring array for FMD%d%c", d, r));
896 if (etaBin <= 0 || etaBin >= fEtaAxis.GetNbins()+1) {
897 AliError(Form("bin=%d is out of range [%d,%d]",
898 etaBin, 1, fEtaAxis.GetNbins()));
901 // AliInfo(Form("Adding fit %p at %3d", fit, etaBin));
902 ringArray->AddAtAndExpand(fit, etaBin);
906 //____________________________________________________________________
908 AliFMDCorrELossFit::SetFit(UShort_t d, Char_t r, Double_t eta, ELossFit* fit)
911 // Set the fit parameters from a function
917 // f ELoss fit result - note, the object will take ownership
919 Int_t bin = FindEtaBin(eta);
921 AliError(Form("eta=%f is out of range [%f,%f]",
922 eta, fEtaAxis.GetXmin(), fEtaAxis.GetXmax()));
926 return SetFit(d, r, bin, fit);
928 //____________________________________________________________________
930 AliFMDCorrELossFit::SetFit(UShort_t d, Char_t r,
932 Int_t quality,UShort_t n,
933 Double_t chi2, UShort_t nu,
934 Double_t c, Double_t ec,
935 Double_t delta, Double_t edelta,
936 Double_t xi, Double_t exi,
937 Double_t sigma, Double_t esigma,
938 Double_t sigman, Double_t esigman,
939 Double_t* a, Double_t* ea)
942 // Set the fit parameters from a function
948 // quality Quality flag
949 // n @f$ N@f$ - Number of fitted peaks
950 // chi2 @f$ \chi^2 @f$
951 // nu @f$ \nu @f$ - number degrees of freedom
952 // c @f$ C@f$ - scale constant
953 // ec @f$ \delta C@f$ - error on @f$ C@f$
954 // delta @f$ \Delta@f$ - most probable value
955 // edelta @f$ \delta\Delta@f$ - error on @f$\Delta@f$
956 // xi @f$ \xi@f$ - Landau width
957 // exi @f$ \delta\xi@f$ - error on @f$\xi@f$
958 // sigma @f$ \sigma@f$ - Gaussian width
959 // esigma @f$ \delta\sigma@f$ - error on @f$\sigma@f$
960 // sigman @f$ \sigma_n@f$ - Noise width
961 // esigman @f$ \delta\sigma_n@f$ - error on @f$\sigma_n@f$
962 // a Array of @f$ N-1@f$ weights @f$ a_i@f$ for
964 // ea Array of @f$ N-1@f$ errors on weights @f$ a_i@f$ for
967 ELossFit* e = new ELossFit(quality, n,
975 if (!SetFit(d, r, eta, e)) {
981 //____________________________________________________________________
983 AliFMDCorrELossFit::SetFit(UShort_t d, Char_t r, Double_t eta,
984 Int_t quality, const TF1& f)
987 // Set the fit parameters from a function
993 // quality Quality flag
994 // f Function from fit
996 ELossFit* e = new ELossFit(quality, f);
997 if (!SetFit(d, r, eta, e)) {
1003 //____________________________________________________________________
1004 AliFMDCorrELossFit::ELossFit*
1005 AliFMDCorrELossFit::GetFit(UShort_t d, Char_t r, Int_t etabin) const
1008 // Get the fit corresponding to the specified parameters
1013 // etabin Eta bin (1 based)
1016 // Fit parameters or null in case of problems
1018 TObjArray* ringArray = GetRingArray(d, r);
1019 if (!ringArray) return 0;
1020 if (etabin <= 0 || etabin >= fEtaAxis.GetNbins()) return 0;
1021 if (etabin > ringArray->GetEntriesFast()) return 0;
1022 else if (etabin >= ringArray->GetEntriesFast()) etabin--;
1023 else if (!ringArray->At(etabin)) etabin++;
1024 return static_cast<ELossFit*>(ringArray->At(etabin));
1026 //____________________________________________________________________
1027 AliFMDCorrELossFit::ELossFit*
1028 AliFMDCorrELossFit::GetFit(UShort_t d, Char_t r, Double_t eta) const
1031 // Find the fit corresponding to the specified parameters
1039 // Fit parameters or null in case of problems
1041 Int_t etabin = FindEtaBin(eta);
1042 return GetFit(d, r, etabin);
1045 //____________________________________________________________________
1046 AliFMDCorrELossFit::ELossFit*
1047 AliFMDCorrELossFit::FindFit(UShort_t d, Char_t r, Int_t etabin,
1048 UShort_t minQ) const
1051 // Find the fit corresponding to the specified parameters
1056 // etabin Eta bin (1 based)
1059 // Fit parameters or null in case of problems
1061 if (etabin <= 0 || etabin >= fEtaAxis.GetNbins()) {
1062 // AliError(Form("Eta bin=%3d out of bounds [%d,%d] for FMD%d%c",
1063 // etabin, 1, fEtaAxis.GetNbins(), d, r));
1067 TObjArray* ringArray = GetRingArray(d, r);
1069 AliError(Form("Failed to make ring array for FMD%d%c", d, r));
1072 DMSG(fDebug, 10, "Got ringArray %s for FMD%d%c", ringArray->GetName(), d, r);
1073 if (fCache.GetSize() <= 0) CacheBins(minQ);
1074 Int_t idx = (d == 1 ? 0 :
1075 (d - 2) * 2 + 1 + (r=='I' || r=='i' ? 0 : 1));
1076 Int_t bin = CACHE(etabin, idx, fEtaAxis.GetNbins());
1078 if (bin < 0 || bin > ringArray->GetEntriesFast()) return 0;
1080 return static_cast<ELossFit*>(ringArray->At(bin));
1082 //____________________________________________________________________
1083 AliFMDCorrELossFit::ELossFit*
1084 AliFMDCorrELossFit::FindFit(UShort_t d, Char_t r, Double_t eta,
1085 UShort_t minQ) const
1088 // Find the fit corresponding to the specified parameters
1096 // Fit parameters or null in case of problems
1098 Int_t etabin = FindEtaBin(eta);
1099 return FindFit(d, r, etabin, minQ);
1101 //____________________________________________________________________
1103 AliFMDCorrELossFit::GetRingArray(UShort_t d, Char_t r) const
1106 // Get the ring array corresponding to the specified ring
1113 // Pointer to ring array, or null in case of problems
1117 case 1: idx = 0; break;
1118 case 2: idx = (r == 'i' || r == 'I') ? 1 : 2; break;
1119 case 3: idx = (r == 'i' || r == 'I') ? 3 : 4; break;
1121 if (idx < 0 || idx >= fRings.GetEntriesFast()) return 0;
1122 return static_cast<TObjArray*>(fRings.At(idx));
1124 //____________________________________________________________________
1126 AliFMDCorrELossFit::GetOrMakeRingArray(UShort_t d, Char_t r)
1129 // Get the ring array corresponding to the specified ring
1136 // Pointer to ring array, or newly created container
1140 case 1: idx = 0; break;
1141 case 2: idx = (r == 'i' || r == 'I') ? 1 : 2; break;
1142 case 3: idx = (r == 'o' || r == 'I') ? 3 : 4; break;
1144 if (idx < 0) return 0;
1145 if (idx >= fRings.GetEntriesFast() || !fRings.At(idx)) {
1146 TObjArray* a = new TObjArray(0);
1147 // TOrdCollection* a = new TOrdCollection(fEtaAxis.GetNbins());
1148 a->SetName(Form("FMD%d%c", d, r));
1150 fRings.AddAtAndExpand(a, idx);
1152 return static_cast<TObjArray*>(fRings.At(idx));
1155 //____________________________________________________________________
1157 AliFMDCorrELossFit::GetLowerBound(UShort_t d, Char_t r, Int_t etabin,
1160 ELossFit* fit = FindFit(d, r, etabin, 20);
1161 if (!fit) return -1024;
1162 return fit->GetLowerBound(f);
1164 //____________________________________________________________________
1166 AliFMDCorrELossFit::GetLowerBound(UShort_t d, Char_t r, Double_t eta,
1169 Int_t bin = FindEtaBin(eta);
1170 if (bin <= 0) return -1024;
1171 return GetLowerBound(d, r, Int_t(bin), f);
1173 //____________________________________________________________________
1175 AliFMDCorrELossFit::GetLowerBound(UShort_t d, Char_t r, Int_t etabin,
1176 Double_t p, Bool_t) const
1178 DGUARD(fDebug, 10, "Get probability cut for FMD%d%c etabin=%d", d, r, etabin);
1179 ELossFit* fit = FindFit(d, r, etabin, 20);
1180 if (!fit) return -1024;
1181 return fit->FindProbabilityCut(p);
1183 //____________________________________________________________________
1185 AliFMDCorrELossFit::GetLowerBound(UShort_t d, Char_t r, Double_t eta,
1186 Double_t p, Bool_t dummy) const
1188 DGUARD(fDebug, 10, "Get probability cut for FMD%d%c eta=%8.4f", d, r, eta);
1189 Int_t bin = FindEtaBin(eta);
1190 DMSG(fDebug, 10, "bin=%4d", bin);
1191 if (bin <= 0) return -1024;
1192 return GetLowerBound(d, r, Int_t(bin), p, dummy);
1194 //____________________________________________________________________
1196 AliFMDCorrELossFit::GetLowerBound(UShort_t d, Char_t r, Int_t etabin,
1197 Double_t f, Bool_t showErrors,
1198 Bool_t includeSigma) const
1200 ELossFit* fit = FindFit(d, r, etabin, 20);
1203 AliWarning(Form("No fit for FMD%d%c @ etabin=%d", d, r, etabin));
1207 return fit->GetLowerBound(f, includeSigma);
1210 //____________________________________________________________________
1212 AliFMDCorrELossFit::GetLowerBound(UShort_t d, Char_t r, Double_t eta,
1213 Double_t f, Bool_t showErrors,
1214 Bool_t includeSigma) const
1216 Int_t bin = FindEtaBin(eta);
1219 AliError(Form("eta=%f out of bounds for FMD%d%c", eta, d, r));
1222 return GetLowerBound(d, r, bin, f, showErrors, includeSigma);
1225 //____________________________________________________________________
1227 TH1D* MakeHist(const TAxis& axis, const char* name, const char* title,
1230 TH1D* h = new TH1D(Form("%s_%s", name, title),
1231 Form("%s %s", name, title),
1232 axis.GetNbins(), axis.GetXmin(), axis.GetXmax());
1234 h->SetMarkerStyle(20);
1235 h->SetMarkerColor(color);
1236 h->SetMarkerSize(0.5);
1237 h->SetFillColor(color);
1238 h->SetFillStyle(3001);
1239 h->SetLineColor(color);
1246 #define IDX2RING(I) (i == 0 || i == 1 || i == 3 ? 'I' : 'O')
1247 #define IDX2DET(I) (i == 0 ? 1 : (i == 1 || i == 2 ? 2 : 3))
1248 //____________________________________________________________________
1250 AliFMDCorrELossFit::GetStacks(Bool_t err,
1253 UShort_t maxN) const
1255 // Get a list of THStacks
1256 Int_t nRings = fRings.GetEntriesFast();
1257 // Int_t nPad = 6+maxN-1; // 7 regular params, and maxN-1 weights
1275 TList* stacks = new TList;
1276 stacks->AddAt(sChi2nu= new THStack("chi2", "#chi^{2}/#nu"), kChi2nu);
1277 stacks->AddAt(sC = new THStack("c", "C"), kC);
1278 stacks->AddAt(sDelta = new THStack("delta", "#Delta_{mp}"), kDelta);
1279 stacks->AddAt(sXi = new THStack("xi", "#xi"), kXi);
1280 stacks->AddAt(sSigma = new THStack("sigma", "#sigma"), kSigma);
1281 //stacks->AddAt(sigman= new THStack("sigman", "#sigma_{n}"), 5);
1282 stacks->AddAt(n = new THStack("n", "N"), kN);
1284 sChi2nu->SetName("qual");
1285 sChi2nu->SetTitle("Quality");
1287 n->SetTitle("Bin map");
1289 for (Int_t i = 1; i <= maxN; i++) {
1290 stacks->AddAt(new THStack(Form("a_%02d", i+1), Form("a_{%d}", i+1)), kN+i);
1293 // TArrayD min(nPad);
1294 // TArrayD max(nPad);
1295 // min.Reset(100000);
1296 // max.Reset(-100000);
1298 for (Int_t i = 0; i < nRings; i++) {
1299 if (!fRings.At(i)) continue;
1300 TObjArray* a = static_cast<TObjArray*>(fRings.At(i));
1301 Int_t nFits = a->GetEntriesFast();
1302 Int_t color = AliForwardUtil::RingColor(IDX2DET(i), IDX2RING(i));
1304 TH1D* hChi = MakeHist(fEtaAxis,a->GetName(), "chi2", color);
1305 TH1D* hC = MakeHist(fEtaAxis,a->GetName(), "c", color);
1306 TH1D* hDelta = MakeHist(fEtaAxis,a->GetName(), "delta", color);
1307 TH1D* hXi = MakeHist(fEtaAxis,a->GetName(), "xi", color);
1308 TH1D* hSigma = MakeHist(fEtaAxis,a->GetName(), "sigma", color);
1309 // TH1D* hSigmaN = MakeHist(fEtaAxis,a->GetName(), "sigman", color);
1310 TH1D* hN = MakeHist(fEtaAxis,a->GetName(), "n", color);
1312 const char* ho = (rel || !err ? "hist" : "e");
1313 sChi2nu->Add(hChi, "hist"); // 0
1314 sC ->Add(hC, ho); // 1
1315 sDelta ->Add(hDelta, ho); // 2
1316 sXi ->Add(hXi, ho); // 3
1317 sSigma ->Add(hSigma, ho); // 4
1318 // sigman->Add(hSigmaN,ho); // 5
1319 n ->Add(hN, "hist"); // 5
1320 hChi->SetFillColor(color);
1321 hChi->SetFillStyle(3001);
1322 hN->SetFillColor(color);
1323 hN->SetFillStyle(3001);
1325 for (Int_t k = 1; k <= maxN; k++) {
1326 hA[k-1] = MakeHist(fEtaAxis,a->GetName(), Form("a%02d",k+1), color);
1327 static_cast<THStack*>(stacks->At(kN+k))->Add(hA[k-1], ho);
1330 for (Int_t j = 0; j < nFits; j++) {
1331 ELossFit* f = static_cast<ELossFit*>(a->At(j));
1335 Double_t vChi2nu = (rel ? f->fQuality
1336 : (f->fNu <= 0 ? 0 : f->fChi2 / f->fNu));
1337 Double_t vC = (rel ? (f->fC >0 ?f->fEC /f->fC :0)
1339 Double_t vDelta = (rel ? (f->fDelta >0 ?f->fEDelta /f->fDelta :0)
1341 Double_t vXi = (rel ? (f->fXi >0 ?f->fEXi /f->fXi :0)
1343 Double_t vSigma = (rel ? (f->fSigma >0 ?f->fESigma /f->fSigma :0)
1345 Int_t nW = (rel ? CACHE(j,i,fEtaAxis.GetNbins()) :
1346 f->FindMaxWeight());
1347 // Double_t sigman = (rel ? (f->fSigmaN>0 ?f->fESigmaN/f->fSigmaN :0)
1349 hChi ->SetBinContent(b, vChi2nu);
1350 hN ->SetBinContent(b, nW);
1351 hC ->SetBinContent(b, vC);
1352 hDelta ->SetBinContent(b, vDelta);
1353 hXi ->SetBinContent(b, vXi);
1354 hSigma ->SetBinContent(b, vSigma);
1355 // if (vChi2nu > 1e-12) {
1356 // min[kChi2nu] = TMath::Min(min[kChi2nu], vChi2nu);
1357 // max[kChi2nu] = TMath::Max(max[kChi2nu], vChi2nu);
1359 // if (vC > 1e-12) {
1360 // min[kC] = TMath::Min(min[kC], vC);
1361 // max[kC] = TMath::Max(max[kC], vC);
1363 // if (vDelta > 1e-12) {
1364 // min[kDelta] = TMath::Min(min[kDelta], vDelta);
1365 // max[kDelta] = TMath::Max(max[kDelta], vDelta);
1367 // if (vXi > 1e-12) {
1368 // min[kXi] = TMath::Min(min[kXi], vXi);
1369 // max[kXi] = TMath::Max(max[kXi], vXi);
1371 // if (vSigma > 1e-12) {
1372 // min[kSigma] = TMath::Min(min[kSigma], vSigma);
1373 // max[kSigma] = TMath::Max(max[kSigma], vSigma);
1375 // if (nW > 1e-12) {
1376 // min[kN] = TMath::Min(min[kN], Double_t(nW));
1377 // max[kN] = TMath::Max(max[kN], Double_t(nW));
1379 // hSigmaN->SetBinContent(b, sigman);
1381 hC ->SetBinError(b, f->fEC);
1382 hDelta ->SetBinError(b, f->fEDelta);
1383 hXi ->SetBinError(b, f->fEXi);
1384 hSigma ->SetBinError(b, f->fESigma);
1385 // hSigmaN->SetBinError(b, f->fESigmaN);
1387 for (Int_t k = 0; k < f->fN-1 && k < maxN; k++) {
1388 Double_t vA = (rel ? (f->fA[k] > 0 ? f->fEA[k] / f->fA[k] : 0)
1390 hA[k]->SetBinContent(b, vA);
1391 if (!rel) hA[k]->SetBinError(b, f->fEA[k]);
1392 // if (vA > 1e-12) {
1393 // min[kN+1+k] = TMath::Min(min[kN+1+k], vA);
1394 // max[kN+1+k] = TMath::Max(max[kN+1+k], vA);
1402 //____________________________________________________________________
1404 AliFMDCorrELossFit::Draw(Option_t* option)
1410 // option Options. Possible values are
1411 // - err Plot error bars
1413 TString opt(Form("nostack %s", option));
1415 Bool_t rel = (opt.Contains("relative"));
1416 Bool_t err = (opt.Contains("error"));
1417 Bool_t clr = (opt.Contains("clear"));
1418 Bool_t gdd = (opt.Contains("good"));
1419 if (rel) opt.ReplaceAll("relative","");
1420 if (err) opt.ReplaceAll("error","");
1421 if (clr) opt.ReplaceAll("clear", "");
1422 if (gdd) opt.ReplaceAll("good", "");
1425 Int_t nRings = fRings.GetEntriesFast();
1426 for (Int_t i = 0; i < nRings; i++) {
1427 if (!fRings.At(i)) continue;
1428 TObjArray* a = static_cast<TObjArray*>(fRings.At(i));
1429 Int_t nFits = a->GetEntriesFast();
1431 for (Int_t j = 0; j < nFits; j++) {
1432 ELossFit* fit = static_cast<ELossFit*>(a->At(j));
1434 maxN = TMath::Max(maxN, UShort_t(fit->fN));
1437 // AliInfo(Form("Maximum N is %d", maxN));
1438 Int_t nPad = 6+maxN-1; // 7 regular params, and maxN-1 weights
1439 TVirtualPad* pad = gPad;
1442 pad->SetTopMargin(0.02);
1443 pad->SetRightMargin(0.02);
1444 pad->SetBottomMargin(0.15);
1445 pad->SetLeftMargin(0.10);
1447 pad->Divide(2, (nPad+1)/2, 0.1, 0, 0);
1449 TList* stacks = GetStacks(err, rel, gdd, maxN);
1451 Int_t nPad2 = (nPad+1) / 2;
1452 for (Int_t i = 0; i < nPad; i++) {
1453 Int_t iPad = 1 + i/nPad2 + 2 * (i % nPad2);
1454 TVirtualPad* p = pad->cd(iPad);
1455 p->SetLeftMargin(.15);
1460 if (rel && i != 0 && i != 6 && i != 5 && i != 4) p->SetLogy();
1463 THStack* stack = static_cast<THStack*>(stacks->At(i));
1465 // Double_t powMax = TMath::Log10(max[i]);
1466 // Double_t powMin = min[i] <= 0 ? powMax : TMath::Log10(min[i]);
1467 // if (powMax-powMin > 2. && min[i] != 0) p->SetLogy();
1469 // stack->SetMinimum(min[i]);
1470 // stack->SetMaximum(max[i]);
1471 stack->Draw(opt.Data());
1473 TString tit(stack->GetTitle());
1474 if (rel && i != 0 && i != 5)
1475 tit = Form("#delta %s/%s", tit.Data(), tit.Data());
1476 TH1* hist = stack->GetHistogram();
1477 TAxis* yaxis = hist->GetYaxis();
1478 yaxis->SetTitle(tit.Data());
1479 yaxis->SetTitleSize(0.15);
1480 yaxis->SetLabelSize(0.08);
1481 yaxis->SetTitleOffset(0.35);
1482 yaxis->SetTitleFont(132);
1483 yaxis->SetLabelFont(132);
1484 yaxis->SetNdivisions(5);
1487 TAxis* xaxis = stack->GetHistogram()->GetXaxis();
1488 xaxis->SetTitle("#eta");
1489 xaxis->SetTitleSize(0.15);
1490 xaxis->SetLabelSize(0.08);
1491 xaxis->SetTitleOffset(0.35);
1492 xaxis->SetTitleFont(132);
1493 xaxis->SetLabelFont(132);
1494 xaxis->SetNdivisions(10);
1496 stack->Draw(opt.Data());
1501 //____________________________________________________________________
1503 AliFMDCorrELossFit::Print(Option_t* option) const
1506 // Print this object.
1510 // - R Print recursive
1513 TString opt(option);
1515 Int_t nRings = fRings.GetEntriesFast();
1516 bool recurse = opt.Contains("R");
1517 bool cache = opt.Contains("C") && fCache.GetSize() > 0;
1518 Int_t nBins = fEtaAxis.GetNbins();
1520 std::cout << "Low cut in fit range: " << fLowCut << "\n"
1521 << "Eta axis: " << nBins
1522 << " bins, range [" << fEtaAxis.GetXmin() << ","
1523 << fEtaAxis.GetXmax() << "]" << std::endl;
1525 for (Int_t i = 0; i < nRings; i++) {
1526 if (!fRings.At(i)) continue;
1527 TObjArray* a = static_cast<TObjArray*>(fRings.At(i));
1528 Int_t nFits = a->GetEntriesFast();
1530 std::cout << a->GetName() << " [" << nFits << " entries]"
1531 << (recurse ? ":\n" : "\t");
1532 Int_t min = fEtaAxis.GetNbins()+1;
1534 for (Int_t j = 0; j < nFits; j++) {
1535 if (!a->At(j)) continue;
1537 min = TMath::Min(j, min);
1538 max = TMath::Max(j, max);
1541 std::cout << "Bin # " << j << "\t";
1542 ELossFit* fit = static_cast<ELossFit*>(a->At(j));
1547 std::cout << " bin range: " << std::setw(3) << min
1548 << "-" << std::setw(3) << max << " " << std::setw(3)
1549 << (max-min+1) << " bins" << std::endl;
1554 std::cout << " eta bin | Fit bin \n"
1555 << " # range | FMD1i FMD2i FMD2o FMD3i FMD3o"
1556 // << "----+-----+++------+-----------------------------------"
1558 size_t oldPrec = std::cout.precision();
1559 std::cout.precision(3);
1560 for (Int_t i = 1; i <= nBins; i++) {
1561 std::cout << std::setw(4) << i << " "
1562 << std::setw(5) << std::showpos << fEtaAxis.GetBinLowEdge(i)
1563 << " - " << std::setw(5) << fEtaAxis.GetBinUpEdge(i)
1564 << std::noshowpos << " | ";
1565 for (Int_t j = 0; j < 5; j++) {
1566 Int_t bin = CACHE(i,j,nBins);
1567 if (bin <= 0) std::cout << " ";
1568 else std::cout << std::setw(5) << bin
1569 << (bin == i ? ' ' : '*') << ' ';
1571 std::cout << std::endl;
1573 std::cout.precision(oldPrec);
1576 //____________________________________________________________________
1578 AliFMDCorrELossFit::Browse(TBrowser* b)
1581 // Browse this object
1592 //____________________________________________________________________