]> git.uio.no Git - u/mrichter/AliRoot.git/blob - PWGLF/FORWARD/analysis2/scripts/SummaryDrawer.C
Some new options
[u/mrichter/AliRoot.git] / PWGLF / FORWARD / analysis2 / scripts / SummaryDrawer.C
1 /**
2  * @file   SummaryDrawer.C
3  * @author Christian Holm Christensen <cholm@master.hehi.nbi.dk>
4  * @date   Sun Nov 25 11:36:41 2012
5  * 
6  * @brief  Base class for classes to draw summaries 
7  * 
8  * 
9  */
10 #ifndef SUMMARYDRAWER_C
11 # define SUMMARYDRAWER_C
12 # ifndef __CINT__
13 #  include <THStack.h>
14 #  include <TH1.h>
15 #  include <TH2.h>
16 #  include <TH3.h>
17 #  include <TParameter.h>
18 #  include <TCanvas.h>
19 #  include <TList.h>
20 #  include <TFile.h>
21 #  include <TError.h>
22 #  include <TLatex.h>
23 #  include <TLegend.h>
24 #  include <TLegendEntry.h>
25 #  include <TMath.h>
26 #  include <TString.h>
27 #  include <TStyle.h>
28 #  include <TSystem.h>
29 #  include <TProfile.h>
30 #  include <TGaxis.h>
31 #  include <TPad.h>
32 #  include <TRegexp.h>
33 #  include <TGraph.h>
34 #  include <sstream>
35 #  include <iomanip>
36 # else 
37 #  ifdef __ACLIC__
38 class THStack;
39 class TH1;
40 class TH2;
41 class TH3;
42 class TCollection;
43 class TCanvas;
44 class TVirtualPad;
45 class TPad;
46 class TLatex;
47 class TAxis;
48 #  endif
49 # endif
50
51 /**
52  * Base class for summary drawers
53  * 
54  */
55 class SummaryDrawer 
56 {
57 public:
58   enum { 
59     kLogx   = 0x1, 
60     kLogy   = 0x2, 
61     kLogz   = 0x4, 
62     kLegend = 0x10, 
63     kGridx  = 0x100, 
64     kGridy  = 0x200, 
65     kGridz  = 0x400,
66     kSilent = 0x800,
67     kNorth  = 0x1000, 
68     kMiddle = 0x2000,
69     kSouth  = 0x3000, 
70     kEast   = 0x10000, 
71     kCenter = 0x20000,
72     kWest   = 0x30000
73   };
74   enum { 
75     kLandscape         = 0x100, 
76     kPause             = 0x200
77   };    
78   SummaryDrawer() 
79     : fCanvas(0), 
80       fTop(0), 
81       fBody(0),
82       fHeader(0),
83       fParName(0),
84       fParVal(0),
85       fPause(false),
86       fLandscape(false), 
87       fRingMap(0), 
88       fPDF(true),
89       fLastTitle("")
90   {
91     fRingMap = new TVirtualPad*[6];
92     fRingMap[0] = 0;
93     fRingMap[1] = 0;
94     fRingMap[2] = 0;
95     fRingMap[3] = 0;
96     fRingMap[4] = 0;
97     fRingMap[5] = 0;
98   }
99   virtual ~SummaryDrawer() {}
100
101 protected:
102   //____________________________________________________________________
103   /** 
104    * Get null terminated array of ring names 
105    * 
106    * @param lower If true, return in the form FMD[1-3][io], otherwise 
107    *              in the form FMD[1-3][IO]
108    * 
109    * @return Null terminated array of ring names 
110    */
111   static const Char_t** GetRingNames(Bool_t lower=false) 
112   {
113     static const Char_t* lN[]={ "FMD1i", "FMD2i", "FMD2o", "FMD3o", "FMD3i", 0};
114     static const Char_t* uN[]={ "FMD1I", "FMD2I", "FMD2O", "FMD3O", "FMD3I", 0};
115     return (lower ? lN : uN);
116   }
117   //____________________________________________________________________
118   /** 
119    * Get the standard color for a ring  
120    *
121    * @param d Detector
122    * @param r Ring 
123    * 
124    * @return 
125    */
126   static Color_t RingColor(UShort_t d, Char_t r)
127   { 
128     return ((d == 1 ? kRed : (d == 2 ? kGreen : kBlue))
129             + ((r == 'I' || r == 'i') ? 2 : -3));
130   }
131   //____________________________________________________________________
132   TLegend* DrawRingLegend(TVirtualPad* p, UInt_t flags)
133   {
134     TLegend* l = MakeLegend(p, flags, false);
135
136     for (UShort_t i = 0; i < 5; i++) {
137       UShort_t      d = (i+1)/2+1;
138       Char_t        r = (i/2 == 1) ? 'o' : 'i';
139       TLegendEntry* e = l->AddEntry("dummy", Form("FMD%d%c", d, r), "f");
140       e->SetFillColor(RingColor(d, r));
141       e->SetFillStyle(1001);
142       e->SetLineColor(kBlack);
143     }
144    
145     l->Draw();
146     return l;
147   }
148   //____________________________________________________________________
149   static void SysString(UShort_t sys, TString& str)
150   {
151     str = "?";
152     switch (sys) { 
153     case 1: str = "pp"; break;
154     case 2: str = "PbPb"; break;
155     case 3: str = "pPb"; break;
156     }
157   }
158   //____________________________________________________________________
159   static void SNNString(UShort_t sNN, TString& str)
160   {
161     str = "?";
162     if      (sNN < 1000) str = Form("%dGeV", sNN);
163     else if (sNN < 3000) str = Form("%4.2fTeV", 0.001*sNN);
164     else                 str = Form("%dTeV", sNN/1000);
165   }
166   //____________________________________________________________________
167   /** 
168    * Append an & to a string and the next term.
169    * 
170    * @param trg  Output string
171    * @param what Term
172    */
173   static void AppendAnd(TString& trg, const TString& what)
174   {
175     if (!trg.IsNull()) trg.Append(" & ");
176     trg.Append(what);
177   }
178   //____________________________________________________________________
179   static void TriggerString(ULong_t trigger, TString& str)
180   {
181     str = "";
182         /** 
183      * Bits of the trigger pattern
184      */
185     enum { 
186       /** In-elastic collision */
187       kInel        = 0x0001, 
188       /** In-elastic collision with at least one SPD tracklet */
189       kInelGt0     = 0x0002, 
190       /** Non-single diffractive collision */
191       kNSD         = 0x0004, 
192       /** Empty bunch crossing */
193       kEmpty       = 0x0008, 
194       /** A-side trigger */
195       kA           = 0x0010, 
196       /** B(arrel) trigger */
197       kB           = 0x0020, 
198       /** C-side trigger */
199       kC           = 0x0080,  
200       /** Empty trigger */
201       kE           = 0x0100,
202       /** pileup from SPD */
203       kPileUp      = 0x0200,    
204       /** true NSD from MC */
205       kMCNSD       = 0x0400,    
206       /** Offline MB triggered */
207       kOffline     = 0x0800,
208       /** At least one SPD cluster */ 
209       kNClusterGt0 = 0x1000,
210       /** V0-AND trigger */
211       kV0AND       = 0x2000, 
212       /** Satellite event */
213       kSatellite   = 0x4000
214     };
215     if ((trigger & kInel)        != 0x0) AppendAnd(str, "INEL");
216     if ((trigger & kInelGt0)     != 0x0) AppendAnd(str, "INEL>0");
217     if ((trigger & kNSD)         != 0x0) AppendAnd(str, "NSD");
218     if ((trigger & kV0AND)       != 0x0) AppendAnd(str, "V0AND");
219     if ((trigger & kA)           != 0x0) AppendAnd(str, "A");
220     if ((trigger & kB)           != 0x0) AppendAnd(str, "B");
221     if ((trigger & kC)           != 0x0) AppendAnd(str, "C");
222     if ((trigger & kE)           != 0x0) AppendAnd(str, "E");
223     if ((trigger & kMCNSD)       != 0x0) AppendAnd(str, "MCNSD");
224     if ((trigger & kNClusterGt0) != 0x0) AppendAnd(str, "NCluster>0");
225     if ((trigger & kSatellite)   != 0x0) AppendAnd(str, "Satellite");
226   }
227     
228   //__________________________________________________________________
229   /** 
230    * Find an object in a collection
231    * 
232    * @param parent Parent directory
233    * @param name   Name of object
234    * @param verb   Be verbose 
235    * 
236    * @return Pointer to object or null 
237    */
238   static TObject* GetObject(const TObject* parent, 
239                             const TString& name, 
240                             Bool_t verb=true)
241   {
242     if (!parent) {
243       if (verb) Warning("GetObject", "No parent given");
244       return 0;
245     }
246     if (name.IsNull()) { 
247       if (verb) Warning("GetObject", "No name specified");
248       return 0;
249     }
250     TObject* o = 0;
251     if (parent->IsA()->InheritsFrom(TCollection::Class())) {
252       const TCollection* p = static_cast<const TCollection*>(parent);
253       o = p->FindObject(name);
254     }
255     else if (parent->IsA()->InheritsFrom(TDirectory::Class())) {
256       const TDirectory* d = static_cast<const TDirectory*>(parent);
257       o = const_cast<TDirectory*>(d)->Get(name);
258     }
259     else 
260       Warning("GetObject", "Do not know how to find an object (%s) in "
261               "%s (of class %s)", name.Data(), 
262               parent ? parent->GetName() : "?", 
263               parent ? parent->ClassName() : "?");
264     if (!o) {
265       if (verb) Warning("GetObject", "Object \"%s\" not found in parent \"%s\"",
266                         name.Data(), parent->GetName());
267       return 0;
268     }
269     return o;    
270   }
271   //____________________________________________________________________
272   /** 
273    * Check the type of a found object 
274    * 
275    * @param o   Object 
276    * @param cl  Class 
277    * @param src Source of object
278    * 
279    * @return true on success, false otherwise 
280    */
281   static Bool_t CheckType(const TObject* o, 
282                           const TClass*  cl, 
283                           const TString& src)
284   {
285     if (!o->IsA()->InheritsFrom(cl)) { 
286       Warning("CheckType", "Object \"%s\" retrieved from \"%s\" is not a "
287               "%s but a %s", o->GetName(), src.Data(), cl->GetName(), 
288               o->ClassName());
289       return false;
290     }
291     return true;
292   }
293   //__________________________________________________________________
294   /** 
295    * Check a possibly returned object. 
296    * 
297    * @param o  Object found - if any
298    * @param p  Parent of object
299    * 
300    * @return A pointer to the object cast to the right type
301    */
302   template <typename T>
303   static T* DoGetObject(TObject* o, const TObject* p) 
304   {
305     if (!o) return 0;
306     if (!CheckType(o, T::Class(), p->GetName())) return 0;
307     return static_cast<T*>(o);
308   }
309   //__________________________________________________________________
310   /** 
311    * Check a returned parameter from a parent
312    * 
313    * @param o     Possibly found object
314    * @param p     Parent object
315    * @param value Value 
316    * 
317    * @return true on success, false otherwise 
318    */
319   template <typename T>
320   static Bool_t DoGetParameter(TObject* o, const TObject* p, T& value) 
321   {
322     TParameter<T>* r = DoGetObject<TParameter<T> >(o, p);
323     if (!r) return false;
324     // if (r->TestBit(TParameter<T>::kFirst)) value = r->GetVal();
325     // else                                   value = r->GetUniqueID();
326     value = r->GetVal();
327     if (!r->TestBit(BIT(19))) {
328       TObject* oc = GetObject(p, "count", false);
329       if (oc) {
330         TParameter<int>* pc = static_cast<TParameter<int>*>(oc);
331         int cnt = pc->GetVal();
332         value /= cnt;
333       }
334       else 
335         value = r->GetUniqueID();
336     }
337     // value = r->GetUniqueID();
338     return true;
339   }
340     
341   //___________________________________________________________________
342   /** 
343    * Get a Short_t parameter value 
344    * 
345    * @param c      Parent collection
346    * @param name   Name of parameter
347    * @param value  On return the value
348    * @param verb   If true, complain if not found 
349    */
350   static Bool_t GetParameter(const TObject*  c, 
351                              const TString&  name, 
352                              Short_t&        value,
353                              Bool_t          verb=true)
354   {
355     int v;
356     Bool_t r = DoGetParameter(GetObject(c, name, verb), c, v); 
357     value = v;
358     return r;
359   }
360   //___________________________________________________________________
361   /** 
362    * Get a UShort_t parameter value 
363    * 
364    * @param c      Parent collection
365    * @param name   Name of parameter
366    * @param value  On return the value
367    * @param verb   If true, complain if not found 
368    */
369   static Bool_t GetParameter(const TObject*  c, 
370                              const TString&  name, 
371                              UShort_t&       value,
372                              Bool_t          verb=true)
373   {
374     int v;
375     Bool_t r = DoGetParameter(GetObject(c, name, verb), c, v); 
376     value = v;
377     return r;
378   }
379   //___________________________________________________________________
380   /** 
381    * Get a ULong_t parameter value 
382    * 
383    * @param c      Parent collection
384    * @param name   Name of parameter
385    * @param value  On return the value
386    * @param verb   If true, complain if not found 
387    */
388   static Bool_t GetParameter(const TObject*  c, 
389                              const TString&  name, 
390                              ULong_t&        value,
391                              Bool_t          verb=true)
392   {
393     Long_t v;
394     Bool_t r = DoGetParameter(GetObject(c, name, verb), c, v); 
395     value = v;
396     return r;
397   }
398   //_____________________________________________________________________
399   /** 
400    * Get a Int_t parameter value 
401    * 
402    * @param c      Parent collection
403    * @param name   Name of parameter
404    * @param value  On return the value
405    * @param verb   If true, complain if not found 
406    */
407   static Bool_t GetParameter(const TObject*  c, 
408                              const TString&  name, 
409                              Int_t&          value,
410                              Bool_t          verb=true)
411   {
412     return DoGetParameter(GetObject(c, name, verb), c, value);
413   }
414   //_____________________________________________________________________
415   /** 
416    * Get a Double_t parameter value 
417    * 
418    * @param c      Parent collection
419    * @param name   Name of parameter
420    * @param value  On return the value
421    * @param verb   If true, complain if not found 
422    */
423   static Bool_t GetParameter(const TObject*      c, 
424                              const TString&      name, 
425                              Double_t&           value,
426                              Bool_t              verb=true);
427   //_____________________________________________________________________
428   /** 
429    * Get a Bool_t parameter value 
430    * 
431    * @param c      Parent collection
432    * @param name   Name of parameter
433    * @param value  On return the value
434    * @param verb   If true, complain if not found 
435    */
436   static Bool_t GetParameter(const TObject*  c, 
437                              const TString&      name, 
438                              Bool_t&             value,
439                              Bool_t              verb=true)
440   {
441     return DoGetParameter(GetObject(c, name, verb), c, value);
442   }
443   //____________________________________________________________________
444   /** 
445    * Find a collection in another collection 
446    * 
447    * @param parent Parent collection 
448    * @param name   Name of the collection 
449    * @param verb   If true and not found, complain
450    *
451    * @return pointer to collection on success, otherwise null 
452    */
453   static TCollection* GetCollection(const TObject*     parent, 
454                                     const TString&     name,
455                                     Bool_t             verb=true)
456   {
457     return DoGetObject<TCollection>(GetObject(parent, name, verb), parent);
458   }
459   //____________________________________________________________________
460   /** 
461    * Check a 1D histogram object from a parent
462    * 
463    * @param parent Parent collection 
464    * @param name   Name of histogram
465    * @param verb   Possibly be verbose
466    * 
467    * @return pointer or null
468    */
469   static TH1* GetH1(const TObject*     parent, 
470                     const TString&     name,
471                     Bool_t             verb=true)
472   {
473     return DoGetObject<TH1>(GetObject(parent, name, verb), parent);
474   }
475   //____________________________________________________________________
476   /** 
477    * Get a 2D histogram from a collection
478    * 
479    * @param parent Parent collection 
480    * @param name   Name of histogram 
481    * @param verb   If true and not found, complain
482    * 
483    * @return pointer or null
484    */
485   static TH2* GetH2(const TObject*     parent, 
486                     const TString&     name, 
487                     Bool_t             verb=true)
488   {
489     return DoGetObject<TH2>(GetObject(parent, name, verb), parent);
490   }
491   //____________________________________________________________________
492   /** 
493    * Get a 2D histogram from a collection
494    * 
495    * @param parent Parent collection 
496    * @param name   Name of histogram 
497    * @param verb   If true and not found, complain
498    * 
499    * @return pointer or null
500    */
501   static TH3* GetH3(const TCollection* parent, 
502                     const TString&     name, 
503                     Bool_t             verb=true)
504   {
505     // Info("GetH2", "Getting 2D histogram of %s from %p", name.Data(), c);
506     // --- Find the object -------------------------------------------
507     return DoGetObject<TH3>(GetObject(parent, name, verb), parent);
508   }
509   //__________________________________________________________________
510   /** 
511    * Get a histogram stack from a collection
512    * 
513    * @param parent Parent collection 
514    * @param name   Name of histogram 
515    * @param sub    If set, fill from sub-component 
516    * @param verb   If true and not found, complain
517    * 
518    * @return pointer or null
519    */
520   static THStack* GetStack(const TObject*  parent, 
521                            const TString&  name,
522                            const char*     sub=0,
523                            Bool_t          verb=true)
524   {
525     THStack* stack = DoGetObject<THStack>(GetObject(parent,name,verb),parent);
526     if (!stack) return 0;
527     if (sub == 0) return stack;
528   
529     if (stack->GetHists()->GetEntries() <= 0 ||stack->GetMaximum() < 1) { 
530       // Info("GetStack", "No entries in %s", name.Data());
531       stack->GetHists()->Delete();
532       const char** ptr   = GetRingNames(false);
533       while (*ptr) { 
534         TCollection* sc = GetCollection(parent, *ptr, true);
535         if (!sc) { ptr++; continue; }
536
537         TObject* obj = GetObject(sc, sub);
538         if (!obj) {
539           continue;
540           ptr++;
541         }
542
543         if (obj->IsA()->InheritsFrom(TH2::Class())) {
544           TH2* h = static_cast<TH2*>(obj);
545           TH1* p = h->ProjectionX(*ptr, 1, h->GetNbinsY(), "e");
546           p->Scale(1., "width");
547           p->SetTitle(*ptr);
548           p->SetDirectory(0);
549           stack->Add(p);
550         }
551         else if (obj->IsA()->InheritsFrom(TH1::Class())) {
552           TH1* hh = static_cast<TH1*>(obj);
553           hh->SetTitle(*ptr);
554           stack->Add(hh);
555         }
556         ptr++;
557       }
558     }
559     // --- Return the collection -------------------------------------
560     return stack;
561   }
562   //____________________________________________________________________
563   /** 
564    * Clear canvas 
565    * 
566    */
567   void ClearCanvas()
568   {
569     if (fTop) {
570       fTop->Clear();
571       fTop->SetNumber(1);
572       fTop->SetFillColor(kBlue-5);
573       fTop->SetBorderSize(0);
574       fTop->SetBorderMode(0);
575     }
576
577     fBody->Clear();
578     fBody->SetNumber(2);
579     fBody->SetFillColor(0);
580     fBody->SetFillStyle(0);
581     fBody->SetBorderSize(0);
582     fBody->SetBorderMode(0);
583     fBody->SetTopMargin(0.01);
584     fBody->SetLeftMargin(0.10);
585     fBody->SetRightMargin(0.01);
586     fBody->SetBottomMargin(0.10);
587
588     fRingMap[0] = 0;
589     fRingMap[1] = 0;
590     fRingMap[2] = 0;
591     fRingMap[3] = 0;
592     fRingMap[4] = 0;
593     fRingMap[5] = 0;
594     
595     fCanvas->cd();    
596   }
597   //____________________________________________________________________
598   /** 
599    * Create a canvas 
600    * 
601    * @param pname     Name of PDF file to make 
602    * @param landscape If true, print in landscape 
603    * @param pdf       Make PDF
604    *
605    * @return Created canvas 
606    */
607   void CreateCanvas(const TString& pname, 
608                     Bool_t landscape=false, 
609                     Bool_t pdf=true,
610                     Bool_t useTop=true)
611   {
612     // Info("CreateCanvas", "Creating canvas");
613     fLandscape = landscape;
614     fPDF       = pdf;
615     Int_t height = 1000;
616     Int_t width  = height / TMath::Sqrt(2);
617     if (fLandscape) {
618       Int_t tmp = height; 
619       height    = width;
620       width     = tmp;
621     }
622     fCanvas = new TCanvas("c", pname.Data(), width, height);
623     fCanvas->SetFillColor(0);
624     fCanvas->SetBorderSize(0);
625     fCanvas->SetBorderMode(0);
626     if (fPDF) 
627       fCanvas->Print(Form("%s[", pname.Data()), 
628                      Form("pdf %s", fLandscape ? "Landscape" : ""));
629     fCanvas->SetLeftMargin(.1);
630     fCanvas->SetRightMargin(.05);
631     fCanvas->SetBottomMargin(.1);
632     fCanvas->SetTopMargin(.05);
633   
634     gStyle->SetOptStat(0);
635     gStyle->SetTitleColor(0);
636     gStyle->SetTitleStyle(0);
637     gStyle->SetTitleBorderSize(0);
638     gStyle->SetTitleX(.5);
639     gStyle->SetTitleY(1);
640     gStyle->SetTitleW(.8);
641     gStyle->SetTitleH(.09);
642     gStyle->SetFrameFillColor(kWhite);
643     gStyle->SetFrameBorderSize(1);
644     gStyle->SetFrameBorderMode(1);
645     gStyle->SetPalette(1);
646
647     Float_t dy = useTop ? .05 : 0;
648     if (useTop) {
649       fTop = new TPad("top", "Top", 0, 1-dy, 1, 1, 0, 0);
650       fTop->SetNumber(1);
651       fTop->SetFillColor(kBlue-5);
652       fTop->SetBorderSize(0);
653       fTop->SetBorderMode(0);
654       fCanvas->cd();
655       fTop->Draw();
656     }
657
658     fBody = new TPad("body", "Body", 0, 0, 1, 1-dy, 0, 0);
659     fBody->SetNumber(2);
660     fBody->SetFillColor(0);
661     fBody->SetFillStyle(0);
662     fBody->SetBorderSize(0);
663     fBody->SetBorderMode(0);
664     fCanvas->cd();
665     fBody->Draw();
666
667     fHeader = new TLatex(.5, .5, "Title");
668     fHeader->SetNDC();
669     fHeader->SetTextAlign(22);
670     fHeader->SetTextSize(.7);
671     fHeader->SetTextColor(kWhite);
672     fHeader->SetTextFont(62);
673
674     Double_t x1 = .1;
675     Double_t x2 = .6;
676     Double_t y  = .8;
677     Double_t s  = fLandscape ? 0.08 : 0.05;
678     fParName = new TLatex(x1, y, "");
679     fParName->SetTextAlign(13);
680     fParName->SetNDC();
681     fParName->SetTextSize(s);
682     fParName->SetTextFont(62);
683     
684     fParVal = new TLatex(x2, y, "");
685     fParVal->SetTextAlign(13);
686     fParVal->SetNDC();
687     fParVal->SetTextSize(s);
688     fParVal->SetTextFont(42);
689
690     fCanvas->cd();
691   }
692
693   //____________________________________________________________________
694   /** 
695    * Close the PDF
696    * 
697    */
698   void CloseCanvas()
699   {
700     // Info("CloseCanvas", "Closing canvas");
701     // ClearCanvas();
702     if (fPDF && fCanvas) {
703       // Printf("Closing canvas with last title %s", fLastTitle.Data());
704       fCanvas->Print(Form("%s]", fCanvas->GetTitle()),
705                      Form("pdf %s Title:%s", 
706                           fLandscape ? "Landscape" : "",
707                           fLastTitle.Data()));
708     }
709     if (fCanvas)
710       fCanvas->Close();
711     fCanvas = 0;
712   }
713
714   //__________________________________________________________________
715   /** 
716    * Print the canvas 
717    * 
718    * @param title  Title 
719    * @param size   Size of text 
720    */
721   void PrintCanvas(const TString& title, Float_t size=.7)
722   {
723     if (fTop) {
724       fTop->cd();
725       fHeader->SetTextSize(size);
726       fHeader->DrawLatex(.5,.5,title);
727     }
728   
729     fCanvas->Modified();
730     fCanvas->Update();
731     fCanvas->cd();
732
733     if (fPDF) {
734       TString tit;
735       tit.Form("pdf %s Title:%s", fLandscape ? "Landscape" : "",
736                title.Data());
737
738 #ifdef DEBUG
739       Info("PrintCanvas", "Printing to %s (%s)", 
740            fCanvas->GetTitle(), tit.Data());
741 #else
742       gSystem->RedirectOutput("/dev/null");
743 #endif
744       fCanvas->Print(fCanvas->GetTitle(), tit);
745 #ifndef DEBUG
746       gSystem->RedirectOutput(0);
747 #endif
748       fLastTitle = title;
749       Pause();
750       
751       ClearCanvas();
752     }
753   }
754   //__________________________________________________________________
755   /** 
756    * Make a chapter page 
757    * 
758    * @param title Title 
759    */
760   void MakeChapter(const TString& title)
761   {
762     fBody->cd();
763
764     TLatex* ltx = new TLatex(.5, .5, title);
765     ltx->SetNDC();
766     ltx->SetTextAlign(22);
767     ltx->Draw();
768     
769     PrintCanvas(title);
770   }
771   //__________________________________________________________________
772   /** 
773    * Draw an object in pad 
774    * 
775    * @param c       PArent pad 
776    * @param padNo   Sub-pad number (0 is self)
777    * @param h       Object to draw 
778    * @param opts    Options
779    * @param flags   Flags
780    * @param title   Title on plot
781    *
782    * @return Drawn object - if any
783    */
784   TObject* DrawInPad(TVirtualPad* c, 
785                      Int_t        padNo, 
786                      TObject*     h, 
787                      Option_t*    opts="",
788                      UInt_t       flags=0x0,
789                      const char*  title="")
790   {
791     TVirtualPad* p = c->GetPad(padNo);
792     if (!p) { 
793       Warning("DrawInPad", "Pad # %d not found in %s", padNo, c->GetName());
794       return 0;
795     }
796     return DrawInPad(p, h, opts, flags, title);
797   }
798   /** 
799    * Draw a clone of an object
800    * 
801    * @param o       Object
802    * @param options Draw options
803    * @param title   Title of object
804    *
805    * @return Drawn object - if any
806    */
807   virtual TObject* DrawObjClone(TObject* o, Option_t* options, 
808                                 const char* title)
809   {
810     if (o->IsA()->InheritsFrom(TH1::Class())) 
811       return DrawObjClone(static_cast<TH1*>(o), options, title);
812     else if (o->IsA()->InheritsFrom(THStack::Class())) 
813       return DrawObjClone(static_cast<THStack*>(o), options, title);
814     else if (o->IsA()->InheritsFrom(TGraph::Class()))
815       return o->DrawClone(options);
816     else 
817       o->Draw(options);
818     return o;
819   }
820   /** 
821    * Draw an object clone 
822    * 
823    * @param o        Stack object
824    * @param options  Draw options 
825    * @param title    Title on plot
826    *
827    * @return Drawn object - if any
828    */
829   virtual TObject* DrawObjClone(THStack* o, Option_t* options, 
830                                 const char* title)
831   {
832     // THStack* tmp = static_cast<THStack*>(o->Clone());
833     o->Draw(options);
834     if (title && title[0] != '\0') o->GetHistogram()->SetTitle(title);
835     TAxis*   xAxis = o->GetXaxis();
836     if (!xAxis) {
837       Warning("DrawObjClone", "No X-axis for drawn stack %s", o->GetName());
838       return o;
839     }
840     TH1*     h     = 0;
841     Int_t    nBins = xAxis->GetNbins();
842     Double_t xMin  = xAxis->GetXmin();
843     Double_t xMax  = xAxis->GetXmax();
844     TIter  next(o->GetHists());
845     while ((h = static_cast<TH1*>(next()))) {
846       TAxis* a = h->GetXaxis();
847       nBins    = TMath::Max(nBins, a->GetNbins()); 
848       xMin     = TMath::Min(xMin, a->GetXmin());
849       xMax     = TMath::Max(xMax, a->GetXmax());
850     }
851     if (nBins != xAxis->GetNbins() || 
852         xMin  != xAxis->GetXmin() || 
853         xMax  != xAxis->GetXmax()) {
854       xAxis->Set(nBins, xMin, xMax);
855       o->GetHistogram()->Rebuild();
856     }
857     return o;
858   }
859   /** 
860    * Draw an object clone 
861    * 
862    * @param o        Histogram
863    * @param options  Draw options 
864    * @param title    Title on plot 
865    *
866    * @return Drawn object - if any
867    */
868   virtual TObject* DrawObjClone(TH1* o, Option_t* options, const char* title)
869   {
870     TH1* tmp = o->DrawCopy(options);
871     if (title && title[0] != '\0') tmp->SetTitle(title);
872     return tmp;
873   }    
874   //__________________________________________________________________
875   static void GetLegendPosition(UInt_t    flags, TVirtualPad* p, 
876                                 Double_t& x1,    Double_t&    y1, 
877                                 Double_t& x2,    Double_t&    y2)
878   {
879     UInt_t   horiz = (flags & 0xF0000);
880     UInt_t   verti = (flags & 0xF000);
881     Double_t eps   = .01;
882     Double_t dY    = .4;
883     Double_t dX    = .4;
884     Double_t yB    = p->GetBottomMargin()+eps;
885     Double_t yT    = 1-p->GetTopMargin()-eps;
886     Double_t xL    = p->GetLeftMargin()+eps;
887     Double_t xR    = 1-p->GetRightMargin()-eps;
888     switch (verti) { 
889     case kNorth:  y1 = yT-dY;           break;
890     case kSouth:  y1 = yB;              break;
891     case kMiddle: y1 = (yB+yT-dY)/2;    break;
892     }
893     y2 = TMath::Min(y1 + dY, yT);
894     
895     switch (horiz) { 
896     case kEast:   x1 = xL;              break;
897     case kWest:   x1 = xR-dX;           break;
898     case kCenter: x1 = (xL+xR-dX)/2;    break;
899     }
900     x2 = TMath::Min(x1 + dX, xR);
901   } 
902   TLegend* MakeLegend(TVirtualPad* p, UInt_t flags, Bool_t autoFill)
903   {
904     Double_t x1 = fParVal->GetX();
905     Double_t y1 = fParVal->GetY();
906     Double_t x2 = 0;
907     Double_t y2 = 0;
908     GetLegendPosition(flags, p, x1, y1, x2, y2);
909
910     //Printf("Legend at (%f,%f)x(%f,%f)", x1, y1, x2, y2);
911     TLegend* l = 0;
912     if (autoFill) l = p->BuildLegend(x1, y1, x2, y2);
913     else          l = new TLegend(x1, y1, x2, y2);
914     l->SetFillColor(0);
915     l->SetFillStyle(0);
916     l->SetBorderSize(0);
917
918     return l;
919   }
920   //__________________________________________________________________
921   /** 
922    * Draw an object in pad 
923    * 
924    * @param p       Pad
925    * @param h       Object to draw 
926    * @param opts    Options
927    * @param flags   Flags
928    * @param title   Title on plot
929    *
930    * @return Drawn object - if any
931    */
932   TObject* DrawInPad(TVirtualPad* p, 
933                      TObject*     h, 
934                      Option_t*    opts="",
935                      UInt_t       flags=0x0,
936                      const char*  title="")
937   {
938     if (!p) { 
939       Warning("DrawInPad", "No pad specified");
940       return 0;
941     }
942     p->cd();
943     // Info("DrawInPad", "Drawing in pad %p", p);
944     // fBody->ls();
945     if (flags & kLogx) p->SetLogx();
946     if (flags & kLogy) p->SetLogy();
947     if (flags & kLogz) p->SetLogz();
948     if (flags & kGridx) p->SetGridx();
949     if (flags & kGridy) p->SetGridy();
950     // if (flags & kGridz) p->SetGridz();
951     p->SetFillColor(0);
952     TString o(opts);
953     if (o.Contains("colz", TString::kIgnoreCase)) 
954       p->SetRightMargin(0.15);
955     if (!h) {
956       if (!(flags & kSilent))
957         Warning("DrawInPad", "Nothing to draw in pad # %s", p->GetName());
958       return 0;
959     }
960     if (o.Contains("text", TString::kIgnoreCase)) {
961       TH1* hh = static_cast<TH1*>(h);
962       hh->SetMaximum(1.1*hh->GetMaximum());
963       hh->SetMarkerSize(2);
964       o.Append("30");
965     }
966     TObject* ret = DrawObjClone(h, o, title);
967     
968     if (flags & kLegend) {
969       MakeLegend(p, flags, true);
970     }
971     p->Modified();
972     p->Update();
973     p->cd();
974
975     return ret;
976   }
977   //__________________________________________________________________
978   /** 
979    * Draw two graphs in the same frame, but with separate y-axis 
980    * 
981    * @param c      Mother pad 
982    * @param padNo  Sub-pad number (0 is self)
983    * @param h1     First histogram
984    * @param h2     Second histogram
985    * @param opts   Options
986    * @param flags  Flags
987    */
988   void DrawTwoInPad(TVirtualPad* c, Int_t padNo, TH1* h1, TH1* h2,
989                     Option_t* opts="", UShort_t flags=0x0)
990   {
991     TVirtualPad* p = c->cd(padNo);
992     if (!p) { 
993       Warning("DrawInPad", "Pad # %d not found in %s", padNo, c->GetName());
994       return;
995     }
996     if (flags & kLogx) p->SetLogx();
997     if (flags & kLogy) p->SetLogy();
998     if (flags & kLogz) p->SetLogz();
999     if (flags & kGridx) p->SetGridx();
1000     if (flags & kGridy) p->SetGridy();
1001     // if (flags & kGridz) p->SetGridz();
1002     p->SetFillColor(0);
1003
1004     TString o(opts);
1005     o.ToLower();
1006     TString fopts(o);
1007     Bool_t e3 = o.Contains("e3");
1008     if (e3) {
1009       fopts.ReplaceAll("e3", " same");
1010     }
1011     
1012     h1->GetYaxis()->SetLabelSize(0);
1013     h1->GetYaxis()->SetTicks("");
1014     h1->GetYaxis()->SetNdivisions(0);
1015     h1->DrawCopy(o); // First draw with opts 
1016     if (e3) h1->DrawCopy(fopts);
1017     p->Update();
1018
1019     Double_t m1 = 1.05 * h1->GetMaximum();
1020     if (m1 > 0) {
1021       TGaxis*  a1 = new TGaxis(p->GetUxmin(), p->GetUymin(), 
1022                                p->GetUxmin(), p->GetUymax(), 
1023                                0, m1, 510);
1024       a1->SetLineColor(h1->GetLineColor());
1025       a1->Draw();
1026     }
1027
1028     o.Append(" same");
1029     Double_t m2    = 1.1 * h2->GetMaximum();
1030     Double_t scale = m2 > 0 ? m1 / m2 : 1;
1031     h2->Scale(scale);
1032     h2->DrawCopy(o);
1033     if (e3) h2->DrawCopy(fopts);
1034
1035     if (m2 > 0) {
1036       TGaxis*  a2 = new TGaxis(p->GetUxmax(), p->GetUymin(), 
1037                                p->GetUxmax(), p->GetUymax(), 
1038                                0, m2, 510, "+L");
1039       a2->SetLineColor(h2->GetLineColor());
1040       a2->Draw();
1041     }
1042     if (flags& kLegend) { 
1043       MakeLegend(p, flags, true);
1044     }
1045     p->Modified();
1046     p->Update();
1047     p->cd();
1048   }  
1049   
1050   //____________________________________________________________________
1051   /** 
1052    * Draw a parameter.  
1053    * 
1054    * @param y       Current y position. On return new y position
1055    * @param name    Parameter name
1056    * @param value   Parameter value 
1057    * @param size    Optional text size
1058    */
1059   void DrawParameter(Double_t&      y, 
1060                      const TString& name, 
1061                      const TString& value,
1062                      Double_t       size=0)
1063   {
1064     Double_t s = fParName->GetTextSize();
1065     Double_t t = fParVal->GetTextSize();
1066     if (name.IsNull() && value.IsNull()) return;
1067     if (size > 0) { 
1068       fParName->SetTextSize(size);
1069       fParVal->SetTextSize(size);
1070     }
1071     if (!name.IsNull())
1072       fParName->DrawLatex(fParName->GetX(), y, Form("%s:", name.Data()));
1073     if (!value.IsNull())
1074       fParVal->DrawLatex(fParVal->GetX(), y, value.Data());
1075     if (!name.IsNull())
1076       y -= 1.2 * fParName->GetTextSize();
1077     else if (!value.IsNull())
1078       y -= 1.2 * fParVal->GetTextSize();
1079
1080     fParName->SetTextSize(s);
1081     fParVal->SetTextSize(t);
1082   }  
1083   template <typename T>
1084   void DrawTParameter(Double_t&      y,
1085                       TList*         list, 
1086                       const TString& name) {
1087     T value;
1088     if (!GetParameter(list, name, value)) 
1089       return;
1090     std::stringstream s;
1091     s << std::boolalpha << value;
1092     DrawParameter(y, name, s.str().c_str(), 0);
1093   }
1094       
1095   //__________________________________________________________________
1096   /**
1097    * Structure to hold a dived pad 
1098    */
1099   struct DividedPad { 
1100     TVirtualPad*  fParent;
1101     TVirtualPad** fSubs;
1102     Bool_t        fLandscape;
1103     Int_t         fNCol;
1104     Int_t         fNRow;
1105
1106     DividedPad(TVirtualPad* p, Bool_t landscape, Int_t nCol, Int_t nRow) 
1107       : fParent(p), 
1108         fSubs(0),
1109         fLandscape(landscape),
1110         fNCol(landscape ? nRow : nCol),
1111         fNRow(landscape ? nCol : nRow)
1112     {
1113       Int_t nPad = fNCol * fNRow;
1114       fSubs      = new TVirtualPad*[nPad];
1115     }
1116     void Divide(Bool_t commonX, Bool_t commonY) {
1117       if ((!commonX && !commonY) || (commonX && commonY)) {
1118         // In case we have no common axis or do have both to be common,
1119         // we directly use the TVirtualPad::Divide member function 
1120         fParent->Divide(fNCol, fNRow, commonX ? 0 : 0.01, commonY ? 0 : 0.01);
1121         for (Int_t iPad = 1; iPad <= fNRow*fNCol; iPad++) 
1122           fSubs[iPad-1] = fParent->GetPad(iPad);
1123       }
1124       else if (commonX && !commonY) {
1125         // We need to have common X axis, but not common Y axis. We first
1126         // divide the pad in fNCol columns, and then each in to fNRow rows
1127         fParent->Divide(fNCol, 1);
1128         for (Int_t iCol = 1; iCol <= fNCol; iCol++) { 
1129           TVirtualPad* q = fParent->GetPad(iCol);
1130
1131           if (fNRow == 1) {
1132             fSubs[GetIdx(iCol,0)] = q;
1133             continue;
1134           }
1135
1136           q->Divide(1,fNRow,0,0);
1137           for (Int_t iRow = 1; iRow <= fNRow; iRow++) 
1138             fSubs[GetIdx(iCol, iRow)] = q->GetPad(iRow);
1139         }
1140       }
1141       else if (!commonX && commonY) { 
1142         // We need to have common Y axis, but not common X axis. We first
1143         // divide the pad in fNRow rows, and then each in to fNCol columns
1144         fParent->Divide(1, fNRow);
1145         for (Int_t iRow = 1; iRow <= fNRow; iRow++) { 
1146           TVirtualPad* q = fParent->GetPad(iRow);
1147
1148           if (fNCol == 1) {
1149             fSubs[GetIdx(0,iRow)] = q;
1150             continue;
1151           }
1152           
1153           q->Divide(fNCol,1,0,0);
1154           for (Int_t iCol = 1; iCol <= fNCol; iCol++) 
1155             fSubs[GetIdx(iCol, iRow)] = q->GetPad(iCol);
1156         }
1157       }
1158     }
1159     virtual ~DividedPad() { if (fSubs) delete [] fSubs; }
1160     /** 
1161      * Get a sub-pad 
1162      * 
1163      * @param idx Index (0 based)
1164      * 
1165      * @return Pad or null
1166      */
1167     TVirtualPad* GetPad(Int_t idx) {
1168       if (!fSubs) {
1169         ::Warning("GetPad","No sub-pads");
1170         return 0;
1171       }
1172       if (idx < 0 || idx >= (fNRow*fNCol)) {
1173         ::Warning("GetPad", "Inded %d out of bounds [%d,%d]", 
1174                   idx, 0, fNRow*fNCol);
1175         return 0;
1176       }
1177       return fSubs[idx];
1178     }
1179     Int_t GetIdx(Int_t iCol, Int_t iRow) const 
1180     {
1181       return (iRow-1) * fNCol + iCol;
1182     }
1183     /** 
1184      * Get a sub-pad 
1185      * 
1186      * @param iRow  Row number (1-based)
1187      * @param iCol  Column number (1-based)
1188      * 
1189      * @return Pad or null
1190      */
1191     TVirtualPad* GetPad(Int_t iCol, Int_t iRow) { 
1192       if (iRow < 0 || iRow > fNRow) return 0;
1193       if (iCol < 0 || iRow > fNCol) return 0;
1194       return GetPad(GetIdx(iCol, iRow));
1195     }
1196   };
1197     
1198   //__________________________________________________________________
1199   void DivideForRings(Bool_t commonX, Bool_t commonY)
1200   {
1201     // 
1202     // Divide canvas for rings 
1203     // 
1204     if ((!commonX && !commonY) || 
1205         (commonX  && commonY)) {
1206     // Portrait:
1207     //    +----------+----------+
1208     //    | 1: FMD1i | 2: Free  |
1209     //    +----------+----------+
1210     //    | 3: FMD2i | 4: FMD2o |
1211     //    +----------+----------+
1212     //    | 5: FMD3i | 6: FMD3o |
1213     //    +----------+----------+
1214     // 
1215     // Landscape:
1216     //    +----------+----------+----------+
1217     //    | 1: FMD1i | 2: FMD2i | 3: FMD3i |
1218     //    +----------+----------+----------+
1219     //    | 4: Free  | 5: FMD2o | 6: FMD3o |
1220     //    +----------+----------+----------+
1221     // 
1222       fBody->Divide(fLandscape ? 3 : 2, fLandscape ? 2 : 3,
1223                     commonX ? 0 : 0.01, commonY ? 0 : 0.01);
1224       fRingMap[0] = fBody->GetPad(1);                  // FMD1i;
1225       fRingMap[1] = fBody->GetPad(fLandscape ? 2 : 3); // FMD2i;
1226       fRingMap[2] = fBody->GetPad(fLandscape ? 5 : 4); // FMD2o;
1227       fRingMap[3] = fBody->GetPad(fLandscape ? 3 : 5); // FMD3i;
1228       fRingMap[4] = fBody->GetPad(6);                  // FMD3o;
1229       fRingMap[5] = fBody->GetPad(fLandscape ? 4 : 2); // Free
1230     }
1231     else if (commonX && !commonY) {
1232       // Divide into two  - left/right
1233       // Portrait:
1234       //    +----------++----------+
1235       //    | 1: FMD1i || 1: Free  |
1236       //    +----------++----------+
1237       //    | 2: FMD2i || 2: FMD2o |
1238       //    +----------++----------+
1239       //    | 3: FMD3i || 3: FMD3o |
1240       //    +----------++----------+
1241       // 
1242       // Landscape:
1243       //    +----------++----------++----------+
1244       //    | 1: FMD1i || 1: FMD2i || 1: FMD3i |
1245       //    +----------++----------++----------+
1246       //    | 2: Free  || 2: FMD2o || 2: FMD3o |
1247       //    +----------++----------++----------+
1248       // 
1249       fBody->Divide(fLandscape ? 3 : 2, 1);
1250       TVirtualPad* left = fBody->cd(1);
1251       left->Divide(fLandscape ? 2 : 3);
1252       TVirtualPad* middle = fBody->cd(2);
1253       middle->Divide(fLandscape ? 2 : 3);
1254
1255       Info("left","%p",left); left->ls();
1256       Info("middle","%p",middle); middle->ls();
1257
1258       fRingMap[0] = left->GetPad(1); // FMD1i;
1259       if (!fLandscape) {
1260         fRingMap[1] = left->GetPad(2);   // FMD2i
1261         fRingMap[2] = middle->GetPad(2); // FMD2o
1262         fRingMap[3] = left->GetPad(3);   // FMD3i
1263         fRingMap[4] = middle->GetPad(3); // FMD3o
1264         fRingMap[5] = middle->GetPad(1); // Free
1265       }
1266       else {
1267         TVirtualPad* right = fBody->cd(3);
1268         right->Divide(fLandscape ? 2 : 3);
1269         fRingMap[1] = middle->GetPad(1); // FMD2i
1270         fRingMap[2] = middle->GetPad(2); // FMD2o
1271         fRingMap[3] = right->GetPad(1);  // FMD3i
1272         fRingMap[4] = right->GetPad(2);  // FMD3o
1273         fRingMap[5] = left->GetPad(2);   // Free
1274       }
1275     }
1276     else { 
1277       // Divide into two  - left/right
1278       // Portrait:
1279       //    +----------+----------+
1280       //    | 1: FMD1i | 2: Free  |
1281       //    +----------+----------+
1282       //    +----------+----------+
1283       //    | 1: FMD2i | 2: FMD2o |
1284       //    +----------+----------+
1285       //    +----------+----------+
1286       //    | 1: FMD3i | 2: FMD3o |
1287       //    +----------+----------+
1288       // 
1289       // Landscape:
1290       //    +----------+----------+----------+
1291       //    | 1: FMD1i | 2: FMD2i | 3: FMD3i |
1292       //    +----------+----------+----------+
1293       //    +----------+----------+----------+
1294       //    | 1: Free  | 2: FMD2o | 3: FMD3o |
1295       //    +----------+----------+----------+
1296       // 
1297       fBody->Divide(1, fLandscape ? 2 : 3);
1298       TVirtualPad* top = fBody->cd(1);
1299       top->Divide(fLandscape ? 3 : 2);
1300       TVirtualPad* middle = fBody->cd(2);
1301       middle->Divide(fLandscape ? 3 : 2);
1302
1303       fRingMap[0] = top->GetPad(1); // FMD1i;
1304       if (!fLandscape) {
1305         TVirtualPad* bottom = fBody->cd(2);
1306         bottom->Divide(2);
1307
1308         fRingMap[1] = middle->GetPad(1); // FMD2i
1309         fRingMap[2] = middle->GetPad(2); // FMD2o
1310         fRingMap[3] = bottom->GetPad(1); // FMD3i
1311         fRingMap[4] = bottom->GetPad(2); // FMD3o
1312         fRingMap[5] = top->GetPad(2);    // Free
1313       }
1314       else {
1315         fRingMap[1] = top->GetPad(2);    // FMD2i
1316         fRingMap[2] = middle->GetPad(2); // FMD2o
1317         fRingMap[3] = top->GetPad(3);    // FMD3i
1318         fRingMap[4] = middle->GetPad(3); // FMD3o
1319         fRingMap[5] = middle->GetPad(1); // Free
1320       }
1321     }
1322     if (fRingMap[0]) fRingMap[0]->SetTitle("FMD1i");
1323     if (fRingMap[1]) fRingMap[1]->SetTitle("FMD2i");
1324     if (fRingMap[2]) fRingMap[2]->SetTitle("FMD2o");
1325     if (fRingMap[3]) fRingMap[3]->SetTitle("FMD3i");
1326     if (fRingMap[4]) fRingMap[4]->SetTitle("FMD3o");
1327     if (fRingMap[5]) fRingMap[5]->SetTitle("Other");
1328   }
1329   //__________________________________________________________________
1330   TVirtualPad* RingPad(UShort_t d, Char_t r) const
1331   {
1332     Int_t idx = 0;
1333     switch (d) { 
1334     case 0:     idx = 5; break;
1335     case 1:     idx = 0; break;
1336     case 2:     idx = 1 + ((r == 'I' || r == 'i') ? 0 : 1); break;
1337     case 3:     idx = 3 + ((r == 'I' || r == 'i') ? 0 : 1); break;
1338     default: return 0;
1339     }
1340     return fRingMap[idx];
1341     // return fBody->GetPad(no);
1342   }
1343   //__________________________________________________________________
1344   TVirtualPad* RingPad(const char* name) const
1345   {
1346     TString n(name);
1347     Int_t idx = n.Index("FMD");
1348     if (n == kNPOS) return 0;
1349     n.Remove(0, idx+3);
1350     Int_t det = n.Atoi();
1351     n.Remove(0,1);
1352     Char_t rng = n[0];
1353     return RingPad(det, rng);
1354   }
1355   //__________________________________________________________________
1356   /** 
1357    * Draw an object in pad 
1358    * 
1359    * @param d       Detector 
1360    * @param r       Ring 
1361    * @param h       Object to draw 
1362    * @param opts    Options
1363    * @param flags   Flags
1364    * @param title   Title on plot
1365    */
1366   void DrawInRingPad(UShort_t    d, 
1367                      Char_t      r, 
1368                      TObject*    h, 
1369                      Option_t*   opts="",
1370                      UShort_t    flags=0x0,
1371                      const char* title="")
1372   {
1373     TVirtualPad* p = RingPad(d, r);
1374     if (!p) {
1375       Warning("DrawInRingPad", "No pad found for FMD%d%c", d, r);
1376       return;
1377     }
1378     DrawInPad(p, h, opts, flags, title);
1379   }
1380   /** 
1381    * Draw object in a ring pad
1382    * 
1383    * @param name    Name of ring
1384    * @param h       Object to draw
1385    * @param opts    Options
1386    * @param flags   Flags
1387    * @param title   Possible new title
1388    */
1389   void DrawInRingPad(const char* name, 
1390                      TObject*    h, 
1391                      Option_t*   opts="", 
1392                      UShort_t    flags=0x0, 
1393                      const char* title="")
1394   {
1395     TVirtualPad* p = RingPad(name);
1396     if (!p) {
1397       Warning("DrawInRingPad", "No pad found for \"%s\"", name);
1398       return;
1399     }
1400     DrawInPad(p, h, opts, flags, title);
1401   }
1402   /** 
1403    * Draw object in a ring pad. Which pad to draw in depends on the
1404    * name or title of the drawn object (must contain the ring name as
1405    * a sub-string).
1406    * 
1407    * @param h       Object to draw
1408    * @param opts    Options
1409    * @param flags   Flags
1410    * @param title   Possible new title
1411    */
1412   void DrawInRingPad(TObject*    h, 
1413                      Option_t*   opts="", 
1414                      UShort_t    flags=0x0, 
1415                      const char* title="")
1416   {
1417     if (!h) return;
1418     TVirtualPad* p = RingPad(h->GetName());
1419     if (!p) {
1420       p = RingPad(h->GetTitle());
1421       if (!p) {
1422         Warning("DrawInRingPad", "No pad found for %s/%s", 
1423                 h->GetName(), h->GetTitle());
1424         return;
1425       }
1426     }
1427     DrawInPad(p, h, opts, flags, title);
1428   }
1429     
1430
1431   //__________________________________________________________________
1432   /** 
1433    * Pause after each plot
1434    * 
1435    */
1436   void Pause()
1437   {
1438     if (!fPause) return;
1439     printf("Press enter to continue");
1440     std::cin.get();
1441   }
1442   static void CompileScript(const TString& name, 
1443                             const TString& sub, 
1444                             const TString& check,
1445                             Bool_t         force)
1446   {
1447     if (!check.IsNull() && gROOT->GetClass(check)) return;
1448
1449     TString fwd =gSystem->ExpandPathName("$ALICE_ROOT/PWGLF/FORWARD/analysis2");
1450     TString macPath(gROOT->GetMacroPath());
1451     TString incPath(gSystem->GetIncludePath());
1452     if (!macPath.Contains(fwd)) macPath.Append(Form(":%s", fwd.Data()));
1453     if (!incPath.Contains(fwd)) gSystem->AddIncludePath(Form("-I%s",
1454                                                              fwd.Data()));
1455     if (!sub.IsNull()) { 
1456       TObjArray* subs = sub.Tokenize(": ");
1457       TObject*   pSub = 0;
1458       TIter      iSub(subs);
1459       while ((pSub = iSub())) {
1460         TString subDir = gSystem->ConcatFileName(fwd, pSub->GetName());
1461         if (!macPath.Contains(subDir))
1462           macPath.Append(Form(":%s", subDir.Data()));
1463         if (!incPath.Contains(subDir)) 
1464           gSystem->AddIncludePath(Form("-I%s", subDir.Data()));
1465       }
1466     }
1467     gROOT->SetMacroPath(macPath);
1468     gROOT->LoadMacro(Form("%s%s", name.Data(), (force ? "++g" : "+")));
1469   }
1470   //____________________________________________________________________
1471   virtual void DrawEventInspector(TCollection* parent)
1472   {
1473     Info("DrawEventInspector", "Drawing event inspector");
1474     TCollection* c = GetCollection(parent, "fmdEventInspector");
1475     if (!c) return;
1476
1477     UShort_t sys=0, sNN=0;
1478     Int_t field=0;
1479     ULong_t runNo=0;
1480     Int_t lowFlux=0, nPileUp=0, ipMethod=0;
1481     ULong_t aliRev=0, aliBra=0;    
1482     Bool_t v0and=false;
1483     Double_t dPileUp=0.;
1484     Double_t y = .8;
1485
1486     fBody->cd();
1487
1488     Double_t save = fParName->GetTextSize();
1489     fParName->SetTextSize(0.03);
1490     fParVal->SetTextSize(0.03);
1491     
1492     GetParameter(c, "sys", sys);
1493     GetParameter(c, "sNN", sNN);
1494     GetParameter(c, "field", field);
1495     GetParameter(c, "runNo", runNo);
1496     GetParameter(c, "lowFlux", lowFlux);
1497     GetParameter(c, "ipMethod", ipMethod, false);
1498     GetParameter(c, "v0and", v0and);
1499     GetParameter(c, "nPileUp", nPileUp);
1500     GetParameter(c, "dPileup", dPileUp);
1501     GetParameter(c, "alirootRev", aliRev);
1502     GetParameter(c, "alirootBranch", aliBra);
1503     
1504     TString tS; SysString(sys, tS); DrawParameter(y, "System", tS);
1505     TString tE; SNNString(sNN, tE); DrawParameter(y, "#sqrt{s_{NN}}", tE);
1506     DrawParameter(y, "L3 B field", Form("%+2dkG", field));
1507     DrawParameter(y, "Run #", Form("%lu", runNo));
1508     DrawParameter(y, "Low flux cut", Form("%d", lowFlux));
1509     TString sIpMeth("unknown");
1510     switch(ipMethod) { 
1511     case 0: sIpMeth = "Normal"; break;
1512     case 1: sIpMeth = "pA in 2012"; break;
1513     case 2: sIpMeth = "pA in 2013"; break;
1514     case 3: sIpMeth = "PWG-UD"; break;
1515     case 4: sIpMeth = "Satellite"; break;
1516     }
1517     DrawParameter(y, "Use PWG-UD vertex", sIpMeth);
1518     DrawParameter(y, "Use V0AND for NSD", (v0and ? "yes" : "no"));
1519     DrawParameter(y, "Least # of pile-up vertex", Form("%d", nPileUp));
1520     DrawParameter(y, "Least distance of pile-up vertex",
1521                   Form("%fcm", dPileUp));
1522     DrawParameter(y, "AliROOT", Form("%lu/0x%08lx", ULong_t(aliRev), 
1523                                      ULong_t(aliBra)));
1524
1525     TH1*    triggers     = GetH1(c, "triggers");
1526     TH1*    vertex       = GetH1(c, "vertex", false);
1527     Bool_t  mc           = (vertex != 0);
1528     if (mc) { 
1529       Int_t nInelMC = vertex->GetEntries();
1530       Int_t nInel   = triggers->GetBinContent(1);
1531       Int_t nNSDMC  = triggers->GetBinContent(11);
1532       Int_t nNSD    = triggers->GetBinContent(4);
1533       DrawParameter(y, 
1534                     Form("#varepsilon_{INEL} = #bf{%d/%d}", nInel, nInelMC),
1535                     Form("%5.3f", float(nInel)/nInelMC));
1536       DrawParameter(y, 
1537                     Form("#varepsilon_{NSD} = #bf{%d/%d}", nNSD, nNSDMC),
1538                     Form("%5.3f", float(nNSD)/nNSDMC));
1539     }
1540
1541     PrintCanvas("Event Inspector");
1542     fParName->SetTextSize(save);
1543     fParVal->SetTextSize(save);
1544
1545     if (fLandscape) fBody->Divide(4,2);
1546     else            fBody->Divide(2,4);
1547     
1548     TH1*    nEventsTr    = GetH1(c, "nEventsTr");
1549     TH1*    nEventsTrVtx = GetH1(c, "nEventsTrVtx");
1550     TH1*    nEventsAcc   = GetH1(c, "nEventsAccepted");
1551     if (nEventsTr)    nEventsTr->Rebin(2);
1552     if (nEventsTrVtx) nEventsTrVtx->Rebin(2);
1553     if (vertex) {
1554       // vertex->Rebin(2);
1555       vertex->SetFillColor(kMagenta+2);
1556     }
1557     DrawInPad(fBody, 1, nEventsTr, "", kLogy, 
1558               "Events w/trigger, trigger+vertex, accepted");
1559     if (vertex) DrawInPad(fBody, 1, vertex, "same");
1560     DrawInPad(fBody, 1, nEventsTrVtx, "same"); 
1561     DrawInPad(fBody, 1, nEventsAcc, "same", kLegend);
1562
1563
1564     DrawInPad(fBody, 2, GetH2(c, "nEventsAcceptedXY"), "colz", kLogz);
1565     DrawInPad(fBody, 3, triggers,          "hist text");
1566     if (GetH1(c, "trgStatus"))
1567       DrawInPad(fBody, 4, GetH1(c, "trgStatus"),       "hist text");
1568     else  // Old one 
1569       DrawInPad(fBody, 4, GetH2(c, "triggerCorr"),     "colz", kLogz);
1570     DrawInPad(fBody, 5, GetH1(c, "status"),            "hist text");
1571     if (GetH1(c, "vtxStatus"))
1572       DrawInPad(fBody, 6, GetH1(c, "vtxStatus"),       "hist text");
1573     else // old 
1574       DrawInPad(fBody, 6, GetH1(c, "type"),            "hist text");
1575
1576     TH1* cent     = GetH1(c, "cent");
1577     if (cent) { 
1578       cent->Scale(1, "width");
1579       DrawInPad(fBody, 7, cent, "", kLogy);
1580     }
1581
1582     TH1* pileupStatus = GetH1(c, "pileupStatus", false);
1583     if (pileupStatus) DrawInPad(fBody, 8, pileupStatus, "hist text30");
1584     else {
1585       TH2* centQual = GetH2(c, "centVsQuality");
1586       if (centQual) { 
1587         centQual->Scale(1, "width");
1588         DrawInPad(fBody, 8, centQual, "colz", kLogz);
1589       }
1590     }
1591     
1592     PrintCanvas("EventInspector - Histograms");  
1593
1594     if (!mc) return; // not MC 
1595   
1596     TH1* phiR         = GetH1(c, "phiR");
1597     TH1* b            = GetH1(c, "b");
1598     TH2* bVsNpart     = GetH2(c, "bVsParticipants");
1599     TH2* bVsNbin      = GetH2(c, "bVsBinary");
1600     TH2* bVsCent      = GetH2(c, "bVsCentrality");
1601     TH2* vzComparison = GetH2(c, "vzComparison");
1602     TH2* centVsNpart  = GetH2(c, "centralityVsParticipans");// Spelling!
1603     TH2* centVsNbin   = GetH2(c, "centralityVsBinary");
1604   
1605     fBody->Divide(2,3);
1606
1607     DrawInPad(fBody, 1, phiR);
1608     DrawInPad(fBody, 2, vzComparison, "colz", kLogz);
1609     DrawInPad(fBody, 3, b);
1610
1611     TProfile* nPartB = bVsNpart->ProfileX("nPartB",1,-1,"s");
1612     TProfile* nBinB  = bVsNbin->ProfileX("nBinB",1,-1,"s");
1613     nPartB->SetMarkerColor(kBlue+2);
1614     nPartB->SetMarkerStyle(20);
1615     nPartB->SetLineColor(kBlue+2);
1616     nPartB->SetFillColor(kBlue-10);
1617     nPartB->SetFillStyle(1001);
1618     nPartB->SetMarkerSize(0.7);
1619     nBinB->SetMarkerColor(kRed+2);
1620     nBinB->SetMarkerStyle(21);
1621     nBinB->SetLineColor(kRed+2);
1622     nBinB->SetFillColor(kRed-10);
1623     nBinB->SetMarkerSize(0.7);
1624     nBinB->SetFillStyle(1001);
1625
1626     DrawTwoInPad(fBody, 4, nPartB, nBinB, "e3 p", kLegend);
1627
1628     DrawInPad(fBody, 5, bVsCent, "colz", kLogz);
1629
1630     TProfile* nPartC = centVsNpart->ProfileY("nPartC",1,-1,"s");
1631     TProfile* nBinC  = centVsNbin->ProfileY("nBinC",1,-1,"s");
1632     nPartC->SetMarkerColor(kBlue+2);
1633     nPartC->SetMarkerStyle(20);
1634     nPartC->SetLineColor(kBlue+2);
1635     nPartC->SetFillColor(kBlue-10);
1636     nPartC->SetFillStyle(1001);
1637     nPartC->SetMarkerSize(0.7);
1638     nBinC->SetMarkerColor(kRed+2);
1639     nBinC->SetMarkerStyle(21);
1640     nBinC->SetLineColor(kRed+2);
1641     nBinC->SetFillColor(kRed-10);
1642     nBinC->SetMarkerSize(0.7);
1643     nBinC->SetFillStyle(1001);
1644
1645     DrawTwoInPad(fBody, 6, nPartC, nBinC, "e3 p", kLegend);
1646
1647     PrintCanvas("EventInspector - Monte-Carlo");  
1648   }
1649   //____________________________________________________________________
1650   virtual void DrawESDFixer(TCollection* parent)
1651   {
1652     Info("DrawESDFixer", "Drawing ESD fixer");
1653     TCollection* c = GetCollection(parent, "fmdESDFixer");
1654     if (!c) return;
1655
1656     Int_t  recoFactor = 0;
1657     Bool_t recalcEta = false;
1658     Bool_t invalidIsEmpty = false;
1659
1660     fBody->cd();
1661
1662     Double_t save = fParName->GetTextSize();
1663     fParName->SetTextSize(0.05);
1664     fParVal->SetTextSize(0.05);
1665
1666     fBody->Divide(2,2);
1667     fBody->cd(1);
1668     
1669     Double_t y = .8;
1670     if (GetParameter(c, "recoFactor", recoFactor))
1671         DrawParameter(y, "Noise factor used in reco",
1672                       Form("%d (assumed)", recoFactor));
1673     if (GetParameter(c, "recalcEta", recalcEta))
1674         DrawParameter(y, "Recalculate #eta",
1675                       Form("%s", (recalcEta ? "yes" : "no")));
1676     if (GetParameter(c, "invalidIsEmpty", invalidIsEmpty))
1677         DrawParameter(y, "Assume invalid strips are empty",
1678                       Form("%s", (invalidIsEmpty ? "yes" : "no")));
1679
1680     TCollection* xd = GetCollection(c, "extraDead");
1681     if (xd) 
1682       DrawParameter(y, "# extra dead strips", 
1683                     Form("%d", xd->GetEntries()));
1684     
1685     DrawInPad(fBody, 2, GetH1(c, "noiseChange"), "", kLogy);
1686     DrawInPad(fBody, 3, GetH1(c, "etaChange"), "", kLogy);
1687     DrawInPad(fBody, 4, GetH1(c, "deadChange"), "", kLogy);
1688         
1689     PrintCanvas("ESD Fixer");
1690     fParName->SetTextSize(save);
1691     fParVal->SetTextSize(save);
1692   }
1693   //____________________________________________________________________
1694   void DrawTrackDensity(TCollection* parent, 
1695                         const char* folderName="mcTrackDensity")
1696   {
1697     Info("DrawTrackDensity", "Drawing track density");
1698
1699     // --- MC --------------------------------------------------------
1700     TCollection* mc = GetCollection(parent, folderName, false);
1701     if (!mc) return; // Not MC 
1702
1703     fBody->Divide(2,3);
1704     DrawInPad(fBody, 1, GetH2(mc, "binFlow"),    "colz", kLogz);
1705     DrawInPad(fBody, 2, GetH2(mc, "binFlowEta"), "colz", kLogz);
1706     DrawInPad(fBody, 3, GetH2(mc, "binFlowPhi"), "colz", kLogz);
1707     DrawInPad(fBody, 4, GetH1(mc, "nRefs"),       "",    kLogy,
1708               "# of references");
1709     DrawInPad(fBody, 4, GetH1(mc, "clusterRefs",   false), "same");
1710     DrawInPad(fBody, 4, GetH1(mc, "clusterSize",   false), "same");
1711     DrawInPad(fBody, 4, GetH1(mc, "nClusters",     false), "same", kLegend);
1712     DrawInPad(fBody, 5, GetH2(mc, "clusterVsRefs", false),"colz", kLogz);
1713
1714     PrintCanvas("Track density");  
1715   }
1716   //__________________________________________________________________
1717   TCanvas* fCanvas;  // Our canvas 
1718   TPad*    fTop;     // Top part 
1719   TPad*    fBody;    // Body part 
1720   TLatex*  fHeader;  // Header text 
1721   TLatex*  fParName; // Parameter name 
1722   TLatex*  fParVal;  // Parameter value 
1723   Bool_t   fPause;   // Whether to pause after drawing a canvas
1724   Bool_t   fLandscape; // Landscape or Portrait orientation
1725   TVirtualPad** fRingMap;
1726   Bool_t   fPDF;
1727   TString  fLastTitle;
1728 };
1729 #if 0
1730 template <> 
1731 inline Bool_t 
1732 SummaryDrawer::DoGetParameter<Double_t>(TObject* o, const TObject* p, 
1733                                         Double_t& value)
1734 {
1735   TParameter<Double_t>* r = DoGetObject<TParameter<Double_t>(o, p);
1736   UInt_t  i = o->GetUniqueID();
1737   Float_t v = *reinterpret_cast<Float_t*>(&i);
1738   value = v;
1739   return true;
1740 }
1741 #endif
1742 inline Bool_t 
1743 SummaryDrawer::GetParameter(const TObject*   c, 
1744                             const TString&   name, 
1745                             Double_t&        value,
1746                             Bool_t           verb)
1747   
1748 {
1749   return DoGetParameter(GetObject(c, name, verb), c, value);
1750 }
1751
1752 #endif
1753 //
1754 // EOF
1755 //
1756