2 * @file UnfoldMultDists.C
3 * @author Christian Holm Christensen <cholm@nbi.dk>
4 * @date Tue Nov 12 09:25:52 2013
6 * @brief A class to do unfolding
9 * @ingroup pwglf_forward_multdist
17 #include <TLegendEntry.h>
21 #include <TParameter.h>
22 #include <TMultiGraph.h>
23 #include <TGraphAsymmErrors.h>
24 #include "RooUnfold.h"
25 #include "RooUnfoldResponse.h"
29 * Class to do unfolding of raw histograms produced by AliForwardMultDists
31 * @ingroup pwglf_forward_multdist
40 kColorMeasured = kOrange-2,
41 kColorTruth = kBlue-3,
42 kColorAccepted = kMagenta-3,
43 kColorTrgVtx = kBlack,
44 kColorUnfolded = kOrange+2,
45 kColorCorrected= kRed+2,
46 kColorError = kBlue-10,
47 kColorALICE = kPink+1,
56 * Get a top collection from a file
58 * @param fileName Name of file
59 * @param results Wheter it's the results collection or not
61 * @return Collection or null
63 static TCollection* GetTop(const TString& fileName, Bool_t results=false)
65 TFile* file = TFile::Open(fileName, "READ");
67 Error("GetTop", "Failed to open %s", fileName.Data());
71 TString cName(Form("ForwardMult%s", results ? "Results" : "Sums"));
72 file->GetObject(cName, ret);
74 Error("GetTop", "Failed to get collection %s from %s",
75 cName.Data(), fileName.Data());
80 * Get an object from a collection
83 * @param name Name of object
84 * @param cl Possible class to check against
85 * @param verbose Be verbose
87 * @return Pointer to object or null
89 static TObject* GetObject(TCollection* c, const TString& name,
90 TClass* cl, Bool_t verbose=true)
92 TObject* o = c->FindObject(name);
95 Warning("GetObject", "%s not found in %s", name.Data(), c->GetName());
98 if (cl && !o->IsA()->InheritsFrom(cl)) {
100 Warning("GetCollection", "%s is not a %s but a %s",
101 name.Data(), cl->GetName(), o->ClassName());
109 * @param c Parent collection
110 * @param name Name of object to findf
111 * @param verbose Be verbose
115 static TCollection* GetCollection(TCollection* c,
117 Bool_t verbose=-true)
119 return static_cast<TCollection*>(GetObject(c, name,
120 TCollection::Class(),
124 * Get a 1D histogram from a collection
126 * @param c Collection
127 * @param name Nanme of histogram
128 * @param verbose Be verbose
130 * @return Pointer to object or null
132 static TH1* GetH1(TCollection* c, const TString& name, Bool_t verbose=true)
134 return static_cast<TH1*>(GetObject(c, name, TH1::Class(), verbose));
137 * Get a 2D histogram from a collection
139 * @param c Collection
140 * @param name Nanme of histogram
141 * @param verbose Be verbose
143 * @return Pointer to object or null
145 static TH2* GetH2(TCollection* c, const TString& name, Bool_t verbose=true)
147 return static_cast<TH2*>(GetObject(c, name, TH2::Class(), verbose));
150 * Get an unsigned short parameter from the collection
152 * @param c Collection
153 * @param name Parameter name
158 static void GetParameter(TCollection* c, const TString& name, UShort_t& v)
160 TObject* o = GetObject(c, name, TParameter<int>::Class(), true);
161 v = (!o ? 0 : o->GetUniqueID());
164 * Get an unsigned short parameter from the collection
166 * @param c Collection
167 * @param name Parameter name
172 static void GetParameter(TCollection* c, const TString& name, ULong_t& v)
174 TObject* o = GetObject(c, name, TParameter<long>::Class(), true);
175 v = (!o ? 0 : o->GetUniqueID());
178 * Get an unsigned short parameter from the collection
180 * @param c Collection
181 * @param name Parameter name
186 static void GetParameter(TCollection* c, const TString& name, Double_t& v)
188 TObject* o = GetObject(c, name, TParameter<double>::Class(), true);
189 v = (!o ? 0 : static_cast<TParameter<double>*>(o)->GetVal());
192 * Get the method identifier
194 * @param method Method
196 * @return Method identifier
198 static UInt_t MethodId(TString& method)
204 const Method methods[] = { {RooUnfold::kNone, "None"},
205 {RooUnfold::kBayes, "Bayes"},
206 {RooUnfold::kSVD, "SVD"},
207 {RooUnfold::kBinByBin,"BinByBin"},
208 {RooUnfold::kTUnfold, "TUnfold"},
209 {RooUnfold::kInvert, "Invert"},
210 {RooUnfold::kDagostini,"Dagostini"},
211 {0xDeadBeef, "unknown"} };
212 const Method* pMethod = methods;
213 while (pMethod->id != 0xDeadBeef) {
214 if (method.BeginsWith(pMethod->name, TString::kIgnoreCase)) {
215 method = pMethod->name;
220 if (pMethod->id == 0xDeadBeef)
221 Error("MethodId", "Unknown unfolding method: %s", method.Data());
227 * Run the unfolding and correction task.
229 * The @a measuredFile is assumed to have the structure
232 * /- ForwardMultSums (TCollection)
233 * |- [type] (TCollection)
234 * | |- [bin] (TCollection)
235 * | | `- rawDist (TH1)
242 * and @a corrFile is assumed to have the structure
245 * /- ForwardMultResults (TCollection)
246 * |- [type] (TCollection)
247 * | |- [bin] (TCollection)
249 * | | |- truthAccepted (TH1)
250 * | | |- triggerVertex (TH1)
251 * | | `- response (TH2)
258 * where @c [type] is one of <i>symmetric</i>, <i>positive</i>,
259 * <i>negative</i>, or <i>other</i>, and [bin] is the @f$ \eta@f$
263 * [bin] := [eta_spec] _ [eta_spec]
264 * [eta_spec] := [sign_char] [integer_part] d [decimal_part]
265 * [sign_part] := p positive eta
267 * [integer_part] := [number]
268 * [decimal_part] := [number] [number]
269 * [number] := 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
272 * That is, the bin @f$ -3\le\eta\ge3@f$ is labeled
273 * <b>m3d00_p3d00</b>, @f$ 0\le\eta\ge2.5@f$ is <b>p0d00_p2d50</b>
275 * @a measuredFile and @a corrFile can point to the same file. If
276 * @a corrFile is not specified, it is assumed that @a measuredFile
277 * has the expected @a corrFile @e in @e addition to the
278 * expected content of that file.
280 * @param measuredFile Name of file containing measured data
281 * @param corrFile Name of file containing correction data
282 * @param method Unfolding method to use
283 * @param regParam Regularization parameter
285 void Run(const TString& measuredFile, const TString& corrFile,
286 const TString& method="Bayes", Double_t regParam=4)
288 // Get the input collections
289 if (measuredFile.IsNull()) {
290 Error("Run", "No measurements given");
293 TCollection* mTop = GetTop(measuredFile, false);
294 TCollection* cTop = GetTop(corrFile.IsNull() ? measuredFile : corrFile,
296 if (!mTop || !cTop) return;
298 // Get some info from the input collection
304 GetParameter(mTop, "sys", sys);
305 GetParameter(mTop, "sNN", sNN);
306 GetParameter(mTop, "trigger", trig);
307 GetParameter(mTop, "minIpZ", minZ);
308 GetParameter(mTop, "maxIpZ", maxZ);
309 if (sys == 0 || sNN == 0)
310 Warning("Run", "System (%d) and/or collision energy (%d) unknown",
313 // Open the output file
314 TFile* out = TFile::Open("forward_unfolded.root", "RECREATE");
316 Error("Run", "Failed to open output file");
320 // Decode method option and store in file
321 TString meth(method);
322 UInt_t mId = MethodId(meth);
323 if (mId == 0xDeadBeef) return;
326 SaveInformation(out,meth,mId,regParam,sys,sNN,trig,minZ,maxZ,
330 TString savPath(gROOT->GetMacroPath());
331 gROOT->SetMacroPath(Form("%s:$(ALICE_ROOT)/PWGLF/FORWARD/analysis2/scripts",
332 gROOT->GetMacroPath()));
334 if (!gROOT->GetClass("OtherPNch"))
335 gROOT->LoadMacro("OtherPNchData.C++");
336 gROOT->SetMacroPath(savPath);
338 // Loop over the input
339 const char* inputs[] = { "symmetric", "positive", "negative", 0 };
340 const char** pinput = inputs;
342 TCollection* mInput = GetCollection(mTop, *pinput, false);
343 TCollection* cInput = GetCollection(cTop, *pinput, false);
344 if (mInput && cInput)
345 ProcessType(mInput, cInput, mId, regParam, out,
357 * Append an & to a string and the next term.
359 * @param trg Output string
362 static void AppendAnd(TString& trg, const TString& what)
364 if (!trg.IsNull()) trg.Append(" & ");
368 * Store some information on the output
370 * @param dir Where to store
371 * @param method Method used
372 * @param mId Method identifier
373 * @param regParam Regularization parameter
374 * @param sys Collision system
375 * @param sNN Center of mass energy
376 * @param trigger Trigger mask
377 * @param minIpZ Least z coordinate of interaction point
378 * @param maxIpZ Largest z coordinate of interaction point
379 * @param self Self-consistency check
381 void SaveInformation(TDirectory* dir,
382 const TString& method,
394 TParameter<bool>* pM = new TParameter<bool>("self", self);
398 TNamed* outMeth = new TNamed("method", method.Data());
399 outMeth->SetUniqueID(mId);
402 TParameter<double>* pR = new TParameter<double>("regParam", regParam);
406 TString tS = (sys == 1 ? "pp" : sys == 2 ? "PbPb" : sys == 3 ? "pPb" : "?");
407 TNamed* pS = new TNamed("sys", tS.Data()); pS->SetUniqueID(sys);
411 if (sNN < 1000) tE = Form("%dGeV", sNN);
412 else if (sNN < 3000) tE = Form("%4.2fTeV", float(sNN)/1000);
413 else tE = Form("%dTeV", sNN/1000);
414 TNamed* pE = new TNamed("sNN", tE.Data()); pE->SetUniqueID(sNN);
419 * Bits of the trigger pattern
422 /** In-elastic collision */
424 /** In-elastic collision with at least one SPD tracklet */
426 /** Non-single diffractive collision */
428 /** Empty bunch crossing */
430 /** A-side trigger */
432 /** B(arrel) trigger */
434 /** C-side trigger */
438 /** pileup from SPD */
440 /** true NSD from MC */
442 /** Offline MB triggered */
444 /** At least one SPD cluster */
445 kNClusterGt0 = 0x1000,
446 /** V0-AND trigger */
448 /** Satellite event */
451 if ((trigger & kInel) != 0x0) AppendAnd(tT, "INEL");
452 if ((trigger & kInelGt0) != 0x0) AppendAnd(tT, "INEL>0");
453 if ((trigger & kNSD) != 0x0) AppendAnd(tT, "NSD");
454 if ((trigger & kV0AND) != 0x0) AppendAnd(tT, "V0AND");
455 if ((trigger & kA) != 0x0) AppendAnd(tT, "A");
456 if ((trigger & kB) != 0x0) AppendAnd(tT, "B");
457 if ((trigger & kC) != 0x0) AppendAnd(tT, "C");
458 if ((trigger & kE) != 0x0) AppendAnd(tT, "E");
459 if ((trigger & kMCNSD) != 0x0) AppendAnd(tT, "MCNSD");
460 if ((trigger & kNClusterGt0) != 0x0) AppendAnd(tT, "NCluster>0");
461 if ((trigger & kSatellite) != 0x0) AppendAnd(tT, "Satellite");
462 TNamed* pT = new TNamed("trigger", tT.Data()); pT->SetUniqueID(trigger);
465 TParameter<double>* pY = new TParameter<double>("minIpZ", minIpZ);
469 TParameter<double>* pZ = new TParameter<double>("maxIpZ", maxIpZ);
474 * Save a script to do a summary of this step
479 std::ofstream f("SummarizeUnfold.C");
480 f << "void SummarizeUnfold(const char* file=\"forward_unfolded.root\")\n"
482 << " const char* fwd=\"$ALICE_ROOT/PWGLF/FORWARD/analysis2\";\n"
483 << " gROOT->LoadMacro(Form(\"%s/DrawUnfoldedSummary.C\",fwd));\n"
484 << " DrawUnfoldedSummary(file);\n"
486 << "// EOF" << std::endl;
490 * Process a single type - i.e., one of <i>symmetric</i>,
491 * <i>positive</i>, <i>negative</i>, or <i>other</i> - by looping
492 * over all contained objects and call ProcessBin for each found
495 * @param measured Input collection of measured data
496 * @param corrections Input collection of correction data
497 * @param method Unfolding method to use
498 * @param regParam Regularisation parameter
499 * @param out Output directory.
500 * @param sys Collision system
501 * @param sNN Collision energy
503 void ProcessType(TCollection* measured,
504 TCollection* corrections,
511 Printf(" Processing %s ...", measured->GetName());
512 TDirectory* dir = out->mkdir(measured->GetName());
514 // Make some summary stacks
515 THStack* allMeasured = new THStack("measured",
516 "Measured P(#it{N}_{ch})");
517 THStack* allTruth = new THStack("truth",
518 "MC 'truth' P(#it{N}_{ch})");
519 THStack* allTruthA = new THStack("truthAccepted",
520 "MC 'truth' accepted P(#it{N}_{ch})");
521 THStack* allUnfolded = new THStack("unfolded",
522 "Unfolded P(#it{N}_{ch})");
523 THStack* allCorrected = new THStack("corrected",
524 "Corrected P(#it{N}_{ch})");
525 THStack* allRatio = (sys != 1 ? 0 :
526 new THStack("ratios", "Ratios to other"));
527 TMultiGraph* allALICE = (sys != 1 ? 0 :
528 new TMultiGraph("alice", "ALICE Published"));
529 TMultiGraph* allCMS = (sys != 1 ? 0 :
530 new TMultiGraph("cms", "CMS Published"));
532 // Loop over the list of objects.
533 static TRegexp regex("[pm][0-9]d[0-9]*_[pm][0-9]d[0-9]*");
534 TIter next(measured);
537 Double_t r = regParam;
538 while ((o = next())) {
539 // Go back to where we where
542 // if not a collection, don't bother
543 if (!o->IsA()->InheritsFrom(TCollection::Class())) continue;
545 // If it doesn't match our regular expression, don't bother
546 TString n(o->GetName());
547 if (n.Index(regex) == kNPOS) {
548 // Warning("ScanType", "%s in %s doesn't match eta range regexp",
549 // n.Data(), real->GetName());
552 TCollection* mBin = static_cast<TCollection*>(o);
553 TCollection* cBin = GetCollection(corrections, n.Data());
556 THStack* binS = ProcessBin(mBin, cBin, method, r, dir);
560 Bin2Stack(binS, i, allMeasured, allTruth, allTruthA,
561 allUnfolded, allCorrected, result);
565 Other2Stack(o->GetName(), i, sNN, allALICE, allCMS, alice, cms);
566 Ratio2Stack(i, result, alice, cms, allRatio);
569 dir->Add(allMeasured);
572 dir->Add(allUnfolded);
573 dir->Add(allCorrected);
574 if (allALICE && allALICE->GetListOfGraphs()) {
575 if (allALICE->GetListOfGraphs()->GetEntries() > 0)
580 if (allCMS && allCMS->GetListOfGraphs()) {
581 if (allCMS->GetListOfGraphs()->GetEntries() > 0)
586 if (allRatio && allRatio->GetHists()) {
587 if (allRatio->GetHists()->GetEntries() > 0)
594 * Process a single eta bin
596 * @param measured Input collection of measured data
597 * @param corrections Input collection of correction data
598 * @param method Unfolding method to use
599 * @param regParam Regularisation parameter
600 * @param out Output directory.
602 * @return Stack of histograms or null
604 THStack* ProcessBin(TCollection* measured,
605 TCollection* corrections,
610 Printf(" Processing %s ...", measured->GetName());
611 // Try to get the data
612 TH1* inRaw = GetH1(measured, "rawDist");
613 TH1* inTruth = GetH1(corrections, "truth");
614 TH1* inTruthA = GetH1(corrections, "truthAccepted");
615 TH1* inTrgVtx = GetH1(corrections, "triggerVertex");
616 TH2* inResp = GetH2(corrections, "response");
617 if (!inRaw || !inTruth || !inTruthA || !inTrgVtx || !inResp)
620 // Make output directory
621 TDirectory* dir = out->mkdir(measured->GetName());
624 // Copy the input to the output
625 TH1* outRaw = static_cast<TH1*>(inRaw ->Clone("measured"));
626 TH1* outTruth = static_cast<TH1*>(inTruth ->Clone("truth"));
627 TH1* outTruthA = static_cast<TH1*>(inTruthA ->Clone("truthAccepted"));
628 TH1* outTrgVtx = static_cast<TH1*>(inTrgVtx ->Clone("triggerVertex"));
629 TH2* outResp = static_cast<TH2*>(inResp ->Clone("response"));
631 // Make our response matrix
632 RooUnfoldResponse matrix(0, 0, inResp);
634 // Store regularization parameter
635 Double_t r = regParam;
636 RooUnfold::Algorithm algo = (RooUnfold::Algorithm)method;
637 RooUnfold* unfolder = RooUnfold::New(algo, &matrix, inRaw, r);
638 unfolder->SetVerbose(0);
640 // Do the unfolding and get the result
641 TH1* res = unfolder->Hreco();
642 res->SetDirectory(0);
644 // Make a copy to store on the output
645 TH1* outUnfold = static_cast<TH1*>(res->Clone("unfolded"));
646 TString tit(outUnfold->GetTitle());
647 tit.ReplaceAll("Unfold Reponse matrix", "Unfolded P(#it{N}_{ch})");
648 outUnfold->SetTitle(tit);
650 // Clone the unfolded results and divide by the trigger/vertex
652 TH1* outCorr = static_cast<TH1*>(outUnfold->Clone("corrected"));
653 outCorr->Divide(inTrgVtx);
654 tit.ReplaceAll("Unfolded", "Corrected");
655 outCorr->SetTitle(tit);
657 // Now normalize the output to integral=1
658 TH1* hists[] = { outRaw, outUnfold, outCorr, 0 };
663 Double_t intg = h->Integral(1, h->GetXaxis()->GetXmax());
664 h->Scale(1. / intg, "width");
670 TH1* ratioTrue = static_cast<TH1*>(outCorr->Clone("ratioCorrTruth"));
671 tit = ratioTrue->GetTitle();
672 tit.ReplaceAll("Corrected", "Corrected/MC 'truth'");
673 ratioTrue->SetTitle(tit);
674 ratioTrue->Divide(outTruth);
675 ratioTrue->SetYTitle("P_{corrected}(#it{N}_{ch})/P_{truth}(#it{N}_{ch})");
677 TH1* ratioAcc = static_cast<TH1*>(outUnfold->Clone("ratioUnfAcc"));
678 tit = ratioAcc->GetTitle();
679 tit.ReplaceAll("Unfolded", "Unfolded/MC selected");
680 ratioAcc->SetTitle(tit);
681 ratioAcc->Divide(outTruthA);
682 ratioAcc->SetYTitle("P_{unfolded}(#it{N}_{ch})/P_{MC}(#it{N}_{ch})");
686 tit = measured->GetName();
687 tit.ReplaceAll("m", "-");
688 tit.ReplaceAll("p", "+");
689 tit.ReplaceAll("d", ".");
690 tit.ReplaceAll("_", "<#it{#eta}<");
691 THStack* stack = new THStack("all", tit);
692 stack->Add(outTruth, "E2");
693 stack->Add(outTruthA, "E2");
694 stack->Add(outRaw, "E1");
695 stack->Add(outUnfold, "E1");
696 stack->Add(outCorr, "E1");
699 // Rest of the function is devoted to making the output look nice
700 outRaw ->SetDirectory(dir);
701 outTruth ->SetDirectory(dir);
702 outTruthA->SetDirectory(dir);
703 outTrgVtx->SetDirectory(dir);
704 outResp ->SetDirectory(dir);
705 outUnfold->SetDirectory(dir);
706 outCorr ->SetDirectory(dir);
708 outRaw ->SetMarkerStyle(20); // Measured is closed
709 outTruth ->SetMarkerStyle(24); // MC is open
710 outTruthA->SetMarkerStyle(24); // MC is open
711 outTrgVtx->SetMarkerStyle(20); // Derived is closed
712 outUnfold->SetMarkerStyle(20); // Derived is closed
713 outCorr ->SetMarkerStyle(20); // Derived is closed
715 outRaw ->SetMarkerSize(0.9);
716 outTruth ->SetMarkerSize(1.6);
717 outTruthA->SetMarkerSize(1.4);
718 outTrgVtx->SetMarkerSize(1.0);
719 outUnfold->SetMarkerSize(0.9);
720 outCorr ->SetMarkerSize(1.0);
722 outRaw ->SetMarkerColor(kColorMeasured);
723 outTruth ->SetMarkerColor(kColorTruth);
724 outTruthA->SetMarkerColor(kColorAccepted);
725 outTrgVtx->SetMarkerColor(kColorTrgVtx);
726 outUnfold->SetMarkerColor(kColorUnfolded);
727 outCorr ->SetMarkerColor(kColorCorrected);
729 outRaw ->SetFillColor(kColorError);
730 outTruth ->SetFillColor(kColorError);
731 outTruthA->SetFillColor(kColorError);
732 outTrgVtx->SetFillColor(kColorError);
733 outUnfold->SetFillColor(kColorError);
734 outCorr ->SetFillColor(kColorError);
736 outRaw ->SetFillStyle(0);
737 outTruth ->SetFillStyle(1001);
738 outTruthA->SetFillStyle(1001);
739 outTrgVtx->SetFillStyle(0);
740 outUnfold->SetFillStyle(0);
741 outCorr ->SetFillStyle(0);
743 outRaw ->SetLineColor(kBlack);
744 outTruth ->SetLineColor(kBlack);
745 outTruthA->SetLineColor(kBlack);
746 outTrgVtx->SetLineColor(kBlack);
747 outUnfold->SetLineColor(kBlack);
748 outCorr ->SetLineColor(kBlack);
751 TLegend* l = StackLegend(stack);
752 l->AddEntry(outRaw, "Raw", "lp");
753 l->AddEntry(outTruth, "MC 'truth'", "fp");
754 l->AddEntry(outTruthA, "MC 'truth' accepted", "fp");
755 l->AddEntry(outUnfold, "Unfolded", "lp");
756 l->AddEntry(outCorr, "Corrected", "lp");
760 static void BinAttributes(Int_t i,
766 // --- Setup for markers -----------------------------------------
767 const Int_t nMarkers = 7;
768 const Int_t aClosed[] = { 20, 21, 22, 23, 29, 33, 34 };
769 const Int_t aOpen[] = { 24, 25, 26, 32, 30, 27, 28 };
770 const Float_t aSize[] = { 1.1, 1.0, 1.2, 1.2, 1.2, 1.2, 1.0 };
771 Int_t j = i % nMarkers;
776 factor = TMath::Power(10, i);
779 * Add the bin histograms to our summary stacks
781 * @param bin Bin stack
782 * @param i Current off-set in the stacks
783 * @param measured All measured @f$ P(N_{ch})@f$
784 * @param truth All MC truth @f$ P(N_{ch})@f$
785 * @param accepted All MC accepted @f$ P(N_{ch})@f$
786 * @param unfolded All unfolded @f$ P(N_{ch})@f$
787 * @param corrected All corrected @f$ P(N_{ch})@f$
788 * @param result The result in this bin
790 void Bin2Stack(const THStack* bin, Int_t i,
801 BinAttributes(i, open, closed, size, factor);
803 TIter next(bin->GetHists());
805 while ((h = static_cast<TH1*>(next()))) {
807 Int_t col = h->GetMarkerColor();
810 case kColorMeasured: tmp = measured; sty = closed; break;
811 case kColorTruth: tmp = truth; sty = open; break;
812 case kColorAccepted: tmp = accepted; sty = open; break;
813 case kColorUnfolded: tmp = unfolded; sty = closed; break;
814 case kColorCorrected: tmp = corrected; sty = closed; break;
817 // Now clone, and add to the appropriate stack
818 TH1* cln = static_cast<TH1*>(h->Clone(h->GetName()));
819 cln->SetDirectory(0);
820 cln->SetMarkerStyle(sty);
821 cln->SetMarkerSize(size);
822 cln->Scale(factor); // Scale by 10^i
823 if (col == kColorCorrected) result = cln;
825 // Make sure we do not get the old legend
826 TObject* tst = cln->FindObject("legend");
827 if (tst) cln->GetListOfFunctions()->Remove(tst);
829 tmp->Add(cln, next.GetOption());
832 // Add entries to our stacks
833 TString txt = bin->GetTitle();
834 if (i == 0) txt.Append(" (#times1)");
835 else if (i == 1) txt.Append(" (#times10)");
836 else txt.Append(Form(" (#times10^{%d})", i));
837 THStack* stacks[] = { measured, truth, accepted, unfolded, corrected, 0 };
838 THStack** pstack = stacks;
840 TLegend* leg = StackLegend(*pstack);
845 TLegendEntry* e = leg->AddEntry(dummy, txt, "p");
846 e->SetMarkerStyle(closed);
847 e->SetMarkerSize(1.2*size);
848 e->SetMarkerColor(kBlack);
851 e->SetLineColor(kBlack);
855 * Add distributions from other experiments to stacks
857 * @param name Name of current bin
858 * @param i Index of current bin
859 * @param sNN Center of mass energy
860 * @param allALICE Stack of ALICE data
861 * @param allCMS Stack of CMS data
862 * @param alice Possible ALICE result on return
863 * @param cms Possible CMS result on return
865 void Other2Stack(const TString& name, Int_t i,
866 UShort_t sNN, TMultiGraph* allALICE, TMultiGraph* allCMS,
867 TGraph*& alice, TGraph*& cms)
869 if (!allALICE && !allCMS) return;
872 tmp.ReplaceAll("p", "+");
873 tmp.ReplaceAll("m", "-");
874 tmp.ReplaceAll("_", " ");
875 tmp.ReplaceAll("d", ".");
876 TObjArray* tokens = tmp.Tokenize(" ");
877 if (!tokens || tokens->GetEntriesFast() < 2) {
878 Error("Other2Stack", "Failed to decode eta range from %s", name.Data());
879 if (tokens) tokens->Delete();
882 Double_t eta1 = static_cast<TObjString*>(tokens->At(0))->String().Atof();
883 Double_t eta2 = static_cast<TObjString*>(tokens->At(1))->String().Atof();
886 if (TMath::Abs(eta2+eta1) > 1e-3) {
888 // Info("Other2Stack", "bin [%f,%f] is not symmetric (%f)",
889 // eta1, eta2, TMath::Abs(eta2-eta1));
892 Double_t aEta = TMath::Abs(eta1);
897 BinAttributes(i, open, closed, size, factor);
900 TGraphAsymmErrors* g = GetOther(1, aEta, sNN, factor);
902 g->SetMarkerStyle(closed);
903 g->SetMarkerColor(kColorALICE);
904 g->SetMarkerSize(size);
905 allALICE->Add(g, "p same");
910 TGraphAsymmErrors* g = GetOther(0, aEta, sNN, factor);
912 g->SetMarkerStyle(closed);
913 g->SetMarkerColor(kColorCMS);
914 g->SetMarkerSize(size);
915 allCMS->Add(g, "p same");
921 * Create ratios to other data
923 * @param ib Bin number
925 * @param alice ALICE result if any
926 * @param cms CMS result if any
927 * @param all Stack to add ratio to
929 void Ratio2Stack(Int_t ib, TH1* res, TGraph* alice, TGraph* cms, THStack* all)
931 if (!all || !res || !(alice || cms)) return;
934 TGraph* gs[] = { (alice ? alice : cms), (alice ? cms : 0), 0 };
938 const char* n = (g == alice ? "ALICE" : "CMS");
940 TH1* r = static_cast<TH1*>(res->Clone(Form("ratio%s", n)));
941 TString tit(r->GetTitle());
942 tit.ReplaceAll("Corrected", Form("Ratio to %s", n));
944 r->SetMarkerColor(g->GetMarkerColor());
945 r->SetLineColor(g->GetLineColor());
947 TObject* tst = r->FindObject("legend");
948 if (tst) r->GetListOfFunctions()->Remove(tst);
950 for (Int_t i = 1; i <= r->GetNbinsX(); i++) {
951 Double_t c = r->GetBinContent(i);
952 Double_t e = r->GetBinError(i);
953 Double_t o = g->Eval(r->GetBinCenter(i));
955 r->SetBinContent(i, 0);
956 r->SetBinError(i, 0);
959 r->SetBinContent(i, (c - o) / o + off);
960 r->SetBinError(i, e / o);
965 TLegend* leg = StackLegend(all);
968 TString txt = res->GetTitle();
969 txt.ReplaceAll("Corrected P(#it{N}_{ch}) in ", "");
970 if (ib == 0) txt.Append(" "); // (#times1)");
971 // else if (ib == 1) txt.Append(" (#times10)");
972 else txt.Append(Form(" (+%d)", off));
975 TLegendEntry* e = leg->AddEntry(dummy, txt, "p");
976 e->SetMarkerStyle(res->GetMarkerStyle());
977 e->SetMarkerSize(res->GetMarkerSize());
978 e->SetMarkerColor(kBlack);
981 e->SetLineColor(kBlack);
985 * Get or create a stack legend. This is done by adding a TLegend
986 * object to the list of functions for the first histogram in the
989 * @param stack Stack to get the legend from/modify
991 * @return The legend object or null
993 TLegend* StackLegend(THStack* stack)
995 TList* hists = stack->GetHists();
996 if (!hists) return 0;
998 TObject* first = hists->First();
999 if (!first) return 0;
1001 TH1* hist = static_cast<TH1*>(first);
1002 TList* list = hist->GetListOfFunctions();
1003 TObject* o = list->FindObject("legend");
1004 if (o) return static_cast<TLegend*>(o);
1006 TLegend* l = new TLegend(0.65, 0.65, 0.9, 0.9, "", "NDC");
1007 l->SetName("legend");
1008 l->SetBorderSize(0);
1017 /* =================================================================
1019 * Measurements from other sources, such as published ALICE, CMS, ...
1021 TGraphAsymmErrors* GetOther(UShort_t type, Double_t eta, UShort_t sNN,
1024 TString oC = Form("OtherPNch::GetData(%hu,%f,%hu);",
1026 TGraphAsymmErrors* g =
1027 reinterpret_cast<TGraphAsymmErrors*>(gROOT->ProcessLine(oC));
1029 // Warning("GetOther", "No other data found for type=%d eta=%f sNN=%d",
1035 for (Int_t j = 0; j < g->GetN(); j++) {
1036 g->SetPoint(j, g->GetX()[j], g->GetY()[j]*factor);
1037 g->SetPointError(j, g->GetEXlow()[j], g->GetEXhigh()[j],
1038 g->GetEYlow()[j]*factor, g->GetEYhigh()[j]*factor);
1045 UnfoldMultDists(const TString& method="Bayes",
1046 Double_t regParam=1e-30,
1047 const TString& measured="forward_multdists.root",
1048 const TString& corrections="")
1051 m.Run(measured, corrections, method, regParam);