]> git.uio.no Git - u/mrichter/AliRoot.git/blame - PWGLF/FORWARD/analysis2/DrawdNdeta.C
Updates for better drawings
[u/mrichter/AliRoot.git] / PWGLF / FORWARD / analysis2 / DrawdNdeta.C
CommitLineData
e1f47419 1/**
ffca499d 2 * @file DrawdNdeta.C
3 * @author Christian Holm Christensen <cholm@dalsgaard.hehi.nbi.dk>
4 * @date Wed Mar 23 14:07:10 2011
5 *
5bb5d1f6 6 * @brief Script to visualise the dN/deta for pp and PbPb
e1f47419 7 *
ffca499d 8 * This script is independent of any AliROOT code - and should stay
9 * that way.
10 *
970b1a8a 11 * The script is <i>very</i> long - sigh - the joy of drawing
5bb5d1f6 12 * things nicely in ROOT
ffca499d 13 *
bd6f5206 14 * @ingroup pwglf_forward_dndeta
e1f47419 15 */
b2e7f2d6 16#include <TH1.h>
f709afcf 17#include <TColor.h>
b2e7f2d6 18#include <THStack.h>
19#include <TGraphErrors.h>
20#include <TGraphAsymmErrors.h>
21#include <TMultiGraph.h>
22#include <TFile.h>
23#include <TList.h>
24#include <TString.h>
25#include <TError.h>
26#include <TSystem.h>
27#include <TROOT.h>
28#include <TMath.h>
29#include <TCanvas.h>
30#include <TPad.h>
31#include <TStyle.h>
32#include <TLegend.h>
33#include <TLegendEntry.h>
34#include <TLatex.h>
35#include <TImage.h>
33ab4a11 36#include <TRandom.h>
37#include <fstream>
298a7264 38#include <iostream>
290052e7 39/** Systematic error color */
37079f20 40#define SYSERR_COLOR kBlue-10
290052e7 41/** Systematic error style */
37079f20 42#define SYSERR_STYLE 1001
b2e7f2d6 43
797161e8 44Double_t myFunc(Double_t* xp, Double_t* pp);
45
2f92ff0e 46/**
47 * Class to draw dN/deta results
48 *
bd6f5206 49 * @ingroup pwglf_forward_tasks_dndeta
50 * @ingroup pwglf_forward_dndeta
2f92ff0e 51 */
b2e7f2d6 52struct dNdetaDrawer
53{
2f92ff0e 54 /**
55 * POD of data for range zooming
56 */
b2e7f2d6 57 struct RangeParam
58 {
59 TAxis* fMasterAxis; // Master axis
60 TAxis* fSlave1Axis; // First slave axis
61 TVirtualPad* fSlave1Pad; // First slave pad
62 TAxis* fSlave2Axis; // Second slave axis
63 TVirtualPad* fSlave2Pad; // Second slave pad
64 };
65 //__________________________________________________________________
2f92ff0e 66 /**
67 * Constructor
68 *
69 */
b2e7f2d6 70 dNdetaDrawer()
33ab4a11 71 : // Options
72 fShowRatios(false), // Show ratios
73 fShowLeftRight(false), // Show asymmetry
74 fShowRings(false), // Show rings too
75 fExport(false), // Export data to script
76 fCutEdges(false), // Whether to cut edges
77 fRemoveOuters(false), // Whether to remove outers
78 fShowOthers(0), // Show other data
298a7264 79 fMirror(false),
80 fForceMB(false),
33ab4a11 81 // Settings
82 fRebin(0), // Rebinning factor
83 fFwdSysErr(0.076), // Systematic error in forward range
84 fCenSysErr(0), // Systematic error in central range
85 fTitle(""), // Title on plot
86 fClusterScale(""), // Scaling of clusters to tracklets
87 // Read (or set) information
88 fTrigString(0), // Trigger string (read, or set)
89 fNormString(0), // Normalisation string (read, or set)
90 fSNNString(0), // Energy string (read, or set)
91 fSysString(0), // Collision system string (read or set)
92 fVtxAxis(0), // Vertex cuts (read or set)
93 fCentAxis(0), // Centrality axis
94 // Resulting plots
95 fResults(0), // Stack of results
96 fRatios(0), // Stack of ratios
97 fLeftRight(0), // Left-right asymmetry
98 fOthers(0), // Older data
99 fTriggers(0), // Number of triggers
100 fTruth(0), // Pointer to truth
101 fRangeParam(0) // Parameter object for range zoom
b2e7f2d6 102 {
103 fRangeParam = new RangeParam;
104 fRangeParam->fMasterAxis = 0;
105 fRangeParam->fSlave1Axis = 0;
106 fRangeParam->fSlave1Pad = 0;
107 fRangeParam->fSlave2Axis = 0;
108 fRangeParam->fSlave2Pad = 0;
109 }
290052e7 110 /**
111 * Cpoy constructor
112 */
33ab4a11 113 dNdetaDrawer(const dNdetaDrawer&) {}
290052e7 114 /**
115 * Assignment operator
116 *
117 *
118 * @return Reference to this object
119 */
33ab4a11 120 dNdetaDrawer& operator=(const dNdetaDrawer&) { return *this; }
121
ffca499d 122 //__________________________________________________________________
290052e7 123 /**
124 * Destructor
125 */
ffca499d 126 virtual ~dNdetaDrawer()
127 {
128 if (fRatios && fRatios->GetHists()) fRatios->GetHists()->Delete();
129 if (fResults && fResults->GetHists()) fResults->GetHists()->Delete();
130
131 if (fTrigString) { delete fTrigString; fTrigString = 0; }
132 if (fSNNString) { delete fSNNString; fSNNString = 0; }
133 if (fSysString) { delete fSysString; fSysString = 0; }
134 if (fVtxAxis) { delete fVtxAxis; fVtxAxis = 0; }
135 if (fCentAxis) { delete fCentAxis; fCentAxis = 0; }
136 if (fResults) { delete fResults; fResults = 0; }
137 if (fRatios) { delete fRatios; fRatios = 0; }
138 if (fOthers) { delete fOthers; fOthers = 0; }
139 if (fTriggers) { delete fTriggers; fTriggers = 0; }
140 fRangeParam = 0;
141 }
142
2f92ff0e 143 //==================================================================
144 /**
145 * @{
146 * @name Set parameters
147 */
148 /**
149 * Show other (UA5, CMS, ...) data
150 *
151 * @param x Whether to show or not
152 */
797161e8 153 void SetShowOthers(UShort_t x) { fShowOthers = x; }
2f92ff0e 154 //__________________________________________________________________
2f92ff0e 155 /**
156 * Whether to show ratios or not. If there's nothing to compare to,
157 * the ratio panel will be implicitly disabled
158 *
159 * @param x Whether to show or not
160 */
b2e7f2d6 161 void SetShowRatios(Bool_t x) { fShowRatios = x; }
2f92ff0e 162 //__________________________________________________________________
163 /**
164 *
165 * Whether to show the left/right asymmetry
166 *
167 * @param x To show or not
168 */
b2e7f2d6 169 void SetShowLeftRight(Bool_t x) { fShowLeftRight = x; }
797161e8 170 //__________________________________________________________________
171 /**
172 * Whether to show rings
173 *
174 * @param x To show or not
175 */
f709afcf 176 void SetShowRings(Bool_t x) { fShowRings = x; }
2f92ff0e 177 //__________________________________________________________________
33ab4a11 178 /**
179 * Whether to export results to a script
180 *
181 * @param x Wheter to export results to a script
182 */
183 void SetExport(Bool_t x) { fExport = x; }
184 //__________________________________________________________________
2f92ff0e 185 /**
186 * Set the rebinning factor
187 *
188 * @param x Rebinning factor (must be a divisor in the number of bins)
189 */
b2e7f2d6 190 void SetRebin(UShort_t x) { fRebin = x; }
2f92ff0e 191 //__________________________________________________________________
192 /**
193 * Wheter to cut away the edges
194 *
195 * @param x Whether or not to cut away edges
196 */
b2e7f2d6 197 void SetCutEdges(Bool_t x) { fCutEdges = x; }
2f92ff0e 198 //__________________________________________________________________
199 /**
200 * Set the title of the plot
201 *
202 * @param x Title
203 */
b2e7f2d6 204 void SetTitle(TString x) { fTitle = x; }
797161e8 205 //__________________________________________________________________
206 /**
207 * Set the systematic error in the forward region
208 *
209 * @param e Systematic error in the forward region
210 */
211 void SetForwardSysError(Double_t e=0) { fFwdSysErr = e; }
212 //__________________________________________________________________
213 /**
214 * Set the systematic error in the forward region
215 *
216 * @param e Systematic error in the forward region
217 */
218 void SetCentralSysError(Double_t e=0) { fCenSysErr = e; }
298a7264 219 void SetForceMB(Bool_t force=true) { fForceMB = force; }
220 void SetMirror(Bool_t mirror=true) { fMirror = mirror; }
2f92ff0e 221 /* @} */
222 //==================================================================
223 /**
224 * @{
225 * @name Override settings from input
226 */
227 /**
228 * Override setting from file
229 *
230 * @param sNN Center of mass energy per nucleon pair (GeV)
231 */
232 void SetSNN(UShort_t sNN)
233 {
cdb9e20f 234 fSNNString = new TNamed("sNN", Form("%04dGeV", sNN));
2f92ff0e 235 fSNNString->SetUniqueID(sNN);
236 }
237 //__________________________________________________________________
238 /**
239 * Set the collision system
240 * - 1: pp
241 * - 2: PbPb
242 *
243 * @param sys collision system
244 */
245 void SetSys(UShort_t sys)
246 {
fe52e455 247 fSysString = new TNamed("sys", (sys == 1 ? "pp" :
4d97b4bb 248 sys == 2 ? "PbPb" :
249 sys == 3 ? "pPb" :
250 "unknown"));
fe52e455 251 fSysString->SetUniqueID(sys);
2f92ff0e 252 }
253 //__________________________________________________________________
254 /**
255 * Set the vertex range in centimeters
256 *
257 * @param vzMin Min @f$ v_z@f$
258 * @param vzMax Max @f$ v_z@f$
259 */
260 void SetVertexRange(Double_t vzMin, Double_t vzMax)
261 {
262 fVtxAxis = new TAxis(10, vzMin, vzMax);
263 fVtxAxis->SetName("vtxAxis");
264 fVtxAxis->SetTitle(Form("v_{z}#in[%+5.1f,%+5.1f]cm", vzMin, vzMax));
265 }
b2e7f2d6 266 //__________________________________________________________________
2f92ff0e 267 void SetTrigger(UShort_t trig)
268 {
269 fTrigString = new TNamed("trigString", (trig & 0x1 ? "INEL" :
270 trig & 0x2 ? "INEL>0" :
271 trig & 0x4 ? "NSD" :
272 "unknown"));
273 fTrigString->SetUniqueID(trig);
274 }
275
276
277 //==================================================================
278 /**
279 * @{
280 * @name Main steering functions
281 */
282 /**
283 * Run the code to produce the final result.
284 *
285 * @param filename File containing the data
286 */
e308a636 287 void Run(const char* filename="forward_dndeta.root")
b2e7f2d6 288 {
e308a636 289 Double_t max = 0, rmax=0, amax=0;
b2e7f2d6 290
e308a636 291 gStyle->SetPalette(1);
e1f47419 292
e308a636 293 // --- Open input file -------------------------------------------
294 TFile* file = TFile::Open(filename, "READ");
295 if (!file) {
296 Error("Open", "Cannot open %s", filename);
297 return;
298 }
299 // --- Get forward list ------------------------------------------
300 TList* forward = static_cast<TList*>(file->Get("ForwardResults"));
301 if (!forward) {
302 Error("Open", "Couldn't find list ForwardResults");
303 return;
304 }
305 // --- Get information on the run --------------------------------
306 FetchInformation(forward);
307 // --- Set the macro pathand load other data script --------------
bd6f5206 308 gROOT->SetMacroPath(Form("%s:$(ALICE_ROOT)/PWGLF/FORWARD/analysis2",
e308a636 309 gROOT->GetMacroPath()));
310 gROOT->LoadMacro("OtherData.C");
311
312 // --- Get the central results -----------------------------------
313 TList* clusters = static_cast<TList*>(file->Get("CentralResults"));
314 if (!clusters) Warning("Open", "Couldn't find list CentralResults");
b2e7f2d6 315
9ecab72f 316 // --- Get the central results -----------------------------------
317 TList* mcTruth = static_cast<TList*>(file->Get("MCTruthResults"));
318 if (!mcTruth) Warning("Open", "Couldn't find list MCTruthResults");
319
e308a636 320 // --- Make our containtes ---------------------------------------
321 fResults = new THStack("results", "Results");
322 fRatios = new THStack("ratios", "Ratios");
323 fLeftRight = new THStack("asymmetry", "Left-right asymmetry");
324 fOthers = new TMultiGraph();
b2e7f2d6 325
e308a636 326 // --- Loop over input data --------------------------------------
cd3b3781 327 TObjArray truths;
328 /*TObjArray* mcA =*/ FetchResults(mcTruth, "MCTruth", max, rmax, amax,truths);
329 TObjArray* fwdA = FetchResults(forward, "Forward", max, rmax, amax,truths);
330 TObjArray* cenA = FetchResults(clusters, "Central", max, rmax, amax,truths);
b2e7f2d6 331
e308a636 332 // --- Get trigger information -----------------------------------
333 TList* sums = static_cast<TList*>(file->Get("ForwardSums"));
334 if (sums) {
335 TList* all = static_cast<TList*>(sums->FindObject("all"));
336 if (all) {
337 fTriggers = FetchResult(all, "triggers");
338 if (!fTriggers) all->ls();
339 }
340 else {
341 Warning("Run", "List all not found in ForwardSums");
342 sums->ls();
343 }
344 }
345 else {
346 Warning("Run", "No ForwardSums directory found in %s", file->GetName());
347 file->ls();
348 }
349
350 // --- Check our stacks ------------------------------------------
351 if (!fResults->GetHists() ||
352 fResults->GetHists()->GetEntries() <= 0) {
353 Error("Run", "No histograms in result stack!");
354 return;
355 }
356 if (!fOthers->GetListOfGraphs() ||
357 fOthers->GetListOfGraphs()->GetEntries() <= 0) {
358 Warning("Run", "No other data found - disabling that");
797161e8 359 fShowOthers = 0;
e308a636 360 }
361 if (!fRatios->GetHists() ||
362 fRatios->GetHists()->GetEntries() <= 0) {
363 Warning("Run", "No ratio data found - disabling that");
364 // fRatios->ls();
365 fShowRatios = false;
366 }
367 if (!fLeftRight->GetHists() ||
368 fLeftRight->GetHists()->GetEntries() <= 0) {
369 Warning("Run", "No left/right data found - disabling that");
370 // fLeftRight->ls();
371 fShowLeftRight = false;
372 }
797161e8 373 if (fFwdSysErr > 0) {
374 if (fCenSysErr <= 0) fCenSysErr = fFwdSysErr;
375 for (Int_t i = 0; i < fwdA->GetEntriesFast(); i++) {
376 TH1* fwd = static_cast<TH1*>(fwdA->At(i));
377 TH1* cen = static_cast<TH1*>(cenA->At(i));
378 CorrectForward(fwd);
379 CorrectCentral(cen);
380 Double_t low, high;
381 TH1* tmp = Merge(cen, fwd, low, high);
382 TF1* f = FitMerged(tmp, low, high);
383 MakeSysError(tmp, cen, fwd, f);
384 delete f;
385 Info("", "Adding systematic error histogram %s",
386 tmp->GetName());
387 fResults->GetHists()->AddFirst(tmp, "e5");
298a7264 388
389 if (!fMirror) continue;
390
797161e8 391 TH1* tmp2 = Symmetrice(tmp);
392 tmp2->SetFillColor(tmp->GetFillColor());
393 tmp2->SetFillStyle(tmp->GetFillStyle());
394 tmp2->SetMarkerStyle(tmp->GetMarkerStyle());
395 tmp2->SetLineWidth(tmp->GetLineWidth());
396 fResults->GetHists()->AddFirst(tmp2, "e5");
397 fResults->Modified();
398 }
399 }
400 delete fwdA;
401 delete cenA;
e308a636 402
403 // --- Close the input file --------------------------------------
404 file->Close();
405
406
b2e7f2d6 407
e308a636 408 // --- Plot results ----------------------------------------------
409 Plot(max, rmax, amax);
b2e7f2d6 410 }
e1f47419 411
b2e7f2d6 412 //__________________________________________________________________
2f92ff0e 413 /**
e1f47419 414 * Fetch the information on the run from the results list
2f92ff0e 415 *
e1f47419 416 * @param results Results list
2f92ff0e 417 */
e1f47419 418 void FetchInformation(const TList* results)
b2e7f2d6 419 {
2f92ff0e 420 if (!fTrigString)
0be6c8cd 421 fTrigString = static_cast<TNamed*>(results->FindObject("trigger"));
422 if (!fNormString)
423 fNormString = static_cast<TNamed*>(results->FindObject("scheme"));
2f92ff0e 424 if (!fSNNString)
425 fSNNString = static_cast<TNamed*>(results->FindObject("sNN"));
426 if (!fSysString)
427 fSysString = static_cast<TNamed*>(results->FindObject("sys"));
428 if (!fVtxAxis)
429 fVtxAxis = static_cast<TAxis*>(results->FindObject("vtxAxis"));
e308a636 430 if (!fCentAxis)
431 fCentAxis = static_cast<TAxis*>(results->FindObject("centAxis"));
c25b5e1b 432
433 TNamed* options = static_cast<TAxis*>(results->FindObject("options"));
0be6c8cd 434 if (!fTrigString) fTrigString = new TNamed("trigger", "unknown");
435 if (!fNormString) fNormString = new TNamed("scheme", "unknown");
bad9a3c1 436 if (!fSNNString) fSNNString = new TNamed("sNN", "unknown");
437 if (!fSysString) fSysString = new TNamed("sys", "unknown");
438 if (!fVtxAxis) {
439 fVtxAxis = new TAxis(1,0,0);
440 fVtxAxis->SetName("vtxAxis");
441 fVtxAxis->SetTitle("v_{z} range unspecified");
442 }
b2e7f2d6 443
0be6c8cd 444 TString centTxt("none");
e308a636 445 if (fCentAxis) {
446 Int_t nCent = fCentAxis->GetNbins();
0be6c8cd 447 centTxt = Form("%d bins", nCent);
e308a636 448 for (Int_t i = 0; i <= nCent; i++)
0be6c8cd 449 centTxt.Append(Form("%c%d", i == 0 ? ' ' : '-',
ffca499d 450 int(fCentAxis->GetXbins()->At(i))));
e308a636 451 }
e1f47419 452 Info("FetchInformation",
fe52e455 453 "Initialized for\n"
0be6c8cd 454 " Trigger: %-30s (%d)\n"
455 " sqrt(sNN): %-30s (%dGeV)\n"
456 " System: %-30s (%d)\n"
457 " Vz range: %-30s (%f,%f)\n"
458 " Normalization: %-30s (%d)\n"
c25b5e1b 459 " Centrality: %s\n"
460 " Options: %s",
fe52e455 461 fTrigString->GetTitle(), fTrigString->GetUniqueID(),
462 fSNNString->GetTitle(), fSNNString->GetUniqueID(),
463 fSysString->GetTitle(), fSysString->GetUniqueID(),
e308a636 464 fVtxAxis->GetTitle(), fVtxAxis->GetXmin(), fVtxAxis->GetXmax(),
0be6c8cd 465 fNormString->GetTitle(), fNormString->GetUniqueID(),
c25b5e1b 466 centTxt.Data(), (options ? options->GetTitle() : "none"));
e1f47419 467 }
e308a636 468 //__________________________________________________________________
469 TMultiGraph* FetchOthers(UShort_t centLow, UShort_t centHigh)
470 {
471 TMultiGraph* thisOther = 0;
797161e8 472 if (fShowOthers == 0) return 0;
e308a636 473
e308a636 474 UShort_t sys = (fSysString ? fSysString->GetUniqueID() : 0);
475 UShort_t trg = (fTrigString ? fTrigString->GetUniqueID() : 0);
476 UShort_t snn = (fSNNString ? fSNNString->GetUniqueID() : 0);
797161e8 477 Long_t ret = gROOT->ProcessLine(Form("GetData(%d,%d,%d,%d,%d,%d);",
e308a636 478 sys,snn,trg,
797161e8 479 centLow,centHigh,
480 fShowOthers));
481 if (!ret) return 0;
482
483 thisOther = reinterpret_cast<TMultiGraph*>(ret);
e308a636 484 return thisOther;
485 }
e1f47419 486 //__________________________________________________________________
487 /**
e308a636 488 * Get the results from the top-level list
e1f47419 489 *
e308a636 490 * @param list List
491 * @param name name
492 * @param max On return, maximum of data
493 * @param rmax On return, maximum of ratios
494 * @param amax On return, maximum of left-right comparisons
290052e7 495 *
496 * @return Array of results
e1f47419 497 */
797161e8 498 TObjArray*
499 FetchResults(const TList* list,
500 const char* name,
501 Double_t& max,
502 Double_t& rmax,
cd3b3781 503 Double_t& amax,
504 TObjArray& truths)
e1f47419 505 {
298a7264 506 UShort_t n = HasCent() ? fCentAxis->GetNbins() : 0;
cd3b3781 507 // Info("FetchResults","got %d centrality bins", n);
e308a636 508 if (n == 0) {
509 TList* all = static_cast<TList*>(list->FindObject("all"));
797161e8 510 if (!all) {
e308a636 511 Error("FetchResults", "Couldn't find list 'all' in %s",
512 list->GetName());
797161e8 513 return 0;
514 }
515 TObjArray* a = new TObjArray;
516 TH1* h = FetchResults(all, name, FetchOthers(0,0),
cd3b3781 517 -1000, 0, max, rmax, amax, fTruth);
518 // Info("FetchResults", "Adding %s to result stack", h->GetName());
797161e8 519 a->AddAt(h, 0);
520 return a;
b2e7f2d6 521 }
e1f47419 522
797161e8 523 TObjArray* a = new TObjArray;
cd3b3781 524 truths.Expand(n);
e308a636 525 for (UShort_t i = 0; i < n; i++) {
5bb5d1f6 526 UShort_t centLow = fCentAxis->GetBinLowEdge(i+1);
527 UShort_t centHigh = fCentAxis->GetBinUpEdge(i+1);
e308a636 528 TString lname = Form("cent%03d_%03d", centLow, centHigh);
529 TList* thisCent = static_cast<TList*>(list->FindObject(lname));
5bb5d1f6 530 Int_t col = GetCentralityColor(i+1);
e308a636 531
532 TString centTxt = Form("%3d%%-%3d%% central", centLow, centHigh);
797161e8 533 if (!thisCent) {
e308a636 534 Error("FetchResults", "Couldn't find list '%s' in %s",
535 lname.Data(), list->GetName());
797161e8 536 continue;
537 }
cd3b3781 538 TH1* tt = static_cast<TH1*>(truths.At(i));
539 TH1* ot = tt;
797161e8 540 TH1* h = FetchResults(thisCent, name, FetchOthers(centLow, centHigh),
cd3b3781 541 col, centTxt.Data(), max, rmax, amax, tt);
542 if (ot != tt) {
543 //Info("FetchResults", "old truth=%p new truth=%p (%s)", ot, tt, name);
544 truths.AddAt(tt, i);
545 }
546 // Info("FetchResults", "Adding %p to result stack", h);
797161e8 547 a->AddAt(h, i);
e1f47419 548 }
797161e8 549 return a;
e308a636 550 }
551 //__________________________________________________________________
290052e7 552 /**
553 * Get the color for a centrality bin
554 *
555 * @param bin Centrality bin
556 *
557 * @return Color
558 */
5bb5d1f6 559 Int_t GetCentralityColor(Int_t bin) const
560 {
561 UShort_t centLow = fCentAxis->GetBinLowEdge(bin);
562 UShort_t centHigh = fCentAxis->GetBinUpEdge(bin);
563 Float_t fc = (centLow+double(centHigh-centLow)/2) / 100;
564 Int_t nCol = gStyle->GetNumberOfColors();
565 Int_t icol = TMath::Min(nCol-1,int(fc * nCol + .5));
566 Int_t col = gStyle->GetColorPalette(icol);
567 //Info("GetCentralityColor","%3d: %3d-%3d -> %3d",bin,centLow,centHigh,col);
568 return col;
569 }
570 //__________________________________________________________________
290052e7 571 /**
572 * Set attributed on a histogram
573 *
574 * @param h Histogram
575 * @param color Color
576 */
e308a636 577 void SetAttributes(TH1* h, Int_t color)
578 {
579 if (!h) return;
580 if (color < 0) return;
ffca499d 581 // h->SetLineColor(color);
e308a636 582 h->SetMarkerColor(color);
ffca499d 583 // h->SetFillColor(color);
e308a636 584 }
585 //__________________________________________________________________
290052e7 586 /**
587 * Set attributed on a graph
588 *
589 * @param g Graph
590 * @param color Color
591 */
e308a636 592 void SetAttributes(TGraph* g, Int_t color)
593 {
594 if (!g) return;
595 if (color < 0) return;
ffca499d 596 // g->SetLineColor(color);
e308a636 597 g->SetMarkerColor(color);
ffca499d 598 // g->SetFillColor(color);
b2e7f2d6 599 }
600 //__________________________________________________________________
290052e7 601 /**
602 * Modify the title
603 *
604 */
9ecab72f 605 void ModifyTitle(TNamed* /*h*/, const char* /*centTxt*/)
e308a636 606 {
5bb5d1f6 607 return;
608 // if (!centTxt || !h) return;
609 // h->SetTitle(Form("%s, %s", h->GetTitle(), centTxt));
e308a636 610 }
611
612 //__________________________________________________________________
613 /**
614 * Fetch results for a particular centrality bin
615 *
616 * @param list List
617 * @param name Name
ffca499d 618 * @param thisOther Other graphs
619 * @param color Color
620 * @param centTxt Centrality text
e308a636 621 * @param max On return, data maximum
622 * @param rmax On return, ratio maximum
623 * @param amax On return, left-right maximum
290052e7 624 *
625 * @return Histogram of results
e308a636 626 */
797161e8 627 TH1* FetchResults(const TList* list,
e308a636 628 const char* name,
629 TMultiGraph* thisOther,
630 Int_t color,
631 const char* centTxt,
632 Double_t& max,
633 Double_t& rmax,
cd3b3781 634 Double_t& amax,
635 TH1*& truth)
b2e7f2d6 636 {
cd3b3781 637
e1f47419 638 TH1* dndeta = FetchResult(list, Form("dndeta%s", name));
639 TH1* dndetaMC = FetchResult(list, Form("dndeta%sMC", name));
640 TH1* dndetaTruth = FetchResult(list, "dndetaTruth");
641 TH1* dndetaSym = 0;
642 TH1* dndetaMCSym = 0;
e308a636 643 SetAttributes(dndeta, color);
298a7264 644 SetAttributes(dndetaMC, HasCent() ? color : color+2);
e308a636 645 SetAttributes(dndetaTruth,color);
646 SetAttributes(dndetaSym, color);
298a7264 647 SetAttributes(dndetaMCSym,HasCent() ? color : color+2);
648 if (dndetaMC && HasCent())
5bb5d1f6 649 dndetaMC->SetMarkerStyle(dndetaMC->GetMarkerStyle()+2);
298a7264 650 if (dndetaMCSym && HasCent())
5bb5d1f6 651 dndetaMCSym->SetMarkerStyle(dndetaMCSym->GetMarkerStyle()+2);
298a7264 652 if (dndetaTruth && HasCent()) {
5bb5d1f6 653 dndetaTruth->SetMarkerStyle(34);
9ecab72f 654 dndetaTruth->SetMarkerColor(kYellow-1);
655 }
298a7264 656 if (dndetaTruth) {
657 dndetaTruth->SetLineColor(kBlack);
cd3b3781 658 dndetaTruth->SetFillColor(kBlack);
659 dndetaTruth->SetFillStyle(3002);
660 // dndetaTruth->SetLineColor(kBlack);
298a7264 661 }
e308a636 662 ModifyTitle(dndeta, centTxt);
663 ModifyTitle(dndetaMC, centTxt);
664 ModifyTitle(dndetaTruth,centTxt);
665 ModifyTitle(dndetaSym, centTxt);
666 ModifyTitle(dndetaMCSym,centTxt);
e308a636 667
e1f47419 668
cd3b3781 669 max = TMath::Max(max, AddHistogram(fResults, dndetaTruth, "e5"));
e308a636 670 max = TMath::Max(max, AddHistogram(fResults, dndetaMC, dndetaMCSym));
671 max = TMath::Max(max, AddHistogram(fResults, dndeta, dndetaSym));
5bb5d1f6 672
9ecab72f 673 if (dndetaTruth) {
cd3b3781 674 truth = dndetaTruth;
5bb5d1f6 675 }
9ecab72f 676 else {
677 if (fShowRings) {
678 THStack* rings = static_cast<THStack*>(list->FindObject("dndetaRings"));
679 if (rings) {
680 TIter next(rings->GetHists());
681 TH1* hist = 0;
682 while ((hist = static_cast<TH1*>(next())))
683 max = TMath::Max(max, AddHistogram(fResults, hist));
ffca499d 684 }
b2e7f2d6 685 }
9ecab72f 686 // Info("FetchResults", "Got %p, %p, %p from %s with name %s, max=%f",
687 // dndeta, dndetaMC, dndetaTruth, list->GetName(), name, max);
688
689 if (fShowLeftRight) {
690 fLeftRight->Add(Asymmetry(dndeta, amax));
691 fLeftRight->Add(Asymmetry(dndetaMC, amax));
9ecab72f 692 }
693
694 if (thisOther) {
695 TIter next(thisOther->GetListOfGraphs());
696 TGraph* g = 0;
697 while ((g = static_cast<TGraph*>(next()))) {
698 fRatios->Add(Ratio(dndeta, g, rmax));
699 fRatios->Add(Ratio(dndetaSym, g, rmax));
700 SetAttributes(g, color);
701 ModifyTitle(g, centTxt);
702 if (!fOthers->GetListOfGraphs() ||
703 !fOthers->GetListOfGraphs()->FindObject(g->GetName())) {
704 max = TMath::Max(max,TMath::MaxElement(g->GetN(), g->GetY()));
705 fOthers->Add(g);
706 }
707 }
708 // fOthers->Add(thisOther);
709 }
b2e7f2d6 710 }
5bb5d1f6 711 if (dndetaMC) {
712 fRatios->Add(Ratio(dndeta, dndetaMC, rmax));
713 fRatios->Add(Ratio(dndetaSym, dndetaMCSym, rmax));
714 }
cd3b3781 715 if (truth) {
716 fRatios->Add(Ratio(dndeta, truth, rmax));
717 fRatios->Add(Ratio(dndetaSym, truth, rmax));
b2e7f2d6 718 }
797161e8 719 return dndeta;
b2e7f2d6 720 }
721 //__________________________________________________________________
2f92ff0e 722 /**
723 * Plot the results
2f92ff0e 724 * @param max Max value
2f92ff0e 725 * @param rmax Maximum diviation from 1 of ratios
2f92ff0e 726 * @param amax Maximum diviation from 1 of asymmetries
727 */
e308a636 728 void Plot(Double_t max,
b2e7f2d6 729 Double_t rmax,
b2e7f2d6 730 Double_t amax)
731 {
732 gStyle->SetOptTitle(0);
733 gStyle->SetTitleFont(132, "xyz");
734 gStyle->SetLabelFont(132, "xyz");
735
e308a636 736 Int_t h = 800;
737 Int_t w = 800; // h / TMath::Sqrt(2);
738 Double_t y1 = 0;
739 Double_t y2 = 0;
740 Double_t y3 = 0;
797161e8 741 if (!fShowRatios) w *= 1.3;
e308a636 742 else y1 = 0.3;
797161e8 743 if (!fShowLeftRight) w *= 1.3;
e308a636 744 else {
745 Double_t y11 = y1;
746 y1 = (y11 > 0.0001 ? 0.4 : 0.2);
ffca499d 747 y2 = (y11 > 0.0001 ? 0.2 : 0.3);
e308a636 748 }
b2e7f2d6 749 TCanvas* c = new TCanvas("Results", "Results", w, h);
750 c->SetFillColor(0);
751 c->SetBorderSize(0);
752 c->SetBorderMode(0);
753
e308a636 754 PlotResults(max, y1);
b2e7f2d6 755 c->cd();
756
e308a636 757 PlotRatios(rmax, y2, y1);
b2e7f2d6 758 c->cd( );
759
e308a636 760 PlotLeftRight(amax, y3, y2);
b2e7f2d6 761 c->cd();
bad9a3c1 762
763
764 Int_t vMin = fVtxAxis->GetXmin();
765 Int_t vMax = fVtxAxis->GetXmax();
766 TString trg(fTrigString->GetTitle());
e308a636 767 Int_t nev = 0;
ffca499d 768 if (fTriggers) nev = fTriggers->GetBinContent(1);
bad9a3c1 769 trg = trg.Strip(TString::kBoth);
f709afcf 770 trg.ReplaceAll(" ", "_");
771 trg.ReplaceAll(">", "Gt");
bad9a3c1 772 TString base(Form("dndeta_%s_%s_%s_%c%02d%c%02dcm_%09dev",
773 fSysString->GetTitle(),
774 fSNNString->GetTitle(),
775 trg.Data(),
776 vMin < 0 ? 'm' : 'p', TMath::Abs(vMin),
777 vMax < 0 ? 'm' : 'p', TMath::Abs(vMax),
778 nev));
779 c->SaveAs(Form("%s.png", base.Data()));
780 c->SaveAs(Form("%s.root", base.Data()));
781 c->SaveAs(Form("%s.C", base.Data()));
33ab4a11 782 base.ReplaceAll("dndeta", "export");
783 Export(base);
b2e7f2d6 784 }
785 //__________________________________________________________________
e308a636 786 /**
787 * Build main legend
788 *
ffca499d 789 * @param stack Stack to include
790 * @param mg (optional) Multi graph to include
791 * @param x1 Lower X coordinate in the range [0,1]
792 * @param y1 Lower Y coordinate in the range [0,1]
793 * @param x2 Upper X coordinate in the range [0,1]
794 * @param y2 Upper Y coordinate in the range [0,1]
e308a636 795 */
ffca499d 796 void BuildLegend(THStack* stack, TMultiGraph* mg,
cd3b3781 797 Double_t x1, Double_t y1, Double_t x2, Double_t y2,
798 Int_t forceCol=0)
e308a636 799 {
800 TLegend* l = new TLegend(x1,y1,x2,y2);
cd3b3781 801 Int_t nCol = forceCol;
802 if (nCol <= 0) nCol = HasCent() ? 1 : 2;
803 l->SetNColumns(nCol);
e308a636 804 l->SetFillColor(0);
805 l->SetFillStyle(0);
806 l->SetBorderSize(0);
807 l->SetTextFont(132);
808
797161e8 809 // Loop over items in stack and get unique items, while ignoring
810 // mirrored data and systematic error bands
ffca499d 811 TIter next(stack->GetHists());
5bb5d1f6 812 TH1* hist = 0;
813 TObjArray unique;
814 unique.SetOwner();
797161e8 815 Bool_t sysErrSeen = false;
5bb5d1f6 816 while ((hist = static_cast<TH1*>(next()))) {
797161e8 817 TString t(hist->GetTitle());
818 TString n(hist->GetName());
819 n.ToLower();
820 if (t.Contains("mirrored")) continue;
821 if (n.Contains("syserror")) { sysErrSeen = true; continue; }
822 if (unique.FindObject(t.Data())) continue;
298a7264 823 TObjString* s1 = new TObjString(hist->GetTitle());
824 s1->SetUniqueID(((hist->GetMarkerStyle() & 0xFFFF) << 16) |
825 ((hist->GetMarkerColor() & 0xFFFF) << 0));
826 unique.Add(s1);
5bb5d1f6 827 // l->AddEntry(hist, hist->GetTitle(), "pl");
e308a636 828 }
ffca499d 829 if (mg) {
797161e8 830 // If we have other stuff, scan for unique names
ffca499d 831 TIter nexto(mg->GetListOfGraphs());
5bb5d1f6 832 TGraph* g = 0;
833 while ((g = static_cast<TGraph*>(nexto()))) {
834 TString n(g->GetTitle());
ffca499d 835 if (n.Contains("mirrored")) continue;
5bb5d1f6 836 if (unique.FindObject(n.Data())) continue;
298a7264 837 TObjString* s2 = new TObjString(n);
838 s2->SetUniqueID(((g->GetMarkerStyle() & 0xFFFF) << 16) |
839 ((g->GetMarkerColor() & 0xFFFF) << 0));
840 unique.Add(s2);
5bb5d1f6 841 // l->AddEntry(hist, hist->GetTitle(), "pl");
ffca499d 842 }
e308a636 843 }
797161e8 844
845 // Add legend entries for unique items only
5bb5d1f6 846 TIter nextu(&unique);
847 TObject* s = 0;
848 Int_t i = 0;
849 while ((s = nextu())) {
850 TLegendEntry* dd = l->AddEntry(Form("data%2d", i++),
851 s->GetName(), "lp");
852 Int_t style = (s->GetUniqueID() >> 16) & 0xFFFF;
853 Int_t color = (s->GetUniqueID() >> 0) & 0xFFFF;
854 dd->SetLineColor(kBlack);
298a7264 855 if (HasCent()) dd->SetMarkerColor(kBlack);
5bb5d1f6 856 else dd->SetMarkerColor(color);
857 dd->SetMarkerStyle(style);
858 }
797161e8 859 if (sysErrSeen) {
860 // Add entry for systematic errors
861 TLegendEntry* d0 = l->AddEntry("d0", Form("%4.1f%% Systematic error",
862 100*fFwdSysErr), "f");
e42bc740 863 d0->SetLineColor(SYSERR_COLOR);
864 d0->SetMarkerColor(SYSERR_COLOR);
865 d0->SetFillColor(SYSERR_COLOR);
866 d0->SetFillStyle(SYSERR_STYLE);
797161e8 867 d0->SetMarkerStyle(0);
868 d0->SetLineWidth(0);
869 i++;
870 }
cd3b3781 871 if (nCol == 2 && i % 2 == 1) {
797161e8 872 // To make sure the 'data' and 'mirrored' entries are on a line
873 // by themselves
874 TLegendEntry* dd = l->AddEntry("dd", " ", "");
875 dd->SetTextSize(0);
876 dd->SetFillStyle(0);
877 dd->SetFillColor(0);
878 dd->SetLineWidth(0);
879 dd->SetLineColor(0);
880 dd->SetMarkerSize(0);
881 }
298a7264 882 if (fMirror) {
cd3b3781 883 // Add entry for 'data'
884 TLegendEntry* d1 = l->AddEntry("d1", "Data", "lp");
885 d1->SetLineColor(kBlack);
886 d1->SetMarkerColor(kBlack);
887 d1->SetMarkerStyle(20);
888
889 // Add entry for 'mirrored data'
298a7264 890 TLegendEntry* d2 = l->AddEntry("d2", "Mirrored data", "lp");
891 d2->SetLineColor(kBlack);
892 d2->SetMarkerColor(kBlack);
893 d2->SetMarkerStyle(24);
894 }
e308a636 895
896 l->Draw();
897 }
898 //__________________________________________________________________
5bb5d1f6 899 /**
900 * Build centrality legend
901 *
5bb5d1f6 902 * @param x1 Lower X coordinate in the range [0,1]
903 * @param y1 Lower Y coordinate in the range [0,1]
904 * @param x2 Upper X coordinate in the range [0,1]
905 * @param y2 Upper Y coordinate in the range [0,1]
906 */
907 void BuildCentLegend(Double_t x1, Double_t y1, Double_t x2, Double_t y2)
908 {
298a7264 909 if (!HasCent()) return;
5bb5d1f6 910
911 TLegend* l = new TLegend(x1,y1,x2,y2);
912 l->SetNColumns(1);
913 l->SetFillColor(0);
914 l->SetFillStyle(0);
915 l->SetBorderSize(0);
916 l->SetTextFont(132);
917
918 Int_t n = fCentAxis->GetNbins();
919 for (Int_t i = 1; i <= n; i++) {
920 Double_t low = fCentAxis->GetBinLowEdge(i);
921 Double_t upp = fCentAxis->GetBinUpEdge(i);
922 TLegendEntry* e = l->AddEntry(Form("dummy%02d", i),
923 Form("%3d%% - %3d%%",
924 int(low), int(upp)), "pl");
925 e->SetMarkerColor(GetCentralityColor(i));
926 }
927 l->Draw();
928 }
929 //__________________________________________________________________
2f92ff0e 930 /**
931 * Plot the results
932 *
2f92ff0e 933 * @param max Maximum
934 * @param yd Bottom position of pad
935 */
e308a636 936 void PlotResults(Double_t max, Double_t yd)
b2e7f2d6 937 {
938 // Make a sub-pad for the result itself
939 TPad* p1 = new TPad("p1", "p1", 0, yd, 1.0, 1.0, 0, 0, 0);
940 p1->SetTopMargin(0.05);
941 p1->SetBorderSize(0);
942 p1->SetBorderMode(0);
943 p1->SetBottomMargin(yd > 0.001 ? 0.001 : 0.1);
797161e8 944 p1->SetRightMargin(0.03);
945 if (fShowLeftRight || fShowRatios) p1->SetGridx();
b2e7f2d6 946 p1->SetTicks(1,1);
947 p1->SetNumber(1);
948 p1->Draw();
949 p1->cd();
33ab4a11 950
e308a636 951 // Info("PlotResults", "Plotting results with max=%f", max);
952 fResults->SetMaximum(1.15*max);
cd3b3781 953 fResults->SetMinimum(yd > 0.00001 ? -0.02*max : 0);
b2e7f2d6 954
797161e8 955 FixAxis(fResults, (1-yd)*(yd > .001 ? 1 : .9 / 1.2),
956 "#font[12]{#frac{1}{N} "
957 "#frac{dN_{#font[132]{ch}}}{d#font[152]{#eta}}}");
b2e7f2d6 958
959 p1->Clear();
e308a636 960 fResults->DrawClone("nostack e1");
b2e7f2d6 961
e308a636 962 fRangeParam->fSlave1Axis = fResults->GetXaxis();
b2e7f2d6 963 fRangeParam->fSlave1Pad = p1;
964
965 // Draw other data
797161e8 966 if (fShowOthers != 0) {
b2e7f2d6 967 TGraphAsymmErrors* o = 0;
e308a636 968 TIter nextG(fOthers->GetListOfGraphs());
b2e7f2d6 969 while ((o = static_cast<TGraphAsymmErrors*>(nextG())))
970 o->DrawClone("same p");
971 }
972
973 // Make a legend in the main result pad
5bb5d1f6 974 BuildCentLegend(.12, 1-p1->GetTopMargin()-.01-.5,
975 .35, 1-p1->GetTopMargin()-.01-.1);
298a7264 976 Double_t x1 = (HasCent() ? .7 : .15);
977 Double_t x2 = (HasCent() ? 1-p1->GetRightMargin()-.01: .90);
978 Double_t y1 = (HasCent() ? .5: p1->GetBottomMargin()+.01);
979 Double_t y2 = (HasCent() ? 1-p1->GetTopMargin()-.01-.15 : .35);
5bb5d1f6 980
981 BuildLegend(fResults, fOthers, x1, y1, x2, y2);
b2e7f2d6 982
983 // Put a title on top
ffca499d 984 fTitle.ReplaceAll("@", " ");
b2e7f2d6 985 TLatex* tit = new TLatex(0.10, 0.95, fTitle.Data());
986 tit->SetNDC();
987 tit->SetTextFont(132);
988 tit->SetTextSize(0.05);
989 tit->Draw();
990
f709afcf 991 Int_t aliceBlue = TColor::GetColor(41,73,156);
b2e7f2d6 992 // Put a nice label in the plot
993 TString eS;
bad9a3c1 994 UShort_t snn = fSNNString->GetUniqueID();
995 const char* sys = fSysString->GetTitle();
5bb5d1f6 996 if (snn == 2750) snn = 2760;
b2e7f2d6 997 if (snn > 1000) eS = Form("%4.2fTeV", float(snn)/1000);
998 else eS = Form("%3dGeV", snn);
5bb5d1f6 999 TLatex* tt = new TLatex(.93, .93, Form("%s #sqrt{s%s}=%s, %s",
b2e7f2d6 1000 sys,
298a7264 1001 (HasCent() ? "_{NN}" : ""),
b2e7f2d6 1002 eS.Data(),
298a7264 1003 HasCent() ? "by centrality" :
bad9a3c1 1004 fTrigString->GetTitle()));
f709afcf 1005 tt->SetTextColor(aliceBlue);
b2e7f2d6 1006 tt->SetNDC();
1007 tt->SetTextFont(132);
1008 tt->SetTextAlign(33);
1009 tt->Draw();
1010
1011 // Put number of accepted events on the plot
e308a636 1012 Int_t nev = 0;
ffca499d 1013 if (fTriggers) nev = fTriggers->GetBinContent(1);
b2e7f2d6 1014 TLatex* et = new TLatex(.93, .83, Form("%d events", nev));
f709afcf 1015 et->SetTextColor(aliceBlue);
b2e7f2d6 1016 et->SetNDC();
1017 et->SetTextFont(132);
1018 et->SetTextAlign(33);
1019 et->Draw();
1020
1021 // Put number of accepted events on the plot
1022 if (fVtxAxis) {
1023 TLatex* vt = new TLatex(.93, .88, fVtxAxis->GetTitle());
1024 vt->SetNDC();
1025 vt->SetTextFont(132);
1026 vt->SetTextAlign(33);
f709afcf 1027 vt->SetTextColor(aliceBlue);
b2e7f2d6 1028 vt->Draw();
1029 }
1030 // results->Draw("nostack e1 same");
1031
e308a636 1032 fRangeParam->fSlave1Axis = FindXAxis(p1, fResults->GetName());
b2e7f2d6 1033 fRangeParam->fSlave1Pad = p1;
1034
1035
1036 // Mark the plot as preliminary
f709afcf 1037 TLatex* pt = new TLatex(.12, .93, "Work in progress");
b2e7f2d6 1038 pt->SetNDC();
1039 pt->SetTextFont(22);
f709afcf 1040 // pt->SetTextSize();
1041 pt->SetTextColor(TColor::GetColor(234,26,46));
b2e7f2d6 1042 pt->SetTextAlign(13);
1043 pt->Draw();
1044
f709afcf 1045 const char* logos[] = { "ALICE.png", "FMD.png", 0 };
1046 const char** logo = logos;
1047 while (*logo) {
1048 if (gSystem->AccessPathName(*logo)) {
1049 logo++;
1050 continue;
1051 }
797161e8 1052 TPad* pad = new TPad("logo", "logo", .12, .7, .25, .9, 0, 0, 0);
f709afcf 1053 pad->SetFillStyle(0);
1054 pad->Draw();
1055 pad->cd();
b2e7f2d6 1056 TImage* i = TImage::Create();
f709afcf 1057 i->ReadImage(*logo);
b2e7f2d6 1058 i->Draw();
f709afcf 1059 break;
b2e7f2d6 1060 }
1061 p1->cd();
1062 }
1063 //__________________________________________________________________
2f92ff0e 1064 /**
1065 * Plot the ratios
1066 *
2f92ff0e 1067 * @param max Maximum diviation from 1
1068 * @param y1 Lower y coordinate of pad
1069 * @param y2 Upper y coordinate of pad
1070 */
e308a636 1071 void PlotRatios(Double_t max, Double_t y1, Double_t y2)
b2e7f2d6 1072 {
797161e8 1073 if (fShowRatios == 0) return;
e308a636 1074
b2e7f2d6 1075 bool isBottom = (y1 < 0.0001);
1076 Double_t yd = y2 - y1;
1077 // Make a sub-pad for the result itself
1078 TPad* p2 = new TPad("p2", "p2", 0, y1, 1.0, y2, 0, 0, 0);
1079 p2->SetTopMargin(0.001);
797161e8 1080 p2->SetRightMargin(0.03);
b2e7f2d6 1081 p2->SetBottomMargin(isBottom ? 1/yd * 0.07 : 0.0001);
1082 p2->SetGridx();
1083 p2->SetTicks(1,1);
1084 p2->SetNumber(2);
1085 p2->Draw();
1086 p2->cd();
1087
1088 // Fix up axis
797161e8 1089 FixAxis(fRatios, yd, "Ratios", 7);
b2e7f2d6 1090
e308a636 1091 fRatios->SetMaximum(1+TMath::Max(.22,1.05*max));
1092 fRatios->SetMinimum(1-TMath::Max(.32,1.05*max));
b2e7f2d6 1093 p2->Clear();
e308a636 1094 fRatios->DrawClone("nostack e1");
b2e7f2d6 1095
1096
1097 // Make a legend
ffca499d 1098 BuildLegend(fRatios, 0, .15,p2->GetBottomMargin()+.01,.9,
cd3b3781 1099 isBottom ? .6 : .4, 2);
ffca499d 1100#if 0
b2e7f2d6 1101 TLegend* l2 = p2->BuildLegend(.15,p2->GetBottomMargin()+.01,.9,
1102 isBottom ? .6 : .4);
1103 l2->SetNColumns(2);
1104 l2->SetFillColor(0);
1105 l2->SetFillStyle(0);
1106 l2->SetBorderSize(0);
1107 l2->SetTextFont(132);
ffca499d 1108#endif
b2e7f2d6 1109 // Make a nice band from 0.9 to 1.1
1110 TGraphErrors* band = new TGraphErrors(2);
e1f47419 1111 band->SetPoint(0, fResults->GetXaxis()->GetXmin(), 1);
1112 band->SetPoint(1, fResults->GetXaxis()->GetXmax(), 1);
b2e7f2d6 1113 band->SetPointError(0, 0, .1);
1114 band->SetPointError(1, 0, .1);
1115 band->SetFillColor(kYellow+2);
1116 band->SetFillStyle(3002);
1117 band->SetLineStyle(2);
1118 band->SetLineWidth(1);
1119 band->Draw("3 same");
1120 band->DrawClone("X L same");
1121
1122 // Replot the ratios on top
e308a636 1123 fRatios->DrawClone("nostack e1 same");
b2e7f2d6 1124
1125 if (isBottom) {
e308a636 1126 fRangeParam->fMasterAxis = FindXAxis(p2, fRatios->GetName());
b2e7f2d6 1127 p2->AddExec("range", Form("RangeExec((dNdetaDrawer::RangeParam*)%p)",
1128 fRangeParam));
1129 }
1130 else {
e308a636 1131 fRangeParam->fSlave2Axis = FindXAxis(p2, fRatios->GetName());
b2e7f2d6 1132 fRangeParam->fSlave2Pad = p2;
1133 }
1134 }
1135 //__________________________________________________________________
2f92ff0e 1136 /**
1137 * Plot the asymmetries
1138 *
2f92ff0e 1139 * @param max Maximum diviation from 1
1140 * @param y1 Lower y coordinate of pad
1141 * @param y2 Upper y coordinate of pad
1142 */
e308a636 1143 void PlotLeftRight(Double_t max, Double_t y1, Double_t y2)
b2e7f2d6 1144 {
e308a636 1145 if (!fShowLeftRight) return;
1146
b2e7f2d6 1147 bool isBottom = (y1 < 0.0001);
1148 Double_t yd = y2 - y1;
1149 // Make a sub-pad for the result itself
1150 TPad* p3 = new TPad("p3", "p3", 0, y1, 1.0, y2, 0, 0, 0);
1151 p3->SetTopMargin(0.001);
797161e8 1152 p3->SetRightMargin(0.03);
b2e7f2d6 1153 p3->SetBottomMargin(isBottom ? 1/yd * 0.07 : 0.0001);
1154 p3->SetGridx();
1155 p3->SetTicks(1,1);
1156 p3->SetNumber(2);
1157 p3->Draw();
1158 p3->cd();
1159
b2e7f2d6 1160 // Fix up axis
797161e8 1161 FixAxis(fLeftRight, yd, "Right/Left", 4);
b2e7f2d6 1162
e308a636 1163 fLeftRight->SetMaximum(1+TMath::Max(.12,1.05*max));
1164 fLeftRight->SetMinimum(1-TMath::Max(.15,1.05*max));
b2e7f2d6 1165 p3->Clear();
e308a636 1166 fLeftRight->DrawClone("nostack e1");
b2e7f2d6 1167
1168
1169 // Make a legend
298a7264 1170 Double_t xx1 = (HasCent() ? .7 : .15);
1171 Double_t xx2 = (HasCent() ? 1-p3->GetRightMargin()-.01 : .90);
5bb5d1f6 1172 Double_t yy1 = p3->GetBottomMargin()+.01;
298a7264 1173 Double_t yy2 = (HasCent() ? 1-p3->GetTopMargin()-.01-.15 : .5);
5bb5d1f6 1174 BuildLegend(fLeftRight, 0, xx1, yy1, xx2, yy2);
1175 // TLegend* l2 = p3->BuildLegend(.15,p3->GetBottomMargin()+.01,.9,.5);
1176 // l2->SetNColumns(2);
1177 // l2->SetFillColor(0);
1178 // l2->SetFillStyle(0);
1179 // l2->SetBorderSize(0);
1180 // l2->SetTextFont(132);
ffca499d 1181
b2e7f2d6 1182 // Make a nice band from 0.9 to 1.1
1183 TGraphErrors* band = new TGraphErrors(2);
e1f47419 1184 band->SetPoint(0, fResults->GetXaxis()->GetXmin(), 1);
1185 band->SetPoint(1, fResults->GetXaxis()->GetXmax(), 1);
b2e7f2d6 1186 band->SetPointError(0, 0, .05);
1187 band->SetPointError(1, 0, .05);
1188 band->SetFillColor(kYellow+2);
1189 band->SetFillStyle(3002);
1190 band->SetLineStyle(2);
1191 band->SetLineWidth(1);
1192 band->Draw("3 same");
1193 band->DrawClone("X L same");
1194
e308a636 1195 fLeftRight->DrawClone("nostack e1 same");
b2e7f2d6 1196 if (isBottom) {
e308a636 1197 fRangeParam->fMasterAxis = FindXAxis(p3, fLeftRight->GetName());
b2e7f2d6 1198 p3->AddExec("range", Form("RangeExec((dNdetaDrawer::RangeParam*)%p)",
1199 fRangeParam));
1200 }
1201 else {
e308a636 1202 fRangeParam->fSlave2Axis = FindXAxis(p3, fLeftRight->GetName());
b2e7f2d6 1203 fRangeParam->fSlave2Pad = p3;
1204 }
1205 }
2f92ff0e 1206 /** @} */
1207 //==================================================================
1208 /**
1209 * @{
1210 * @name Data utility functions
1211 */
1212 /**
1213 * Get a result from the passed list
1214 *
1215 * @param list List to search
1216 * @param name Object name to search for
1217 *
290052e7 1218 * @return Histogram
2f92ff0e 1219 */
e1f47419 1220 TH1* FetchResult(const TList* list, const char* name) const
2f92ff0e 1221 {
1222 if (!list) return 0;
1223
e308a636 1224 TH1* ret = static_cast<TH1*>(list->FindObject(name));
5bb5d1f6 1225#if 0
e1f47419 1226 if (!ret) {
1227 // all->ls();
1228 Warning("GetResult", "Histogram %s not found", name);
2f92ff0e 1229 }
5bb5d1f6 1230#endif
b2e7f2d6 1231
e1f47419 1232 return ret;
2f92ff0e 1233 }
b2e7f2d6 1234 //__________________________________________________________________
2f92ff0e 1235 /**
1236 * Add a histogram to the stack after possibly rebinning it
1237 *
1238 * @param stack Stack to add to
1239 * @param hist histogram
1240 * @param option Draw options
1241 *
1242 * @return Maximum of histogram
1243 */
e308a636 1244 Double_t AddHistogram(THStack* stack, TH1* hist, Option_t* option="") const
b2e7f2d6 1245 {
1246 // Check if we have input
1247 if (!hist) return 0;
1248
1249 // Rebin if needed
1250 Rebin(hist);
1251
1252 stack->Add(hist, option);
1253 return hist->GetMaximum();
1254 }
1255 //__________________________________________________________________
2f92ff0e 1256 /**
1257 * Add a histogram to the stack after possibly rebinning it
1258 *
1259 * @param stack Stack to add to
1260 * @param hist histogram
1261 * @param option Draw options
1262 * @param sym On return, the data symmetriced (added to stack)
1263 *
1264 * @return Maximum of histogram
1265 */
e308a636 1266 Double_t AddHistogram(THStack* stack, TH1* hist, TH1*& sym,
1267 Option_t* option="") const
b2e7f2d6 1268 {
1269 // Check if we have input
1270 if (!hist) return 0;
1271
1272 // Rebin if needed
1273 Rebin(hist);
1274 stack->Add(hist, option);
1275
1276 // Now symmetrice the histogram
298a7264 1277 if (fMirror) {
1278 sym = Symmetrice(hist);
1279 stack->Add(sym, option);
1280 }
b2e7f2d6 1281
1282 return hist->GetMaximum();
1283 }
1284
1285 //__________________________________________________________________
1286 /**
1287 * Rebin a histogram
1288 *
1289 * @param h Histogram to rebin
b2e7f2d6 1290 */
1291 virtual void Rebin(TH1* h) const
1292 {
1293 if (fRebin <= 1) return;
1294
1295 Int_t nBins = h->GetNbinsX();
1296 if(nBins % fRebin != 0) {
1297 Warning("Rebin", "Rebin factor %d is not a devisor of current number "
1298 "of bins %d in the histogram %s", fRebin, nBins, h->GetName());
1299 return;
1300 }
1301
1302 // Make a copy
1303 TH1* tmp = static_cast<TH1*>(h->Clone("tmp"));
1304 tmp->Rebin(fRebin);
1305 tmp->SetDirectory(0);
e28f5fc5 1306 tmp->Reset();
b2e7f2d6 1307 // The new number of bins
1308 Int_t nBinsNew = nBins / fRebin;
1309 for(Int_t i = 1;i<= nBinsNew; i++) {
1310 Double_t content = 0;
1311 Double_t sumw = 0;
1312 Double_t wsum = 0;
1313 Int_t nbins = 0;
1314 for(Int_t j = 1; j<=fRebin;j++) {
1315 Int_t bin = (i-1)*fRebin + j;
1316 Double_t c = h->GetBinContent(bin);
1317
1318 if (c <= 0) continue;
1319
1320 if (fCutEdges) {
1321 if (h->GetBinContent(bin+1)<=0 ||
1322 h->GetBinContent(bin-1)) {
1323 Warning("Rebin", "removing bin %d=%f of %s (%d=%f,%d=%f)",
1324 bin, c, h->GetName(),
1325 bin+1, h->GetBinContent(bin+1),
1326 bin-1, h->GetBinContent(bin-1));
1327 continue;
1328 }
1329 }
1330 Double_t e = h->GetBinError(bin);
1331 Double_t w = 1 / (e*e); // 1/c/c
1332 content += c;
1333 sumw += w;
1334 wsum += w * c;
1335 nbins++;
1336 }
1337
e28f5fc5 1338 if(content > 0 && nbins > 1 ) {
b2e7f2d6 1339 tmp->SetBinContent(i, wsum / sumw);
1340 tmp->SetBinError(i,1./TMath::Sqrt(sumw));
1341 }
1342 }
1343
1344 // Finally, rebin the histogram, and set new content
1345 h->Rebin(fRebin);
1346 h->Reset();
1347 for(Int_t i = 1; i<= nBinsNew; i++) {
1348 h->SetBinContent(i,tmp->GetBinContent(i));
1349 h->SetBinError(i, tmp->GetBinError(i));
1350 }
1351
1352 delete tmp;
1353 }
1354 //__________________________________________________________________
1355 /**
1356 * Make an extension of @a h to make it symmetric about 0
1357 *
1358 * @param h Histogram to symmertrice
1359 *
1360 * @return Symmetric extension of @a h
1361 */
1362 TH1* Symmetrice(const TH1* h) const
1363 {
1364 Int_t nBins = h->GetNbinsX();
1365 TH1* s = static_cast<TH1*>(h->Clone(Form("%s_mirror", h->GetName())));
1366 s->SetTitle(Form("%s (mirrored)", h->GetTitle()));
1367 s->Reset();
1368 s->SetBins(nBins, -h->GetXaxis()->GetXmax(), -h->GetXaxis()->GetXmin());
1369 s->SetMarkerColor(h->GetMarkerColor());
1370 s->SetMarkerSize(h->GetMarkerSize());
1371 s->SetMarkerStyle(h->GetMarkerStyle()+4);
1372 s->SetFillColor(h->GetFillColor());
1373 s->SetFillStyle(h->GetFillStyle());
1374 s->SetDirectory(0);
1375
1376 // Find the first and last bin with data
1377 Int_t first = nBins+1;
1378 Int_t last = 0;
1379 for (Int_t i = 1; i <= nBins; i++) {
1380 if (h->GetBinContent(i) <= 0) continue;
1381 first = TMath::Min(first, i);
1382 last = TMath::Max(last, i);
1383 }
1384
1385 Double_t xfirst = h->GetBinCenter(first-1);
1386 Int_t f1 = h->GetXaxis()->FindBin(-xfirst);
1387 Int_t l2 = s->GetXaxis()->FindBin(xfirst);
1388 for (Int_t i = f1, j=l2; i <= last; i++,j--) {
1389 s->SetBinContent(j, h->GetBinContent(i));
1390 s->SetBinError(j, h->GetBinError(i));
1391 }
1392 // Fill in overlap bin
1393 s->SetBinContent(l2+1, h->GetBinContent(first));
1394 s->SetBinError(l2+1, h->GetBinError(first));
1395 return s;
1396 }
1397 //__________________________________________________________________
2f92ff0e 1398 /**
1399 * Calculate the left-right asymmetry of input histogram
1400 *
1401 * @param h Input histogram
1402 * @param max On return, the maximum distance from 1 of the histogram
1403 *
1404 * @return Asymmetry
1405 */
1406 TH1* Asymmetry(TH1* h, Double_t& max)
1407 {
1408 if (!h) return 0;
1409
1410 TH1* ret = static_cast<TH1*>(h->Clone(Form("%s_leftright", h->GetName())));
1411 // Int_t oBins = h->GetNbinsX();
1412 // Double_t high = h->GetXaxis()->GetXmax();
1413 // Double_t low = h->GetXaxis()->GetXmin();
1414 // Double_t dBin = (high - low) / oBins;
1415 // Int_t tBins = Int_t(2*high/dBin+.5);
1416 // ret->SetBins(tBins, -high, high);
e308a636 1417 ret->SetDirectory(0);
2f92ff0e 1418 ret->Reset();
1419 ret->SetTitle(Form("%s (+/-)", h->GetTitle()));
1420 ret->SetYTitle("Right/Left");
1421 Int_t nBins = h->GetNbinsX();
1422 for (Int_t i = 1; i <= nBins; i++) {
1423 Double_t x = h->GetBinCenter(i);
1424 if (x > 0) break;
1425
1426 Double_t c1 = h->GetBinContent(i);
1427 Double_t e1 = h->GetBinError(i);
1428 if (c1 <= 0) continue;
1429
1430 Int_t j = h->FindBin(-x);
1431 if (j <= 0 || j > nBins) continue;
1432
1433 Double_t c2 = h->GetBinContent(j);
1434 Double_t e2 = h->GetBinError(j);
1435
1436 Double_t c12 = c1*c1;
1437 Double_t e = TMath::Sqrt((e2*e2*c1*c1+e1*e1*c2*c2)/(c12*c12));
1438
1439 Int_t k = ret->FindBin(x);
1440 ret->SetBinContent(k, c2/c1);
1441 ret->SetBinError(k, e);
1442 }
1443 max = TMath::Max(max, RatioMax(ret));
1444
1445 return ret;
1446 }
1447 //__________________________________________________________________
1448 /**
1449 * Transform a graph into a histogram
1450 *
290052e7 1451 * @param g Graph
2f92ff0e 1452 *
290052e7 1453 * @return Histogram
2f92ff0e 1454 */
1455 TH1* Graph2Hist(const TGraphAsymmErrors* g) const
1456 {
1457 Int_t nBins = g->GetN();
1458 TArrayF bins(nBins+1);
1459 Double_t dx = 0;
1460 for (Int_t i = 0; i < nBins; i++) {
1461 Double_t x = g->GetX()[i];
1462 Double_t exl = g->GetEXlow()[i];
1463 Double_t exh = g->GetEXhigh()[i];
1464 bins.fArray[i] = x-exl;
1465 bins.fArray[i+1] = x+exh;
1466 Double_t dxi = exh+exl;
1467 if (i == 0) dx = dxi;
1468 else if (dxi != dx) dx = 0;
1469 }
1470 TString name(g->GetName());
1471 TString title(g->GetTitle());
1472 TH1D* h = 0;
1473 if (dx != 0) {
1474 h = new TH1D(name.Data(), title.Data(), nBins, bins[0], bins[nBins]);
1475 }
1476 else {
1477 h = new TH1D(name.Data(), title.Data(), nBins, bins.fArray);
1478 }
1479 h->SetMarkerStyle(g->GetMarkerStyle());
1480 h->SetMarkerColor(g->GetMarkerColor());
1481 h->SetMarkerSize(g->GetMarkerSize());
1482
1483 return h;
1484 }
1485 /* @} */
1486 //==================================================================
1487 /**
1488 * @{
1489 * @name Ratio utility functions
1490 */
1491 /**
1492 * Get the maximum diviation from 1 in the passed ratio
1493 *
1494 * @param h Ratio histogram
1495 *
1496 * @return Max diviation from 1
1497 */
b2e7f2d6 1498 Double_t RatioMax(TH1* h) const
1499 {
1500 Int_t nBins = h->GetNbinsX();
1501 Double_t ret = 0;
1502 for (Int_t i = 1; i <= nBins; i++) {
1503 Double_t c = h->GetBinContent(i);
1504 if (c == 0) continue;
1505 Double_t e = h->GetBinError(i);
1506 Double_t d = TMath::Abs(1-c-e);
1507 ret = TMath::Max(d, ret);
1508 }
1509 return ret;
1510 }
1511 //__________________________________________________________________
e1f47419 1512 /**
1513 * Make the ratio of h1 to h2
1514 *
ffca499d 1515 * @param o1 First object (numerator)
1516 * @param o2 Second object (denominator)
1517 * @param max Maximum diviation from 1
e1f47419 1518 *
ffca499d 1519 * @return o1 / o2
e1f47419 1520 */
1521 TH1* Ratio(const TObject* o1, const TObject* o2, Double_t& max) const
1522 {
b30dee70 1523 if (!o1 || !o2) return 0;
1524
5bb5d1f6 1525 TH1* r = 0;
1526 const TAttMarker* m1 = 0;
1527 const TAttMarker* m2 = 0;
e1f47419 1528 const TH1* h1 = dynamic_cast<const TH1*>(o1);
1529 if (h1) {
5bb5d1f6 1530 m1 = h1;
e1f47419 1531 const TH1* h2 = dynamic_cast<const TH1*>(o2);
ffca499d 1532 if (h2) {
5bb5d1f6 1533 m2 = h2;
1534 r = RatioHH(h1,h2);
ffca499d 1535 }
1536 else {
1537 const TGraph* g2 = dynamic_cast<const TGraph*>(o2);
1538 if (g2) {
5bb5d1f6 1539 m2 = g2;
1540 r = RatioHG(h1,g2);
ffca499d 1541 }
1542 }
e1f47419 1543 }
ffca499d 1544 else {
1545 const TGraphAsymmErrors* g1 = dynamic_cast<const TGraphAsymmErrors*>(o1);
1546 if (g1) {
5bb5d1f6 1547 m1 = g1;
ffca499d 1548 const TGraphAsymmErrors* g2 =
1549 dynamic_cast<const TGraphAsymmErrors*>(o2);
1550 if (g2) {
5bb5d1f6 1551 m2 = g2;
1552 r = RatioGG(g1, g2);
ffca499d 1553 }
1554 }
e1f47419 1555 }
ffca499d 1556 if (!r) {
1557 Warning("Ratio", "Don't know how to divide a %s (%s) with a %s (%s)",
1558 o1->ClassName(), o1->GetName(), o2->ClassName(), o2->GetName());
1559 return 0;
1560 }
1561 // Check that the histogram isn't empty
1562 if (r->GetEntries() <= 0) {
1563 delete r;
1564 r = 0;
1565 }
5bb5d1f6 1566 if (r) {
9ecab72f 1567 r->SetMarkerStyle(m2->GetMarkerStyle());
1568 r->SetMarkerColor(m1->GetMarkerColor());
cd3b3781 1569 if (TString(o2->GetName()).Contains("truth", TString::kIgnoreCase))
1570 r->SetMarkerStyle(m1->GetMarkerStyle());
5bb5d1f6 1571 r->SetMarkerSize(0.9*m1->GetMarkerSize());
1572 r->SetName(Form("%s_over_%s", o1->GetName(), o2->GetName()));
1573 r->SetTitle(Form("%s / %s", o1->GetTitle(), o2->GetTitle()));
1574 r->SetDirectory(0);
1575 max = TMath::Max(RatioMax(r), max);
1576 }
1577
ffca499d 1578 return r;
e1f47419 1579 }
1580 //__________________________________________________________________
b2e7f2d6 1581 /**
1582 * Compute the ratio of @a h to @a g. @a g is evaluated at the bin
1583 * centers of @a h
1584 *
1585 * @param h Numerator
1586 * @param g Divisor
1587 *
1588 * @return h/g
1589 */
5bb5d1f6 1590 TH1* RatioHG(const TH1* h, const TGraph* g) const
b2e7f2d6 1591 {
1592 if (!h || !g) return 0;
1593
1594 TH1* ret = static_cast<TH1*>(h->Clone("tmp"));
b2e7f2d6 1595 ret->Reset();
b2e7f2d6 1596 Double_t xlow = g->GetX()[0];
1597 Double_t xhigh = g->GetX()[g->GetN()-1];
1598 if (xlow > xhigh) { Double_t t = xhigh; xhigh = xlow; xlow = t; }
1599
1600 for (Int_t i = 1; i <= h->GetNbinsX(); i++) {
1601 Double_t c = h->GetBinContent(i);
1602 if (c <= 0) continue;
1603
1604 Double_t x = h->GetBinCenter(i);
1605 if (x < xlow || x > xhigh) continue;
1606
1607 Double_t f = g->Eval(x);
1608 if (f <= 0) continue;
1609
1610 ret->SetBinContent(i, c / f);
1611 ret->SetBinError(i, h->GetBinError(i) / f);
1612 }
b2e7f2d6 1613 return ret;
1614 }
1615 //__________________________________________________________________
1616 /**
1617 * Make the ratio of h1 to h2
1618 *
1619 * @param h1 First histogram (numerator)
1620 * @param h2 Second histogram (denominator)
1621 *
1622 * @return h1 / h2
1623 */
5bb5d1f6 1624 TH1* RatioHH(const TH1* h1, const TH1* h2) const
b2e7f2d6 1625 {
1626 if (!h1 || !h2) return 0;
5bb5d1f6 1627 TH1* t1 = static_cast<TH1*>(h1->Clone("tmp"));
b2e7f2d6 1628 t1->Divide(h2);
b2e7f2d6 1629 return t1;
1630 }
1631 //__________________________________________________________________
1632 /**
1633 * Calculate the ratio of two graphs - g1 / g2
1634 *
1635 * @param g1 Numerator
1636 * @param g2 Denominator
1637 *
1638 * @return g1 / g2 in a histogram
1639 */
ffca499d 1640 TH1* RatioGG(const TGraphAsymmErrors* g1,
5bb5d1f6 1641 const TGraphAsymmErrors* g2) const
b2e7f2d6 1642 {
1643 Int_t nBins = g1->GetN();
1644 TArrayF bins(nBins+1);
1645 Double_t dx = 0;
1646 for (Int_t i = 0; i < nBins; i++) {
1647 Double_t x = g1->GetX()[i];
1648 Double_t exl = g1->GetEXlow()[i];
1649 Double_t exh = g1->GetEXhigh()[i];
1650 bins.fArray[i] = x-exl;
1651 bins.fArray[i+1] = x+exh;
1652 Double_t dxi = exh+exl;
1653 if (i == 0) dx = dxi;
1654 else if (dxi != dx) dx = 0;
1655 }
b2e7f2d6 1656 TH1* h = 0;
1657 if (dx != 0) {
5bb5d1f6 1658 h = new TH1F("tmp", "tmp", nBins, bins[0], bins[nBins]);
b2e7f2d6 1659 }
1660 else {
5bb5d1f6 1661 h = new TH1F("tmp", "tmp", nBins, bins.fArray);
b2e7f2d6 1662 }
b2e7f2d6 1663
1664 Double_t low = g2->GetX()[0];
1665 Double_t high = g2->GetX()[g2->GetN()-1];
1666 if (low > high) { Double_t t = low; low = high; high = t; }
1667 for (Int_t i = 0; i < nBins; i++) {
1668 Double_t x = g1->GetX()[i];
1669 if (x < low-dx || x > high+dx) continue;
1670 Double_t c1 = g1->GetY()[i];
1671 Double_t e1 = g1->GetErrorY(i);
1672 Double_t c2 = g2->Eval(x);
1673
1674 h->SetBinContent(i+1, c1 / c2);
1675 h->SetBinError(i+1, e1 / c2);
1676 }
b2e7f2d6 1677 return h;
2f92ff0e 1678 }
1679 /* @} */
1680 //==================================================================
1681 /**
1682 * @{
1683 * @name Graphics utility functions
1684 */
1685 /**
1686 * Find an X axis in a pad
1687 *
1688 * @param p Pad
1689 * @param name Histogram to find axis for
1690 *
1691 * @return Found axis or null
1692 */
1693 TAxis* FindXAxis(TVirtualPad* p, const char* name)
b2e7f2d6 1694 {
2f92ff0e 1695 TObject* o = p->GetListOfPrimitives()->FindObject(name);
1696 if (!o) {
1697 Warning("FindXAxis", "%s not found in pad", name);
1698 return 0;
b2e7f2d6 1699 }
2f92ff0e 1700 THStack* stack = dynamic_cast<THStack*>(o);
1701 if (!stack) {
1702 Warning("FindXAxis", "%s is not a THStack", name);
1703 return 0;
b2e7f2d6 1704 }
2f92ff0e 1705 if (!stack->GetHistogram()) {
1706 Warning("FindXAxis", "%s has no histogram", name);
1707 return 0;
b2e7f2d6 1708 }
2f92ff0e 1709 TAxis* ret = stack->GetHistogram()->GetXaxis();
1710 return ret;
b2e7f2d6 1711 }
2f92ff0e 1712
b2e7f2d6 1713 //__________________________________________________________________
2f92ff0e 1714 /**
1715 * Fix the apperance of the axis in a stack
1716 *
1717 * @param stack stack of histogram
c6115ede 1718 * @param yd How the canvas is cut
2f92ff0e 1719 * @param ytitle Y axis title
2f92ff0e 1720 * @param ynDiv Divisions on Y axis
c6115ede 1721 * @param force Whether to draw the stack first or not
2f92ff0e 1722 */
797161e8 1723 void FixAxis(THStack* stack, Double_t yd, const char* ytitle,
2f92ff0e 1724 Int_t ynDiv=210, Bool_t force=true)
b2e7f2d6 1725 {
e308a636 1726 if (!stack) {
1727 Warning("FixAxis", "No stack passed for %s!", ytitle);
1728 return;
1729 }
2f92ff0e 1730 if (force) stack->Draw("nostack e1");
b2e7f2d6 1731
2f92ff0e 1732 TH1* h = stack->GetHistogram();
e308a636 1733 if (!h) {
1734 Warning("FixAxis", "Stack %s has no histogram", stack->GetName());
1735 return;
1736 }
797161e8 1737 Double_t s = 1/yd/1.2;
1738 // Info("FixAxis", "for %s, s=1/%f=%f", stack->GetName(), yd, s);
1739
1740 h->SetXTitle("#font[152]{#eta}");
2f92ff0e 1741 h->SetYTitle(ytitle);
1742 TAxis* xa = h->GetXaxis();
1743 TAxis* ya = h->GetYaxis();
797161e8 1744
1745 // Int_t npixels = 20
1746 // Float_t dy = gPad->AbsPixeltoY(0) - gPad->AbsPixeltoY(npixels);
1747 // Float_t ts = dy/(gPad->GetY2() - gPad->GetY1());
1748
2f92ff0e 1749 if (xa) {
797161e8 1750 // xa->SetTitle(h->GetXTitle());
2f92ff0e 1751 // xa->SetTicks("+-");
1752 xa->SetTitleSize(s*xa->GetTitleSize());
1753 xa->SetLabelSize(s*xa->GetLabelSize());
1754 xa->SetTickLength(s*xa->GetTickLength());
797161e8 1755 // xa->SetTitleOffset(xa->GetTitleOffset()/s);
e308a636 1756
1757 if (stack != fResults) {
1758 TAxis* rxa = fResults->GetXaxis();
1759 xa->Set(rxa->GetNbins(), rxa->GetXmin(), rxa->GetXmax());
1760 }
2f92ff0e 1761 }
1762 if (ya) {
797161e8 1763 // ya->SetTitle(h->GetYTitle());
2f92ff0e 1764 ya->SetDecimals();
1765 // ya->SetTicks("+-");
1766 ya->SetNdivisions(ynDiv);
1767 ya->SetTitleSize(s*ya->GetTitleSize());
1768 ya->SetTitleOffset(ya->GetTitleOffset()/s);
1769 ya->SetLabelSize(s*ya->GetLabelSize());
b2e7f2d6 1770 }
b2e7f2d6 1771 }
797161e8 1772 //__________________________________________________________________
1773 /**
1774 * Merge two histograms into one
1775 *
1776 * @param cen Central part
1777 * @param fwd Forward part
1778 * @param xlow On return, lower eta bound
1779 * @param xhigh On return, upper eta bound
1780 *
1781 * @return Newly allocated histogram or null
1782 */
1783 TH1*
1784 Merge(const TH1* cen, const TH1* fwd, Double_t& xlow, Double_t& xhigh)
1785 {
1786 TH1* tmp = static_cast<TH1*>(fwd->Clone("tmp"));
1787 TString name(fwd->GetName());
1788 name.ReplaceAll("Forward", "Merged");
1789 tmp->SetName(name);
1790
1791 // tmp->SetMarkerStyle(28);
1792 // tmp->SetMarkerColor(kBlack);
1793 tmp->SetDirectory(0);
1794 xlow = 100;
1795 xhigh = -100;
1796 for (Int_t i = 1; i <= tmp->GetNbinsX(); i++) {
1797 Double_t cc = cen->GetBinContent(i);
1798 Double_t cf = fwd->GetBinContent(i);
1799 Double_t ec = cen->GetBinError(i);
1800 Double_t ef = fwd->GetBinError(i);
1801 Double_t nc = cf;
1802 Double_t ne = ef;
1803 if (cc < 0.001 && cf < 0.01) continue;
1804 xlow = TMath::Min(tmp->GetXaxis()->GetBinLowEdge(i),xlow);
1805 xhigh = TMath::Max(tmp->GetXaxis()->GetBinUpEdge(i),xhigh);
1806 if (cc > 0.001) {
1807 nc = cc;
1808 ne = ec;
1809 if (cf > 0.001) {
1810 nc = (cf + cc) / 2;
1811 ne = TMath::Sqrt(ec*ec + ef*ef);
1812 }
1813 }
1814 tmp->SetBinContent(i, nc);
1815 tmp->SetBinError(i, ne);
1816 }
1817 return tmp;
1818 }
1819 //____________________________________________________________________
1820 /**
1821 * Fit @f$g(x;A_1,A_2,\sigma_1,\sigma_2)@f$ to histogram data
1822 *
1823 * @param tmp Histogram
1824 * @param xlow Lower x bound
1825 * @param xhigh Upper x bound
1826 *
1827 * @return Fitted function
1828 */
1829 TF1*
1830 FitMerged(TH1* tmp, Double_t xlow, Double_t xhigh)
1831 {
1832 TF1* tmpf = new TF1("tmpf", "gaus", xlow, xhigh);
1833 tmp->Fit(tmpf, "NQ", "");
1834 tmp->SetDirectory(0);
1835
1836 TF1* fit = new TF1("f", myFunc, xlow, xhigh, 4);
1837 fit->SetParNames("a_{1}", "a_{2}", "#sigma_{1}", "#sigma_{2}");
1838 fit->SetParameters(tmpf->GetParameter(0),
1839 .2,
1840 tmpf->GetParameter(2),
1841 tmpf->GetParameter(2)/4);
1842 fit->SetParLimits(3, 0, 100);
1843 fit->SetParLimits(4, 0, 100);
1844 tmp->Fit(fit,"0W","");
1845
1846 delete tmpf;
1847 return fit;
1848 }
1849 //____________________________________________________________________
1850 /**
1851 * Make band of systematic errors
1852 *
1853 * @param tmp Histogram
c6115ede 1854 * @param cen Central
1855 * @param fwd Forward
797161e8 1856 * @param fit Fit
1857 */
1858 void
1859 MakeSysError(TH1* tmp, TH1* cen, TH1* fwd, TF1* fit)
1860 {
1861 for (Int_t i = 1; i <= tmp->GetNbinsX(); i++) {
1862 Double_t tc = tmp->GetBinContent(i);
1863 if (tc < 0.01) continue;
1864 Double_t fc = fwd->GetBinContent(i);
1865 Double_t cc = cen->GetBinContent(i);
1866 Double_t sysErr = fFwdSysErr;
1867 if (cc > .01 && fc > 0.01)
1868 sysErr = (fFwdSysErr+fCenSysErr) / 2;
1869 else if (cc > .01)
1870 sysErr = fCenSysErr;
1871 Double_t x = tmp->GetXaxis()->GetBinCenter(i);
1872 Double_t y = fit->Eval(x);
1873 tmp->SetBinContent(i, y);
1874 tmp->SetBinError(i,sysErr*y);
1875 }
1876 TString name(tmp->GetName());
1877 name.ReplaceAll("Merged", "SysError");
1878 tmp->SetName(name);
e42bc740 1879 tmp->SetMarkerColor(SYSERR_COLOR);
1880 tmp->SetLineColor(SYSERR_COLOR);
1881 tmp->SetFillColor(SYSERR_COLOR);
1882 tmp->SetFillStyle(SYSERR_STYLE);
797161e8 1883 tmp->SetMarkerStyle(0);
1884 tmp->SetLineWidth(0);
1885 }
1886 void CorrectForward(TH1* h) const
1887 {
1888 if (!fRemoveOuters) return;
1889
1890 for (Int_t i = 1; i <= h->GetNbinsX(); i++) {
1891 Double_t eta = h->GetBinCenter(i);
1892 if (TMath::Abs(eta) < 2.3) {
1893 h->SetBinContent(i, 0);
1894 h->SetBinError(i, 0);
1895 }
1896 }
1897 }
1898 void CorrectCentral(TH1* h) const
1899 {
1900 if (fClusterScale.IsNull()) return;
1901 TString t(h->GetTitle());
1902 Info("CorrectCentral", "Replacing Central with Tracklets in %s", t.Data());
1903 t.ReplaceAll("Central", "Tracklets");
1904 h->SetTitle(t);
1905
1906 TF1* cf = new TF1("clusterScale", fClusterScale);
1907 for (Int_t i = 1; i <= h->GetNbinsX(); i++) {
1908 Double_t eta = h->GetBinCenter(i);
1909 Double_t f = cf->Eval(eta);
1910 Double_t c = h->GetBinContent(i);
1911 if (f < .1) f = 1;
1912 h->SetBinContent(i, c / f);
1913 }
1914 delete cf;
1915 }
33ab4a11 1916 //____________________________________________________________________
1917 void Export(const char* basename)
1918 {
1919 TString bname(basename);
1920 bname.ReplaceAll(" ", "_");
1921 bname.ReplaceAll("-", "_");
1922 TString fname(Form("%s.C", bname.Data()));
1923
298a7264 1924 std::ofstream outf(fname.Data());
1925 if (!outf) {
33ab4a11 1926 Error("Export", "Failed to open output file %s", fname.Data());
1927 return;
1928 }
298a7264 1929 outf << "// Create by dNdetaDrawer\n"
1930 << "void " << bname << "(THStack* stack, TLegend* l, Int_t m)\n"
1931 << "{"
1932 << " Int_t ma[] = { 24, 25, 26, 32,\n"
1933 << " 20, 21, 22, 33,\n"
1934 << " 34, 30, 29, 0, \n"
1935 << " 23, 27 };\n"
1936 << " Int_t mm = ((m < 20 || m > 34) ? 0 : ma[m-20]);\n\n";
33ab4a11 1937 TList* hists = fResults->GetHists();
1938 TIter next(hists);
1939 TH1* hist = 0;
1940 while ((hist = static_cast<TH1*>(next()))) {
1941 TString hname = hist->GetName();
1942 hname.Append(Form("_%04x", (gRandom->Integer(0xffff) & 0xffff)));
1943 hist->SetName(hname);
1944 hist->GetListOfFunctions()->Clear();
298a7264 1945 hist->SavePrimitive(outf, "nodraw");
33ab4a11 1946 bool mirror = hname.Contains("mirror");
1947 bool syserr = hname.Contains("SysError");
1948 if (!syserr)
298a7264 1949 outf << " " << hname << "->SetMarkerStyle("
1950 << (mirror ? "mm" : "m") << ");\n";
33ab4a11 1951 else
298a7264 1952 outf << " " << hname << "->SetMarkerStyle(1);\n";
1953 outf << " stack->Add(" << hname
1954 << (syserr ? ",\"e5\"" : "") << ");\n\n";
33ab4a11 1955 }
1956 UShort_t snn = fSNNString->GetUniqueID();
1957 // const char* sys = fSysString->GetTitle();
1958 TString eS;
1959 if (snn == 2750) snn = 2760;
1960 if (snn < 1000) eS = Form("%3dGeV", snn);
1961 else if (snn % 1000 == 0) eS = Form("%dTeV", snn/1000);
1962 else eS = Form("%4.2fTeV", float(snn)/1000);
298a7264 1963 outf << " if (l) {\n"
1964 << " TLegendEntry* e = l->AddEntry(\"\",\"" << eS << "\",\"pl\");\n"
1965 << " e->SetMarkerStyle(m);\n"
1966 << " e->SetMarkerColor(kBlack);\n"
1967 << " }\n"
1968 << "}\n" << std::endl;
33ab4a11 1969 }
09d8cf0a 1970 /* @} */
298a7264 1971 Bool_t HasCent() const { return fCentAxis && !fForceMB; }
2f92ff0e 1972
b2e7f2d6 1973
1974
1975 //__________________________________________________________________
33ab4a11 1976 /**
1977 * @{
1978 * @name Options
1979 */
e308a636 1980 Bool_t fShowRatios; // Show ratios
1981 Bool_t fShowLeftRight;// Show asymmetry
f709afcf 1982 Bool_t fShowRings; // Show rings too
33ab4a11 1983 Bool_t fExport; // Export results to file
e308a636 1984 Bool_t fCutEdges; // Whether to cut edges
33ab4a11 1985 Bool_t fRemoveOuters; // Whether to remove outers
1986 UShort_t fShowOthers; // Show other data
298a7264 1987 Bool_t fMirror; // Whether to mirror
1988 Bool_t fForceMB; // Force min-bias
33ab4a11 1989 /* @} */
1990 /**
1991 * @{
1992 * @name Settings
1993 */
1994 UShort_t fRebin; // Rebinning factor
1995 Double_t fFwdSysErr; // Systematic error in forward range
1996 Double_t fCenSysErr; // Systematic error in central range
e308a636 1997 TString fTitle; // Title on plot
33ab4a11 1998 TString fClusterScale; // Scaling of clusters to tracklets
1999 /* @} */
2000 /**
2001 * @{
2002 * @name Read (or set) information
2003 */
e308a636 2004 TNamed* fTrigString; // Trigger string (read, or set)
0be6c8cd 2005 TNamed* fNormString; // Normalisation string (read, or set)
e308a636 2006 TNamed* fSNNString; // Energy string (read, or set)
2007 TNamed* fSysString; // Collision system string (read or set)
2008 TAxis* fVtxAxis; // Vertex cuts (read or set)
2009 TAxis* fCentAxis; // Centrality axis
33ab4a11 2010 /* @} */
2011 /**
2012 * @{
2013 * @name Resulting plots
2014 */
e308a636 2015 THStack* fResults; // Stack of results
2016 THStack* fRatios; // Stack of ratios
2017 THStack* fLeftRight; // Left-right asymmetry
2018 TMultiGraph* fOthers; // Older data
2019 TH1* fTriggers; // Number of triggers
9ecab72f 2020 TH1* fTruth; // Pointer to truth
33ab4a11 2021 /* @} */
e308a636 2022 RangeParam* fRangeParam; // Parameter object for range zoom
b2e7f2d6 2023};
2024
797161e8 2025//____________________________________________________________________
2026/**
2027 * Function to calculate
2028 * @f[
2029 * g(x;A_1,A_2,\sigma_1,\sigma_2) =
2030 * A_1\left(\frac{1}{2\pi\sigma_1}e^{(x/\sigma_1)^2} -
2031 * A_2\frac{1}{2\pi\sigma_2}e^{(x/\sigma_2)^2}\right)
2032 * @f]
2033 *
2034 * @param xp Pointer to x array
2035 * @param pp Pointer to parameter array
2036 *
2037 * @return @f$g(x;A_1,A_2,\sigma_1,\sigma_2)@f$
2038 */
2039Double_t myFunc(Double_t* xp, Double_t* pp)
2040{
2041 Double_t x = xp[0];
2042 Double_t a1 = pp[0];
2043 Double_t a2 = pp[1];
2044 Double_t s1 = pp[2];
2045 Double_t s2 = pp[3];
2046 return a1*(TMath::Gaus(x, 0, s1) - a2 * TMath::Gaus(x, 0, s2));
2047}
2048
b2e7f2d6 2049//=== Stuff for auto zooming =========================================
290052e7 2050/**
2051 * Update canvas range
2052 *
2053 * @param p Parameter
2054 */
b2e7f2d6 2055void UpdateRange(dNdetaDrawer::RangeParam* p)
2056{
2057 if (!p) {
2058 Warning("UpdateRange", "No parameters %p", p);
2059 return;
2060 }
2061 if (!p->fMasterAxis) {
2062 Warning("UpdateRange", "No master axis %p", p->fMasterAxis);
2063 return;
2064 }
2065 Int_t first = p->fMasterAxis->GetFirst();
2066 Int_t last = p->fMasterAxis->GetLast();
2067 Double_t x1 = p->fMasterAxis->GetBinCenter(first);
2068 Double_t x2 = p->fMasterAxis->GetBinCenter(last);
b2e7f2d6 2069
2070 if (p->fSlave1Axis) {
2071 Int_t i1 = p->fSlave1Axis->FindBin(x1);
2072 Int_t i2 = p->fSlave1Axis->FindBin(x2);
2073 p->fSlave1Axis->SetRange(i1, i2);
2074 p->fSlave1Pad->Modified();
2075 p->fSlave1Pad->Update();
2076 }
2077 if (p->fSlave2Axis) {
2078 Int_t i1 = p->fSlave2Axis->FindBin(x1);
2079 Int_t i2 = p->fSlave2Axis->FindBin(x2);
2080 p->fSlave2Axis->SetRange(i1, i2);
2081 p->fSlave2Pad->Modified();
2082 p->fSlave2Pad->Update();
2083 }
2084 TCanvas* c = gPad->GetCanvas();
2085 c->cd();
2086}
2087
2088//____________________________________________________________________
290052e7 2089/**
2090 * Called when user changes X range
2091 *
2092 * @param p Parameter
2093 */
b2e7f2d6 2094void RangeExec(dNdetaDrawer::RangeParam* p)
2095{
2096 // Event types:
2097 // 51: Mouse move
2098 // 53:
2099 // 1: Button down
2100 // 21: Mouse drag
2101 // 11: Mouse release
2102 // dNdetaDrawer::RangeParam* p =
2103 // reinterpret_cast<dNdetaDrawer::RangeParam*>(addr);
2104 Int_t event = gPad->GetEvent();
2105 TObject *select = gPad->GetSelected();
2106 if (event == 53) {
2107 UpdateRange(p);
2108 return;
2109 }
2110 if (event != 11 || !select || select != p->fMasterAxis) return;
2111 UpdateRange(p);
2112}
2113
33ab4a11 2114//=== Steering functions
2115//==============================================
290052e7 2116/**
2117 * Display usage information
2118 *
2119 */
33ab4a11 2120void
2121Usage()
2122{
2123 Info("DrawdNdeta", "Usage: DrawdNdeta(FILE,TITLE,REBIN,OTHERS,FLAGS)\n\n"
2124 " const char* FILE File name to open (\"forward_root\")\n"
2125 " const char* TITLE Title to put on plot (\"\")\n"
2126 " UShort_t REBIN Rebinning factor (1)\n"
2127 " UShort_t OTHERS Other data to draw - more below (0x7)\n"
2128 " UShort_t FLAGS Visualisation flags - more below (0x7)\n\n"
2129 " OTHERS is a bit mask of\n\n"
2130 " 0x1 Show UA5 data (INEL,NSD, ppbar, 900GeV)\n"
2131 " 0x2 Show CMS data (NSD, pp)\n"
2132 " 0x4 Show published ALICE data (INEL,INEL>0,NSD, pp)\n"
2133 " 0x8 Show event genertor data\n\n"
2134 " FLAGS is a bit mask of\n\n"
2135 " 0x1 Show ratios of data to other data and possibly MC\n"
2136 " 0x2 Show left-right asymmetry\n"
2137 " 0x4 Show systematic error band\n"
2138 " 0x8 Show individual ring results (INEL only)\n"
2139 " 0x10 Cut edges when rebinning\n"
2140 " 0x20 Remove FMDxO points\n"
2141 " 0x40 Do not make our own canvas\n"
298a7264 2142 " 0x80 Force use of MB\n"
2143 " 0x100 Mirror data\n"
33ab4a11 2144 );
2145}
2146
2147//____________________________________________________________________
ffca499d 2148/**
2149 * Draw @f$ dN/d\eta@f$
2150 *
2151 * @param filename File name
ffca499d 2152 * @param title Title
2153 * @param rebin Rebinning factor
c6115ede 2154 * @param others What other data to show
2155 * @param flags Flags
ffca499d 2156 * @param sNN (optional) Collision energy [GeV]
2157 * @param sys (optional) Collision system (1: pp, 2: PbPb)
2158 * @param trg (optional) Trigger (1: INEL, 2: INEL>0, 4: NSD)
2159 * @param vzMin Least @f$ v_z@f$
2160 * @param vzMax Largest @f$ v_z@f$
2161 *
bd6f5206 2162 * @ingroup pwglf_forward_dndeta
ffca499d 2163 */
b2e7f2d6 2164void
2165DrawdNdeta(const char* filename="forward_dndeta.root",
bad9a3c1 2166 const char* title="",
b2e7f2d6 2167 UShort_t rebin=5,
797161e8 2168 UShort_t others=0x7,
298a7264 2169 UShort_t flags=0x187,
fe52e455 2170 UShort_t sNN=0,
2171 UShort_t sys=0,
ffca499d 2172 UShort_t trg=0,
fe52e455 2173 Float_t vzMin=999,
2174 Float_t vzMax=-999)
b2e7f2d6 2175{
33ab4a11 2176 TString fname(filename);
2177 fname.ToLower();
2178 if (fname.CompareTo("help") == 0 ||
2179 fname.CompareTo("--help") == 0) {
2180 Usage();
2181 return;
2182 }
ffca499d 2183 dNdetaDrawer* pd = new dNdetaDrawer;
2184 dNdetaDrawer& d = *pd;
b2e7f2d6 2185 d.SetRebin(rebin);
b2e7f2d6 2186 d.SetTitle(title);
797161e8 2187 d.SetShowOthers(others);
2188 d.SetShowRatios(flags & 0x1);
2189 d.SetShowLeftRight(flags & 0x2);
2190 d.SetForwardSysError(flags & 0x4 ? 0.076 : 0);
2191 d.SetShowRings(flags & 0x8);
2192 d.SetCutEdges(flags & 0x10);
33ab4a11 2193 d.fRemoveOuters = (flags & 0x20);
2194 d.SetExport(flags & 0x40);
298a7264 2195 d.SetForceMB(flags & 0x80);
2196 d.SetMirror(flags & 0x100);
797161e8 2197 // d.fClusterScale = "1.06 -0.003*x +0.0119*x*x";
2f92ff0e 2198 // Do the below if your input data does not contain these settings
fe52e455 2199 if (sNN > 0) d.SetSNN(sNN); // Collision energy per nucleon pair (GeV)
2200 if (sys > 0) d.SetSys(sys); // Collision system (1:pp, 2:PbPB)
2201 if (trg > 0) d.SetTrigger(trg); // Collision trigger (1:INEL, 2:INEL>0, 4:NSD)
2202 if (vzMin < 999 && vzMax > -999)
2203 d.SetVertexRange(vzMin,vzMax); // Collision vertex range (cm)
b2e7f2d6 2204 d.Run(filename);
2205}
2f92ff0e 2206//____________________________________________________________________
2207//
2208// EOF
2209//
2210