]> git.uio.no Git - u/mrichter/AliRoot.git/blob - PWGLF/FORWARD/analysis2/scripts/SummaryDrawer.C
Added script to copy secondary correction
[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     fTop->Clear();
570     fTop->SetNumber(1);
571     fTop->SetFillColor(kBlue-5);
572     fTop->SetBorderSize(0);
573     fTop->SetBorderMode(0);
574
575     fBody->Clear();
576     fBody->SetNumber(2);
577     fBody->SetFillColor(0);
578     fBody->SetFillStyle(0);
579     fBody->SetBorderSize(0);
580     fBody->SetBorderMode(0);
581     fBody->SetTopMargin(0.01);
582     fBody->SetLeftMargin(0.10);
583     fBody->SetRightMargin(0.01);
584     fBody->SetBottomMargin(0.10);
585
586     fRingMap[0] = 0;
587     fRingMap[1] = 0;
588     fRingMap[2] = 0;
589     fRingMap[3] = 0;
590     fRingMap[4] = 0;
591     fRingMap[5] = 0;
592     
593     fCanvas->cd();    
594   }
595   //____________________________________________________________________
596   /** 
597    * Create a canvas 
598    * 
599    * @param pname     Name of PDF file to make 
600    * @param landscape If true, print in landscape 
601    * @param pdf       Make PDF
602    *
603    * @return Created canvas 
604    */
605   void CreateCanvas(const TString& pname, 
606                     Bool_t landscape=false, 
607                     Bool_t pdf=true)
608   {
609     // Info("CreateCanvas", "Creating canvas");
610     fLandscape = landscape;
611     fPDF       = pdf;
612     Int_t height = 1000;
613     Int_t width  = height / TMath::Sqrt(2);
614     if (fLandscape) {
615       Int_t tmp = height; 
616       height    = width;
617       width     = tmp;
618     }
619     fCanvas = new TCanvas("c", pname.Data(), width, height);
620     fCanvas->SetFillColor(0);
621     fCanvas->SetBorderSize(0);
622     fCanvas->SetBorderMode(0);
623     if (fPDF) 
624       fCanvas->Print(Form("%s[", pname.Data()), 
625                      Form("pdf %s", fLandscape ? "Landscape" : ""));
626     fCanvas->SetLeftMargin(.1);
627     fCanvas->SetRightMargin(.05);
628     fCanvas->SetBottomMargin(.1);
629     fCanvas->SetTopMargin(.05);
630   
631     gStyle->SetOptStat(0);
632     gStyle->SetTitleColor(0);
633     gStyle->SetTitleStyle(0);
634     gStyle->SetTitleBorderSize(0);
635     gStyle->SetTitleX(.5);
636     gStyle->SetTitleY(1);
637     gStyle->SetTitleW(.8);
638     gStyle->SetTitleH(.09);
639     gStyle->SetFrameFillColor(kWhite);
640     gStyle->SetFrameBorderSize(1);
641     gStyle->SetFrameBorderMode(1);
642     gStyle->SetPalette(1);
643
644     Float_t dy = .05;
645     fTop = new TPad("top", "Top", 0, 1-dy, 1, 1, 0, 0);
646     fTop->SetNumber(1);
647     fTop->SetFillColor(kBlue-5);
648     fTop->SetBorderSize(0);
649     fTop->SetBorderMode(0);
650     fCanvas->cd();
651     fTop->Draw();
652     
653     fBody = new TPad("body", "Body", 0, 0, 1, 1-dy, 0, 0);
654     fBody->SetNumber(2);
655     fBody->SetFillColor(0);
656     fBody->SetFillStyle(0);
657     fBody->SetBorderSize(0);
658     fBody->SetBorderMode(0);
659     fCanvas->cd();
660     fBody->Draw();
661
662     fHeader = new TLatex(.5, .5, "Title");
663     fHeader->SetNDC();
664     fHeader->SetTextAlign(22);
665     fHeader->SetTextSize(.7);
666     fHeader->SetTextColor(kWhite);
667     fHeader->SetTextFont(62);
668
669     Double_t x1 = .1;
670     Double_t x2 = .6;
671     Double_t y  = .8;
672     Double_t s  = fLandscape ? 0.08 : 0.05;
673     fParName = new TLatex(x1, y, "");
674     fParName->SetTextAlign(13);
675     fParName->SetNDC();
676     fParName->SetTextSize(s);
677     fParName->SetTextFont(62);
678     
679     fParVal = new TLatex(x2, y, "");
680     fParVal->SetTextAlign(13);
681     fParVal->SetNDC();
682     fParVal->SetTextSize(s);
683     fParVal->SetTextFont(42);
684
685     fCanvas->cd();
686   }
687
688   //____________________________________________________________________
689   /** 
690    * Close the PDF
691    * 
692    */
693   void CloseCanvas()
694   {
695     // Info("CloseCanvas", "Closing canvas");
696     // ClearCanvas();
697     if (fPDF && fCanvas) {
698       // Printf("Closing canvas with last title %s", fLastTitle.Data());
699       fCanvas->Print(Form("%s]", fCanvas->GetTitle()),
700                      Form("pdf %s Title:%s", 
701                           fLandscape ? "Landscape" : "",
702                           fLastTitle.Data()));
703     }
704     if (fCanvas)
705       fCanvas->Close();
706     fCanvas = 0;
707   }
708
709   //__________________________________________________________________
710   /** 
711    * Print the canvas 
712    * 
713    * @param title  Title 
714    * @param size   Size of text 
715    */
716   void PrintCanvas(const TString& title, Float_t size=.7)
717   {
718     fTop->cd();
719     fHeader->SetTextSize(size);
720     fHeader->DrawLatex(.5,.5,title);
721   
722     fCanvas->Modified();
723     fCanvas->Update();
724     fCanvas->cd();
725
726     if (fPDF) {
727       TString tit;
728       tit.Form("pdf %s Title:%s", fLandscape ? "Landscape" : "",
729                title.Data());
730
731 #ifdef DEBUG
732       Info("PrintCanvas", "Printing to %s (%s)", 
733            fCanvas->GetTitle(), tit.Data());
734 #else
735       gSystem->RedirectOutput("/dev/null");
736 #endif
737       fCanvas->Print(fCanvas->GetTitle(), tit);
738 #ifndef DEBUG
739       gSystem->RedirectOutput(0);
740 #endif
741       fLastTitle = title;
742       Pause();
743       
744       ClearCanvas();
745     }
746   }
747   //__________________________________________________________________
748   /** 
749    * Make a chapter page 
750    * 
751    * @param title Title 
752    */
753   void MakeChapter(const TString& title)
754   {
755     fBody->cd();
756
757     TLatex* ltx = new TLatex(.5, .5, title);
758     ltx->SetNDC();
759     ltx->SetTextAlign(22);
760     ltx->Draw();
761     
762     PrintCanvas(title);
763   }
764   //__________________________________________________________________
765   /** 
766    * Draw an object in pad 
767    * 
768    * @param c       PArent pad 
769    * @param padNo   Sub-pad number (0 is self)
770    * @param h       Object to draw 
771    * @param opts    Options
772    * @param flags   Flags
773    * @param title   Title on plot
774    *
775    * @return Drawn object - if any
776    */
777   TObject* DrawInPad(TVirtualPad* c, 
778                      Int_t        padNo, 
779                      TObject*     h, 
780                      Option_t*    opts="",
781                      UInt_t       flags=0x0,
782                      const char*  title="")
783   {
784     TVirtualPad* p = c->GetPad(padNo);
785     if (!p) { 
786       Warning("DrawInPad", "Pad # %d not found in %s", padNo, c->GetName());
787       return 0;
788     }
789     return DrawInPad(p, h, opts, flags, title);
790   }
791   /** 
792    * Draw a clone of an object
793    * 
794    * @param o       Object
795    * @param options Draw options
796    * @param title   Title of object
797    *
798    * @return Drawn object - if any
799    */
800   virtual TObject* DrawObjClone(TObject* o, Option_t* options, 
801                                 const char* title)
802   {
803     if (o->IsA()->InheritsFrom(TH1::Class())) 
804       return DrawObjClone(static_cast<TH1*>(o), options, title);
805     else if (o->IsA()->InheritsFrom(THStack::Class())) 
806       return DrawObjClone(static_cast<THStack*>(o), options, title);
807     else if (o->IsA()->InheritsFrom(TGraph::Class()))
808       return o->DrawClone(options);
809     else 
810       o->Draw(options);
811     return o;
812   }
813   /** 
814    * Draw an object clone 
815    * 
816    * @param o        Stack object
817    * @param options  Draw options 
818    * @param title    Title on plot
819    *
820    * @return Drawn object - if any
821    */
822   virtual TObject* DrawObjClone(THStack* o, Option_t* options, 
823                                 const char* title)
824   {
825     // THStack* tmp = static_cast<THStack*>(o->Clone());
826     o->Draw(options);
827     if (title && title[0] != '\0') o->GetHistogram()->SetTitle(title);
828     TAxis*   xAxis = o->GetXaxis();
829     if (!xAxis) {
830       Warning("DrawObjClone", "No X-axis for drawn stack %s", o->GetName());
831       return o;
832     }
833     TH1*     h     = 0;
834     Int_t    nBins = xAxis->GetNbins();
835     Double_t xMin  = xAxis->GetXmin();
836     Double_t xMax  = xAxis->GetXmax();
837     TIter  next(o->GetHists());
838     while ((h = static_cast<TH1*>(next()))) {
839       TAxis* a = h->GetXaxis();
840       nBins    = TMath::Max(nBins, a->GetNbins()); 
841       xMin     = TMath::Min(xMin, a->GetXmin());
842       xMax     = TMath::Max(xMax, a->GetXmax());
843     }
844     if (nBins != xAxis->GetNbins() || 
845         xMin  != xAxis->GetXmin() || 
846         xMax  != xAxis->GetXmax()) {
847       xAxis->Set(nBins, xMin, xMax);
848       o->GetHistogram()->Rebuild();
849     }
850     return o;
851   }
852   /** 
853    * Draw an object clone 
854    * 
855    * @param o        Histogram
856    * @param options  Draw options 
857    * @param title    Title on plot 
858    *
859    * @return Drawn object - if any
860    */
861   virtual TObject* DrawObjClone(TH1* o, Option_t* options, const char* title)
862   {
863     TH1* tmp = o->DrawCopy(options);
864     if (title && title[0] != '\0') tmp->SetTitle(title);
865     return tmp;
866   }    
867   //__________________________________________________________________
868   static void GetLegendPosition(UInt_t    flags, TVirtualPad* p, 
869                                 Double_t& x1,    Double_t&    y1, 
870                                 Double_t& x2,    Double_t&    y2)
871   {
872     UInt_t   horiz = (flags & 0xF0000);
873     UInt_t   verti = (flags & 0xF000);
874     Double_t eps   = .01;
875     Double_t dY    = .4;
876     Double_t dX    = .4;
877     Double_t yB    = p->GetBottomMargin()+eps;
878     Double_t yT    = 1-p->GetTopMargin()-eps;
879     Double_t xL    = p->GetLeftMargin()+eps;
880     Double_t xR    = 1-p->GetRightMargin()-eps;
881     switch (verti) { 
882     case kNorth:  y1 = yT-dY;           break;
883     case kSouth:  y1 = yB;              break;
884     case kMiddle: y1 = (yB+yT-dY)/2;    break;
885     }
886     y2 = TMath::Min(y1 + dY, yT);
887     
888     switch (horiz) { 
889     case kEast:   x1 = xL;              break;
890     case kWest:   x1 = xR-dX;           break;
891     case kCenter: x1 = (xL+xR-dX)/2;    break;
892     }
893     x2 = TMath::Min(x1 + dX, xR);
894   } 
895   TLegend* MakeLegend(TVirtualPad* p, UInt_t flags, Bool_t autoFill)
896   {
897     Double_t x1 = fParVal->GetX();
898     Double_t y1 = fParVal->GetY();
899     Double_t x2 = 0;
900     Double_t y2 = 0;
901     GetLegendPosition(flags, p, x1, y1, x2, y2);
902
903     //Printf("Legend at (%f,%f)x(%f,%f)", x1, y1, x2, y2);
904     TLegend* l = 0;
905     if (autoFill) l = p->BuildLegend(x1, y1, x2, y2);
906     else          l = new TLegend(x1, y1, x2, y2);
907     l->SetFillColor(0);
908     l->SetFillStyle(0);
909     l->SetBorderSize(0);
910
911     return l;
912   }
913   //__________________________________________________________________
914   /** 
915    * Draw an object in pad 
916    * 
917    * @param p       Pad
918    * @param h       Object to draw 
919    * @param opts    Options
920    * @param flags   Flags
921    * @param title   Title on plot
922    *
923    * @return Drawn object - if any
924    */
925   TObject* DrawInPad(TVirtualPad* p, 
926                      TObject*     h, 
927                      Option_t*    opts="",
928                      UInt_t       flags=0x0,
929                      const char*  title="")
930   {
931     if (!p) { 
932       Warning("DrawInPad", "No pad specified");
933       return 0;
934     }
935     p->cd();
936     // Info("DrawInPad", "Drawing in pad %p", p);
937     // fBody->ls();
938     if (flags & kLogx) p->SetLogx();
939     if (flags & kLogy) p->SetLogy();
940     if (flags & kLogz) p->SetLogz();
941     if (flags & kGridx) p->SetGridx();
942     if (flags & kGridy) p->SetGridy();
943     // if (flags & kGridz) p->SetGridz();
944     p->SetFillColor(0);
945     TString o(opts);
946     if (o.Contains("colz", TString::kIgnoreCase)) 
947       p->SetRightMargin(0.15);
948     if (!h) {
949       if (!(flags & kSilent))
950         Warning("DrawInPad", "Nothing to draw in pad # %s", p->GetName());
951       return 0;
952     }
953     if (o.Contains("text", TString::kIgnoreCase)) {
954       TH1* hh = static_cast<TH1*>(h);
955       hh->SetMaximum(1.1*hh->GetMaximum());
956       hh->SetMarkerSize(2);
957       o.Append("30");
958     }
959     TObject* ret = DrawObjClone(h, o, title);
960     
961     if (flags & kLegend) {
962       MakeLegend(p, flags, true);
963     }
964     p->Modified();
965     p->Update();
966     p->cd();
967
968     return ret;
969   }
970   //__________________________________________________________________
971   /** 
972    * Draw two graphs in the same frame, but with separate y-axis 
973    * 
974    * @param c      Mother pad 
975    * @param padNo  Sub-pad number (0 is self)
976    * @param h1     First histogram
977    * @param h2     Second histogram
978    * @param opts   Options
979    * @param flags  Flags
980    */
981   void DrawTwoInPad(TVirtualPad* c, Int_t padNo, TH1* h1, TH1* h2,
982                     Option_t* opts="", UShort_t flags=0x0)
983   {
984     TVirtualPad* p = c->cd(padNo);
985     if (!p) { 
986       Warning("DrawInPad", "Pad # %d not found in %s", padNo, c->GetName());
987       return;
988     }
989     if (flags & kLogx) p->SetLogx();
990     if (flags & kLogy) p->SetLogy();
991     if (flags & kLogz) p->SetLogz();
992     if (flags & kGridx) p->SetGridx();
993     if (flags & kGridy) p->SetGridy();
994     // if (flags & kGridz) p->SetGridz();
995     p->SetFillColor(0);
996
997     TString o(opts);
998     o.ToLower();
999     TString fopts(o);
1000     Bool_t e3 = o.Contains("e3");
1001     if (e3) {
1002       fopts.ReplaceAll("e3", " same");
1003     }
1004     
1005     h1->GetYaxis()->SetLabelSize(0);
1006     h1->GetYaxis()->SetTicks("");
1007     h1->GetYaxis()->SetNdivisions(0);
1008     h1->DrawCopy(o); // First draw with opts 
1009     if (e3) h1->DrawCopy(fopts);
1010     p->Update();
1011
1012     Double_t m1 = 1.05 * h1->GetMaximum();
1013     if (m1 > 0) {
1014       TGaxis*  a1 = new TGaxis(p->GetUxmin(), p->GetUymin(), 
1015                                p->GetUxmin(), p->GetUymax(), 
1016                                0, m1, 510);
1017       a1->SetLineColor(h1->GetLineColor());
1018       a1->Draw();
1019     }
1020
1021     o.Append(" same");
1022     Double_t m2    = 1.1 * h2->GetMaximum();
1023     Double_t scale = m2 > 0 ? m1 / m2 : 1;
1024     h2->Scale(scale);
1025     h2->DrawCopy(o);
1026     if (e3) h2->DrawCopy(fopts);
1027
1028     if (m2 > 0) {
1029       TGaxis*  a2 = new TGaxis(p->GetUxmax(), p->GetUymin(), 
1030                                p->GetUxmax(), p->GetUymax(), 
1031                                0, m2, 510, "+L");
1032       a2->SetLineColor(h2->GetLineColor());
1033       a2->Draw();
1034     }
1035     if (flags& kLegend) { 
1036       MakeLegend(p, flags, true);
1037     }
1038     p->Modified();
1039     p->Update();
1040     p->cd();
1041   }  
1042   
1043   //____________________________________________________________________
1044   /** 
1045    * Draw a parameter.  
1046    * 
1047    * @param y       Current y position. On return new y position
1048    * @param name    Parameter name
1049    * @param value   Parameter value 
1050    * @param size    Optional text size
1051    */
1052   void DrawParameter(Double_t&      y, 
1053                      const TString& name, 
1054                      const TString& value,
1055                      Double_t       size=0)
1056   {
1057     Double_t s = fParName->GetTextSize();
1058     Double_t t = fParVal->GetTextSize();
1059     if (name.IsNull() && value.IsNull()) return;
1060     if (size > 0) { 
1061       fParName->SetTextSize(size);
1062       fParVal->SetTextSize(size);
1063     }
1064     if (!name.IsNull())
1065       fParName->DrawLatex(fParName->GetX(), y, Form("%s:", name.Data()));
1066     if (!value.IsNull())
1067       fParVal->DrawLatex(fParVal->GetX(), y, value.Data());
1068     if (!name.IsNull())
1069       y -= 1.2 * fParName->GetTextSize();
1070     else if (!value.IsNull())
1071       y -= 1.2 * fParVal->GetTextSize();
1072
1073     fParName->SetTextSize(s);
1074     fParVal->SetTextSize(t);
1075   }  
1076   template <typename T>
1077   void DrawTParameter(Double_t&      y,
1078                       TList*         list, 
1079                       const TString& name) {
1080     T value;
1081     if (!GetParameter(list, name, value)) 
1082       return;
1083     std::stringstream s;
1084     s << std::boolalpha << value;
1085     DrawParameter(y, name, s.str().c_str(), 0);
1086   }
1087       
1088   //__________________________________________________________________
1089   /**
1090    * Structure to hold a dived pad 
1091    */
1092   struct DividedPad { 
1093     TVirtualPad*  fParent;
1094     TVirtualPad** fSubs;
1095     Bool_t        fLandscape;
1096     Int_t         fNCol;
1097     Int_t         fNRow;
1098
1099     DividedPad(TVirtualPad* p, Bool_t landscape, Int_t nCol, Int_t nRow) 
1100       : fParent(p), 
1101         fSubs(0),
1102         fLandscape(landscape),
1103         fNCol(landscape ? nRow : nCol),
1104         fNRow(landscape ? nCol : nRow)
1105     {
1106       Int_t nPad = fNCol * fNRow;
1107       fSubs      = new TVirtualPad*[nPad];
1108     }
1109     void Divide(Bool_t commonX, Bool_t commonY) {
1110       if ((!commonX && !commonY) || (commonX && commonY)) {
1111         // In case we have no common axis or do have both to be common,
1112         // we directly use the TVirtualPad::Divide member function 
1113         fParent->Divide(fNCol, fNRow, commonX ? 0 : 0.01, commonY ? 0 : 0.01);
1114         for (Int_t iPad = 1; iPad <= fNRow*fNCol; iPad++) 
1115           fSubs[iPad-1] = fParent->GetPad(iPad);
1116       }
1117       else if (commonX && !commonY) {
1118         // We need to have common X axis, but not common Y axis. We first
1119         // divide the pad in fNCol columns, and then each in to fNRow rows
1120         fParent->Divide(fNCol, 1);
1121         for (Int_t iCol = 1; iCol <= fNCol; iCol++) { 
1122           TVirtualPad* q = fParent->GetPad(iCol);
1123
1124           if (fNRow == 1) {
1125             fSubs[GetIdx(iCol,0)] = q;
1126             continue;
1127           }
1128
1129           q->Divide(1,fNRow,0,0);
1130           for (Int_t iRow = 1; iRow <= fNRow; iRow++) 
1131             fSubs[GetIdx(iCol, iRow)] = q->GetPad(iRow);
1132         }
1133       }
1134       else if (!commonX && commonY) { 
1135         // We need to have common Y axis, but not common X axis. We first
1136         // divide the pad in fNRow rows, and then each in to fNCol columns
1137         fParent->Divide(1, fNRow);
1138         for (Int_t iRow = 1; iRow <= fNRow; iRow++) { 
1139           TVirtualPad* q = fParent->GetPad(iRow);
1140
1141           if (fNCol == 1) {
1142             fSubs[GetIdx(0,iRow)] = q;
1143             continue;
1144           }
1145           
1146           q->Divide(fNCol,1,0,0);
1147           for (Int_t iCol = 1; iCol <= fNCol; iCol++) 
1148             fSubs[GetIdx(iCol, iRow)] = q->GetPad(iCol);
1149         }
1150       }
1151     }
1152     virtual ~DividedPad() { if (fSubs) delete [] fSubs; }
1153     /** 
1154      * Get a sub-pad 
1155      * 
1156      * @param idx Index (0 based)
1157      * 
1158      * @return Pad or null
1159      */
1160     TVirtualPad* GetPad(Int_t idx) {
1161       if (!fSubs) {
1162         ::Warning("GetPad","No sub-pads");
1163         return 0;
1164       }
1165       if (idx < 0 || idx >= (fNRow*fNCol)) {
1166         ::Warning("GetPad", "Inded %d out of bounds [%d,%d]", 
1167                   idx, 0, fNRow*fNCol);
1168         return 0;
1169       }
1170       return fSubs[idx];
1171     }
1172     Int_t GetIdx(Int_t iCol, Int_t iRow) const 
1173     {
1174       return (iRow-1) * fNCol + iCol;
1175     }
1176     /** 
1177      * Get a sub-pad 
1178      * 
1179      * @param iRow  Row number (1-based)
1180      * @param iCol  Column number (1-based)
1181      * 
1182      * @return Pad or null
1183      */
1184     TVirtualPad* GetPad(Int_t iCol, Int_t iRow) { 
1185       if (iRow < 0 || iRow > fNRow) return 0;
1186       if (iCol < 0 || iRow > fNCol) return 0;
1187       return GetPad(GetIdx(iCol, iRow));
1188     }
1189   };
1190     
1191   //__________________________________________________________________
1192   void DivideForRings(Bool_t commonX, Bool_t commonY)
1193   {
1194     // 
1195     // Divide canvas for rings 
1196     // 
1197     if ((!commonX && !commonY) || 
1198         (commonX  && commonY)) {
1199     // Portrait:
1200     //    +----------+----------+
1201     //    | 1: FMD1i | 2: Free  |
1202     //    +----------+----------+
1203     //    | 3: FMD2i | 4: FMD2o |
1204     //    +----------+----------+
1205     //    | 5: FMD3i | 6: FMD3o |
1206     //    +----------+----------+
1207     // 
1208     // Landscape:
1209     //    +----------+----------+----------+
1210     //    | 1: FMD1i | 2: FMD2i | 3: FMD3i |
1211     //    +----------+----------+----------+
1212     //    | 4: Free  | 5: FMD2o | 6: FMD3o |
1213     //    +----------+----------+----------+
1214     // 
1215       fBody->Divide(fLandscape ? 3 : 2, fLandscape ? 2 : 3,
1216                     commonX ? 0 : 0.01, commonY ? 0 : 0.01);
1217       fRingMap[0] = fBody->GetPad(1);                  // FMD1i;
1218       fRingMap[1] = fBody->GetPad(fLandscape ? 2 : 3); // FMD2i;
1219       fRingMap[2] = fBody->GetPad(fLandscape ? 5 : 4); // FMD2o;
1220       fRingMap[3] = fBody->GetPad(fLandscape ? 3 : 5); // FMD3i;
1221       fRingMap[4] = fBody->GetPad(6);                  // FMD3o;
1222       fRingMap[5] = fBody->GetPad(fLandscape ? 4 : 2); // Free
1223     }
1224     else if (commonX && !commonY) {
1225       // Divide into two  - left/right
1226       // Portrait:
1227       //    +----------++----------+
1228       //    | 1: FMD1i || 1: Free  |
1229       //    +----------++----------+
1230       //    | 2: FMD2i || 2: FMD2o |
1231       //    +----------++----------+
1232       //    | 3: FMD3i || 3: FMD3o |
1233       //    +----------++----------+
1234       // 
1235       // Landscape:
1236       //    +----------++----------++----------+
1237       //    | 1: FMD1i || 1: FMD2i || 1: FMD3i |
1238       //    +----------++----------++----------+
1239       //    | 2: Free  || 2: FMD2o || 2: FMD3o |
1240       //    +----------++----------++----------+
1241       // 
1242       fBody->Divide(fLandscape ? 3 : 2, 1);
1243       TVirtualPad* left = fBody->cd(1);
1244       left->Divide(fLandscape ? 2 : 3);
1245       TVirtualPad* middle = fBody->cd(2);
1246       middle->Divide(fLandscape ? 2 : 3);
1247
1248       Info("left","%p",left); left->ls();
1249       Info("middle","%p",middle); middle->ls();
1250
1251       fRingMap[0] = left->GetPad(1); // FMD1i;
1252       if (!fLandscape) {
1253         fRingMap[1] = left->GetPad(2);   // FMD2i
1254         fRingMap[2] = middle->GetPad(2); // FMD2o
1255         fRingMap[3] = left->GetPad(3);   // FMD3i
1256         fRingMap[4] = middle->GetPad(3); // FMD3o
1257         fRingMap[5] = middle->GetPad(1); // Free
1258       }
1259       else {
1260         TVirtualPad* right = fBody->cd(3);
1261         right->Divide(fLandscape ? 2 : 3);
1262         fRingMap[1] = middle->GetPad(1); // FMD2i
1263         fRingMap[2] = middle->GetPad(2); // FMD2o
1264         fRingMap[3] = right->GetPad(1);  // FMD3i
1265         fRingMap[4] = right->GetPad(2);  // FMD3o
1266         fRingMap[5] = left->GetPad(2);   // Free
1267       }
1268     }
1269     else { 
1270       // Divide into two  - left/right
1271       // Portrait:
1272       //    +----------+----------+
1273       //    | 1: FMD1i | 2: Free  |
1274       //    +----------+----------+
1275       //    +----------+----------+
1276       //    | 1: FMD2i | 2: FMD2o |
1277       //    +----------+----------+
1278       //    +----------+----------+
1279       //    | 1: FMD3i | 2: FMD3o |
1280       //    +----------+----------+
1281       // 
1282       // Landscape:
1283       //    +----------+----------+----------+
1284       //    | 1: FMD1i | 2: FMD2i | 3: FMD3i |
1285       //    +----------+----------+----------+
1286       //    +----------+----------+----------+
1287       //    | 1: Free  | 2: FMD2o | 3: FMD3o |
1288       //    +----------+----------+----------+
1289       // 
1290       fBody->Divide(1, fLandscape ? 2 : 3);
1291       TVirtualPad* top = fBody->cd(1);
1292       top->Divide(fLandscape ? 3 : 2);
1293       TVirtualPad* middle = fBody->cd(2);
1294       middle->Divide(fLandscape ? 3 : 2);
1295
1296       fRingMap[0] = top->GetPad(1); // FMD1i;
1297       if (!fLandscape) {
1298         TVirtualPad* bottom = fBody->cd(2);
1299         bottom->Divide(2);
1300
1301         fRingMap[1] = middle->GetPad(1); // FMD2i
1302         fRingMap[2] = middle->GetPad(2); // FMD2o
1303         fRingMap[3] = bottom->GetPad(1); // FMD3i
1304         fRingMap[4] = bottom->GetPad(2); // FMD3o
1305         fRingMap[5] = top->GetPad(2);    // Free
1306       }
1307       else {
1308         fRingMap[1] = top->GetPad(2);    // FMD2i
1309         fRingMap[2] = middle->GetPad(2); // FMD2o
1310         fRingMap[3] = top->GetPad(3);    // FMD3i
1311         fRingMap[4] = middle->GetPad(3); // FMD3o
1312         fRingMap[5] = middle->GetPad(1); // Free
1313       }
1314     }
1315     if (fRingMap[0]) fRingMap[0]->SetTitle("FMD1i");
1316     if (fRingMap[1]) fRingMap[1]->SetTitle("FMD2i");
1317     if (fRingMap[2]) fRingMap[2]->SetTitle("FMD2o");
1318     if (fRingMap[3]) fRingMap[3]->SetTitle("FMD3i");
1319     if (fRingMap[4]) fRingMap[4]->SetTitle("FMD3o");
1320     if (fRingMap[5]) fRingMap[5]->SetTitle("Other");
1321   }
1322   //__________________________________________________________________
1323   TVirtualPad* RingPad(UShort_t d, Char_t r) const
1324   {
1325     Int_t idx = 0;
1326     switch (d) { 
1327     case 0:     idx = 5; break;
1328     case 1:     idx = 0; break;
1329     case 2:     idx = 1 + ((r == 'I' || r == 'i') ? 0 : 1); break;
1330     case 3:     idx = 3 + ((r == 'I' || r == 'i') ? 0 : 1); break;
1331     default: return 0;
1332     }
1333     return fRingMap[idx];
1334     // return fBody->GetPad(no);
1335   }
1336   //__________________________________________________________________
1337   TVirtualPad* RingPad(const char* name) const
1338   {
1339     TString n(name);
1340     Int_t idx = n.Index("FMD");
1341     if (n == kNPOS) return 0;
1342     n.Remove(0, idx+3);
1343     Int_t det = n.Atoi();
1344     n.Remove(0,1);
1345     Char_t rng = n[0];
1346     return RingPad(det, rng);
1347   }
1348   //__________________________________________________________________
1349   /** 
1350    * Draw an object in pad 
1351    * 
1352    * @param d       Detector 
1353    * @param r       Ring 
1354    * @param h       Object to draw 
1355    * @param opts    Options
1356    * @param flags   Flags
1357    * @param title   Title on plot
1358    */
1359   void DrawInRingPad(UShort_t    d, 
1360                      Char_t      r, 
1361                      TObject*    h, 
1362                      Option_t*   opts="",
1363                      UShort_t    flags=0x0,
1364                      const char* title="")
1365   {
1366     TVirtualPad* p = RingPad(d, r);
1367     if (!p) {
1368       Warning("DrawInRingPad", "No pad found for FMD%d%c", d, r);
1369       return;
1370     }
1371     DrawInPad(p, h, opts, flags, title);
1372   }
1373   /** 
1374    * Draw object in a ring pad
1375    * 
1376    * @param name    Name of ring
1377    * @param h       Object to draw
1378    * @param opts    Options
1379    * @param flags   Flags
1380    * @param title   Possible new title
1381    */
1382   void DrawInRingPad(const char* name, 
1383                      TObject*    h, 
1384                      Option_t*   opts="", 
1385                      UShort_t    flags=0x0, 
1386                      const char* title="")
1387   {
1388     TVirtualPad* p = RingPad(name);
1389     if (!p) {
1390       Warning("DrawInRingPad", "No pad found for \"%s\"", name);
1391       return;
1392     }
1393     DrawInPad(p, h, opts, flags, title);
1394   }
1395   /** 
1396    * Draw object in a ring pad. Which pad to draw in depends on the
1397    * name or title of the drawn object (must contain the ring name as
1398    * a sub-string).
1399    * 
1400    * @param h       Object to draw
1401    * @param opts    Options
1402    * @param flags   Flags
1403    * @param title   Possible new title
1404    */
1405   void DrawInRingPad(TObject*    h, 
1406                      Option_t*   opts="", 
1407                      UShort_t    flags=0x0, 
1408                      const char* title="")
1409   {
1410     if (!h) return;
1411     TVirtualPad* p = RingPad(h->GetName());
1412     if (!p) {
1413       p = RingPad(h->GetTitle());
1414       if (!p) {
1415         Warning("DrawInRingPad", "No pad found for %s/%s", 
1416                 h->GetName(), h->GetTitle());
1417         return;
1418       }
1419     }
1420     DrawInPad(p, h, opts, flags, title);
1421   }
1422     
1423
1424   //__________________________________________________________________
1425   /** 
1426    * Pause after each plot
1427    * 
1428    */
1429   void Pause()
1430   {
1431     if (!fPause) return;
1432     printf("Press enter to continue");
1433     std::cin.get();
1434   }
1435   static void CompileScript(const TString& name, 
1436                             const TString& sub, 
1437                             const TString& check,
1438                             Bool_t         force)
1439   {
1440     if (!check.IsNull() && gROOT->GetClass(check)) return;
1441
1442     TString fwd =gSystem->ExpandPathName("$ALICE_ROOT/PWGLF/FORWARD/analysis2");
1443     TString macPath(gROOT->GetMacroPath());
1444     TString incPath(gSystem->GetIncludePath());
1445     if (!macPath.Contains(fwd)) macPath.Append(Form(":%s", fwd.Data()));
1446     if (!incPath.Contains(fwd)) gSystem->AddIncludePath(Form("-I%s",
1447                                                              fwd.Data()));
1448     if (!sub.IsNull()) { 
1449       TObjArray* subs = sub.Tokenize(": ");
1450       TObject*   pSub = 0;
1451       TIter      iSub(subs);
1452       while ((pSub = iSub())) {
1453         TString subDir = gSystem->ConcatFileName(fwd, pSub->GetName());
1454         if (!macPath.Contains(subDir))
1455           macPath.Append(Form(":%s", subDir.Data()));
1456         if (!incPath.Contains(subDir)) 
1457           gSystem->AddIncludePath(Form("-I%s", subDir.Data()));
1458       }
1459     }
1460     gROOT->SetMacroPath(macPath);
1461     gROOT->LoadMacro(Form("%s%s", name.Data(), (force ? "++g" : "+")));
1462   }
1463   //____________________________________________________________________
1464   virtual void DrawEventInspector(TCollection* parent)
1465   {
1466     Info("DrawEventInspector", "Drawing event inspector");
1467     TCollection* c = GetCollection(parent, "fmdEventInspector");
1468     if (!c) return;
1469
1470     UShort_t sys=0, sNN=0;
1471     Int_t field=0;
1472     ULong_t runNo=0;
1473     Int_t lowFlux=0, nPileUp=0, ipMethod=0;
1474     ULong_t aliRev=0, aliBra=0;    
1475     Bool_t v0and=false;
1476     Double_t dPileUp=0.;
1477     Double_t y = .8;
1478
1479     fBody->cd();
1480
1481     Double_t save = fParName->GetTextSize();
1482     fParName->SetTextSize(0.03);
1483     fParVal->SetTextSize(0.03);
1484     
1485     GetParameter(c, "sys", sys);
1486     GetParameter(c, "sNN", sNN);
1487     GetParameter(c, "field", field);
1488     GetParameter(c, "runNo", runNo);
1489     GetParameter(c, "lowFlux", lowFlux);
1490     GetParameter(c, "ipMethod", ipMethod);
1491     GetParameter(c, "v0and", v0and);
1492     GetParameter(c, "nPileUp", nPileUp);
1493     GetParameter(c, "dPileup", dPileUp);
1494     GetParameter(c, "alirootRev", aliRev);
1495     GetParameter(c, "alirootBranch", aliBra);
1496     
1497     TString tS; SysString(sys, tS); DrawParameter(y, "System", tS);
1498     TString tE; SNNString(sNN, tE); DrawParameter(y, "#sqrt{s_{NN}}", tE);
1499     DrawParameter(y, "L3 B field", Form("%+2dkG", field));
1500     DrawParameter(y, "Run #", Form("%lu", runNo));
1501     DrawParameter(y, "Low flux cut", Form("%d", lowFlux));
1502     TString sIpMeth("unknown");
1503     switch(ipMethod) { 
1504     case 0: sIpMeth = "Normal"; break;
1505     case 1: sIpMeth = "pA in 2012"; break;
1506     case 2: sIpMeth = "pA in 2013"; break;
1507     case 3: sIpMeth = "PWG-UD"; break;
1508     case 4: sIpMeth = "Satellite"; break;
1509     }
1510     DrawParameter(y, "Use PWG-UD vertex", sIpMeth);
1511     DrawParameter(y, "Use V0AND for NSD", (v0and ? "yes" : "no"));
1512     DrawParameter(y, "Least # of pile-up vertex", Form("%d", nPileUp));
1513     DrawParameter(y, "Least distance of pile-up vertex",
1514                   Form("%fcm", dPileUp));
1515     DrawParameter(y, "AliROOT", Form("%lu/0x%08lx", ULong_t(aliRev), 
1516                                      ULong_t(aliBra)));
1517
1518     TH1*    triggers     = GetH1(c, "triggers");
1519     TH1*    vertex       = GetH1(c, "vertex", false);
1520     Bool_t  mc           = (vertex != 0);
1521     if (mc) { 
1522       Int_t nInelMC = vertex->GetEntries();
1523       Int_t nInel   = triggers->GetBinContent(1);
1524       Int_t nNSDMC  = triggers->GetBinContent(11);
1525       Int_t nNSD    = triggers->GetBinContent(4);
1526       DrawParameter(y, 
1527                     Form("#varepsilon_{INEL} = #bf{%d/%d}", nInel, nInelMC),
1528                     Form("%5.3f", float(nInel)/nInelMC));
1529       DrawParameter(y, 
1530                     Form("#varepsilon_{NSD} = #bf{%d/%d}", nNSD, nNSDMC),
1531                     Form("%5.3f", float(nNSD)/nNSDMC));
1532     }
1533
1534     PrintCanvas("Event Inspector");
1535     fParName->SetTextSize(save);
1536     fParVal->SetTextSize(save);
1537
1538     if (fLandscape) fBody->Divide(4,2);
1539     else            fBody->Divide(2,4);
1540     
1541     TH1*    nEventsTr    = GetH1(c, "nEventsTr");
1542     TH1*    nEventsTrVtx = GetH1(c, "nEventsTrVtx");
1543     TH1*    nEventsAcc   = GetH1(c, "nEventsAccepted");
1544     if (nEventsTr)    nEventsTr->Rebin(2);
1545     if (nEventsTrVtx) nEventsTrVtx->Rebin(2);
1546     if (vertex) {
1547       // vertex->Rebin(2);
1548       vertex->SetFillColor(kMagenta+2);
1549     }
1550     DrawInPad(fBody, 1, nEventsTr, "", kLogy, 
1551               "Events w/trigger, trigger+vertex, accepted");
1552     if (vertex) DrawInPad(fBody, 1, vertex, "same");
1553     DrawInPad(fBody, 1, nEventsTrVtx, "same"); 
1554     DrawInPad(fBody, 1, nEventsAcc, "same", kLegend);
1555
1556
1557     DrawInPad(fBody, 2, GetH2(c, "nEventsAcceptedXY"), "colz", kLogz);
1558     DrawInPad(fBody, 3, triggers,          "hist text");
1559     if (GetH1(c, "trgStatus"))
1560       DrawInPad(fBody, 4, GetH1(c, "trgStatus"),       "hist text");
1561     else  // Old one 
1562       DrawInPad(fBody, 4, GetH2(c, "triggerCorr"),     "colz", kLogz);
1563     DrawInPad(fBody, 5, GetH1(c, "status"),            "hist text");
1564     if (GetH1(c, "vtxStatus"))
1565       DrawInPad(fBody, 6, GetH1(c, "vtxStatus"),       "hist text");
1566     else // old 
1567       DrawInPad(fBody, 6, GetH1(c, "type"),            "hist text");
1568
1569     TH1* cent     = GetH1(c, "cent");
1570     TH2* centQual = GetH2(c, "centVsQuality");
1571     if (cent && centQual) { 
1572       cent->Scale(1, "width");
1573       centQual->Scale(1, "width");
1574       DrawInPad(fBody, 7, cent, "", kLogy);
1575       DrawInPad(fBody, 8, centQual, "colz", kLogz);
1576     }
1577     
1578     PrintCanvas("EventInspector - Histograms");  
1579
1580     if (!mc) return; // not MC 
1581   
1582     TH1* phiR         = GetH1(c, "phiR");
1583     TH1* b            = GetH1(c, "b");
1584     TH2* bVsNpart     = GetH2(c, "bVsParticipants");
1585     TH2* bVsNbin      = GetH2(c, "bVsBinary");
1586     TH2* bVsCent      = GetH2(c, "bVsCentrality");
1587     TH2* vzComparison = GetH2(c, "vzComparison");
1588     TH2* centVsNpart  = GetH2(c, "centralityVsParticipans");// Spelling!
1589     TH2* centVsNbin   = GetH2(c, "centralityVsBinary");
1590   
1591     fBody->Divide(2,3);
1592
1593     DrawInPad(fBody, 1, phiR);
1594     DrawInPad(fBody, 2, vzComparison, "colz", kLogz);
1595     DrawInPad(fBody, 3, b);
1596
1597     TProfile* nPartB = bVsNpart->ProfileX("nPartB",1,-1,"s");
1598     TProfile* nBinB  = bVsNbin->ProfileX("nBinB",1,-1,"s");
1599     nPartB->SetMarkerColor(kBlue+2);
1600     nPartB->SetMarkerStyle(20);
1601     nPartB->SetLineColor(kBlue+2);
1602     nPartB->SetFillColor(kBlue-10);
1603     nPartB->SetFillStyle(1001);
1604     nPartB->SetMarkerSize(0.7);
1605     nBinB->SetMarkerColor(kRed+2);
1606     nBinB->SetMarkerStyle(21);
1607     nBinB->SetLineColor(kRed+2);
1608     nBinB->SetFillColor(kRed-10);
1609     nBinB->SetMarkerSize(0.7);
1610     nBinB->SetFillStyle(1001);
1611
1612     DrawTwoInPad(fBody, 4, nPartB, nBinB, "e3 p", kLegend);
1613
1614     DrawInPad(fBody, 5, bVsCent, "colz", kLogz);
1615
1616     TProfile* nPartC = centVsNpart->ProfileY("nPartC",1,-1,"s");
1617     TProfile* nBinC  = centVsNbin->ProfileY("nBinC",1,-1,"s");
1618     nPartC->SetMarkerColor(kBlue+2);
1619     nPartC->SetMarkerStyle(20);
1620     nPartC->SetLineColor(kBlue+2);
1621     nPartC->SetFillColor(kBlue-10);
1622     nPartC->SetFillStyle(1001);
1623     nPartC->SetMarkerSize(0.7);
1624     nBinC->SetMarkerColor(kRed+2);
1625     nBinC->SetMarkerStyle(21);
1626     nBinC->SetLineColor(kRed+2);
1627     nBinC->SetFillColor(kRed-10);
1628     nBinC->SetMarkerSize(0.7);
1629     nBinC->SetFillStyle(1001);
1630
1631     DrawTwoInPad(fBody, 6, nPartC, nBinC, "e3 p", kLegend);
1632
1633     PrintCanvas("EventInspector - Monte-Carlo");  
1634   }
1635   //____________________________________________________________________
1636   virtual void DrawESDFixer(TCollection* parent)
1637   {
1638     Info("DrawESDFixer", "Drawing ESD fixer");
1639     TCollection* c = GetCollection(parent, "fmdESDFixer");
1640     if (!c) return;
1641
1642     Int_t  recoFactor = 0;
1643     Bool_t recalcEta = false;
1644     Bool_t invalidIsEmpty = false;
1645
1646     fBody->cd();
1647
1648     Double_t save = fParName->GetTextSize();
1649     fParName->SetTextSize(0.05);
1650     fParVal->SetTextSize(0.05);
1651
1652     fBody->Divide(2,2);
1653     fBody->cd(1);
1654     
1655     Double_t y = .8;
1656     if (GetParameter(c, "recoFactor", recoFactor))
1657         DrawParameter(y, "Noise factor used in reco",
1658                       Form("%d (assumed)", recoFactor));
1659     if (GetParameter(c, "recalcEta", recalcEta))
1660         DrawParameter(y, "Recalculate #eta",
1661                       Form("%s", (recalcEta ? "yes" : "no")));
1662     if (GetParameter(c, "invalidIsEmpty", invalidIsEmpty))
1663         DrawParameter(y, "Assume invalid strips are empty",
1664                       Form("%s", (invalidIsEmpty ? "yes" : "no")));
1665
1666     TCollection* xd = GetCollection(c, "extraDead");
1667     if (xd) 
1668       DrawParameter(y, "# extra dead strips", 
1669                     Form("%d", xd->GetEntries()));
1670     
1671     DrawInPad(fBody, 2, GetH1(c, "noiseChange"), "", kLogy);
1672     DrawInPad(fBody, 3, GetH1(c, "etaChange"), "", kLogy);
1673     DrawInPad(fBody, 4, GetH1(c, "deadChange"), "", kLogy);
1674         
1675     PrintCanvas("ESD Fixer");
1676     fParName->SetTextSize(save);
1677     fParVal->SetTextSize(save);
1678   }
1679   //____________________________________________________________________
1680   void DrawTrackDensity(TCollection* parent)
1681   {
1682     Info("DrawTrackDensity", "Drawing track density");
1683
1684     // --- MC --------------------------------------------------------
1685     TCollection* mc = GetCollection(parent, "mcTrackDensity", false);
1686     if (!mc) return; // Not MC 
1687
1688     fBody->Divide(2,3);
1689     DrawInPad(fBody, 1, GetH2(mc, "binFlow"),    "colz", kLogz);
1690     DrawInPad(fBody, 2, GetH2(mc, "binFlowEta"), "colz", kLogz);
1691     DrawInPad(fBody, 3, GetH2(mc, "binFlowPhi"), "colz", kLogz);
1692     DrawInPad(fBody, 4, GetH1(mc, "nRefs"),       "",    kLogy,
1693               "# of references");
1694     DrawInPad(fBody, 4, GetH1(mc, "clusterRefs",   false), "same");
1695     DrawInPad(fBody, 4, GetH1(mc, "clusterSize",   false), "same");
1696     DrawInPad(fBody, 4, GetH1(mc, "nClusters",     false), "same", kLegend);
1697     DrawInPad(fBody, 5, GetH2(mc, "clusterVsRefs", false),"colz", kLogz);
1698
1699     PrintCanvas("Track density");  
1700   }
1701   //__________________________________________________________________
1702   TCanvas* fCanvas;  // Our canvas 
1703   TPad*    fTop;     // Top part 
1704   TPad*    fBody;    // Body part 
1705   TLatex*  fHeader;  // Header text 
1706   TLatex*  fParName; // Parameter name 
1707   TLatex*  fParVal;  // Parameter value 
1708   Bool_t   fPause;   // Whether to pause after drawing a canvas
1709   Bool_t   fLandscape; // Landscape or Portrait orientation
1710   TVirtualPad** fRingMap;
1711   Bool_t   fPDF;
1712   TString  fLastTitle;
1713 };
1714 #if 0
1715 template <> 
1716 inline Bool_t 
1717 SummaryDrawer::DoGetParameter<Double_t>(TObject* o, const TObject* p, 
1718                                         Double_t& value)
1719 {
1720   TParameter<Double_t>* r = DoGetObject<TParameter<Double_t>(o, p);
1721   UInt_t  i = o->GetUniqueID();
1722   Float_t v = *reinterpret_cast<Float_t*>(&i);
1723   value = v;
1724   return true;
1725 }
1726 #endif
1727 inline Bool_t 
1728 SummaryDrawer::GetParameter(const TObject*   c, 
1729                             const TString&   name, 
1730                             Double_t&        value,
1731                             Bool_t           verb)
1732   
1733 {
1734   return DoGetParameter(GetObject(c, name, verb), c, value);
1735 }
1736
1737 #endif
1738 //
1739 // EOF
1740 //
1741