Fixes for wrong use of const causing PW.CAST_TO_QUALIFIED_TYPE defect in Coverity
[u/mrichter/AliRoot.git] / TPC / Util / AliTPCCalibQAChecker.cxx
1 /**************************************************************************
2  * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
3  *                                                                        *
4  * Author: The ALICE Off-line Project.                                    *
5  * Contributors are mentioned in the code where appropriate.              *
6  *                                                                        *
7  * Permission to use, copy, modify and distribute this software and its   *
8  * documentation strictly for non-commercial purposes is hereby granted   *
9  * without fee, provided that the above copyright notice appears in all   *
10  * copies and that both the copyright notice and this permission notice   *
11  * appear in the supporting documentation. The authors make no claims     *
12  * about the suitability of this software for any purpose. It is          *
13  * provided "as is" without express or implied warranty.                  *
14  **************************************************************************/
15
16 ///////////////////////////////////////////////////////////////////////////////
17 //                                                                           //
18 //  Class to process a tree and create alarms based on thresholds            //
19 //  origin: jens wiechula: jens.wiechula@cern.ch                             //
20 //                                                                           //
21 ///////////////////////////////////////////////////////////////////////////////
22
23 #include <iostream>
24 #include <TObjArray.h>
25 #include <TString.h>
26 #include <TObjString.h>
27 #include <TStyle.h>
28 #include <TMarker.h>
29 #include <TAxis.h>
30 #include <TLine.h>
31 #include <TList.h>
32 #include <TTree.h>
33 #include <TMath.h>
34 #include <TGraph.h>
35 #include <TFrame.h>
36 #include <TIterator.h>
37 #include <TPad.h>
38 #include <TCanvas.h>
39 #include <TH1.h>
40 #include <TH2.h>
41 #include <TStopwatch.h>
42
43 #include <AliLog.h>
44
45 #include "AliTPCCalibQAChecker.h"
46
47 using namespace std;
48
49 AliTPCCalibQAChecker::AliTPCCalibQAChecker() :
50   TNamed("AliTPCCalibQAChecker","AliTPCCalibQAChecker"),
51   fTreePtr(0x0),
52   fHistPtr(0x0),
53   fGraphPtr(0x0),
54   fNumberPtr(0x0),
55   fHist(0x0),
56   fIterSubCheckers(0x0),
57   fArrSubCheckers(0x0),
58   fArrAlarmDescriptions(0x0),
59   fStrDrawRep(""),
60   fStrDrawRepOpt(""),
61   fStrDraw(""),
62   fStrDrawOpt(""),
63   fStrCuts(""),
64   fAlarmType(kMean),
65   fQualityLevel(kINFO),
66   fHistRep(0x0)
67 {
68   //
69   // Default ctor
70   //
71   ResetAlarmThresholds();
72 }
73 //_________________________________________________________________________
74 AliTPCCalibQAChecker::AliTPCCalibQAChecker(const char* name, const char *title) :
75   TNamed(name,title),
76   fTreePtr(0x0),
77   fHistPtr(0x0),
78   fGraphPtr(0x0),
79   fNumberPtr(0x0),
80   fHist(0x0),
81   fIterSubCheckers(0x0),
82   fArrSubCheckers(0x0),
83   fArrAlarmDescriptions(0x0),
84   fStrDrawRep(""),
85   fStrDrawRepOpt(""),
86   fStrDraw(""),
87   fStrDrawOpt(""),
88   fStrCuts(""),
89   fAlarmType(kMean),
90   fQualityLevel(kINFO),
91   fHistRep(0x0)
92 {
93   //
94   // TNamed ctor
95   //
96   ResetAlarmThresholds();
97 }
98 //_________________________________________________________________________
99 AliTPCCalibQAChecker::~AliTPCCalibQAChecker()
100 {
101   //
102   // Default ctor
103   //
104   if (fHistRep) delete fHistRep;
105   if (fIterSubCheckers) delete fIterSubCheckers;
106   if (fArrAlarmDescriptions) delete fArrAlarmDescriptions;
107   if (fArrSubCheckers) delete fArrSubCheckers;
108 }
109 //_________________________________________________________________________
110 void AliTPCCalibQAChecker::AddSubChecker(AliTPCCalibQAChecker *alarm)
111 {
112   //
113   // add a sub checker to this checker
114   //
115   if (!alarm) return;
116   if (!fArrSubCheckers) {
117     fArrSubCheckers=new TObjArray;
118     fArrSubCheckers->SetOwner();
119   }
120   fArrSubCheckers->Add(alarm);
121 }
122 //_________________________________________________________________________
123 void AliTPCCalibQAChecker::Process()
124 {
125   //
126   // Process the alarm thresholds, decide the alarm level, create the representation histogram
127   //
128
129   //reset quality level
130   fQualityLevel=kINFO;
131
132   TStopwatch s;
133   s.Start();
134   //decide which type of checker to use
135   if (fArrSubCheckers && fArrSubCheckers->GetEntries()>0) ProcessSub();
136   else if (fTreePtr && *fTreePtr) ProcessTree();
137   else if (fHistPtr && *fHistPtr) ProcessHist();
138   else if (fGraphPtr && *fGraphPtr) ProcessGraph();
139   else if (fNumberPtr) ProcessNumber();
140   s.Stop();
141   AliInfo(Form("Processing Time (%s): %fs",GetName(),s.RealTime()));
142 }
143 //_________________________________________________________________________
144 void AliTPCCalibQAChecker::ProcessSub()
145 {
146   //
147   // sub checker type checker
148   //
149   QualityFlag_t quality=kINFO;
150   if (fArrSubCheckers && fArrSubCheckers->GetEntries()>0){
151     TIter next(fArrSubCheckers);
152     TObject *o=0x0;
153     while ( (o=next()) ) {
154       AliTPCCalibQAChecker *al=(AliTPCCalibQAChecker*)o;
155       al->Process();
156       QualityFlag_t subQuality=al->GetQuality();
157       if (subQuality>quality) quality=subQuality;
158     }
159   }
160   fQualityLevel=quality;
161 }
162 //_________________________________________________________________________
163 void AliTPCCalibQAChecker::ProcessTree()
164 {
165   //
166   // process tree type checker
167   //
168
169   //Create Representation Histogram
170   CreateRepresentationHist();
171   //
172 //   if (!fTree) return;
173   //chek for the quality
174
175   switch (fAlarmType){
176   case kNentries:
177     ProcessEntries();
178     break;
179   case kMean:
180   case kBinAny:
181   case kBinAll:
182     CreateAlarmHist();
183     ProcessHist();
184     ResetAlarmHist();
185     break;
186   }
187   
188 }
189 //_________________________________________________________________________
190 void AliTPCCalibQAChecker::ProcessHist()
191 {
192   //
193   // process histogram type checker
194   //
195   
196   if (!(fHistPtr && *fHistPtr)) return;
197     
198   switch (fAlarmType){
199   case kNentries:
200   case kMean:
201     ProcessMean();
202     break;
203   case kBinAny:
204   case kBinAll:
205     ProcessBin();
206     break;
207   }
208
209   //create representation histogram if we are not in tree mode
210   if (!fTreePtr){
211     if (!fHistRep) {
212       fHistRep=(*fHistPtr)->Clone();
213       TH1* h=(TH1*)fHistRep;
214       h->SetDirectory(0);
215       h->SetNameTitle(Form("h%s",GetName()),GetTitle());
216     }
217     TH1* h=(TH1*)fHistRep;
218     h->Reset();
219     h->Add(*fHistPtr);
220     if (!fHistRep->InheritsFrom(TH2::Class())) AddQualityLines(h);
221   }
222 }
223 //_________________________________________________________________________
224 void AliTPCCalibQAChecker::ProcessGraph()
225 {
226   //
227   // process graph type checker
228   //
229   if (!(fGraphPtr && *fGraphPtr)) return;
230   Int_t npoints=(*fGraphPtr)->GetN();
231   fQualityLevel=GetQuality(npoints,(*fGraphPtr)->GetY());
232 }
233 //_________________________________________________________________________
234 void AliTPCCalibQAChecker::ProcessNumber()
235 {
236   //
237   // process number type checker
238   //
239   if (!fNumberPtr) return;
240   fQualityLevel=GetQuality(*fNumberPtr);
241   //create representation histogram
242   if (!fHistRep){
243     TH1* h=new TH1F(Form("h%s",GetName()),GetTitle(),1,0,1);
244     h->GetXaxis()->SetBinLabel(1,"Value");
245     AddQualityLines(h);
246     h->SetDirectory(0);
247     fHistRep=h;
248   }
249   TH1 *h=(TH1*)fHistRep;
250   TMarker *marker=(TMarker*)h->GetListOfFunctions()->FindObject("TMarker");
251   if (!marker) {
252     marker=new TMarker(.5,0,20);
253     h->GetListOfFunctions()->Add(marker);
254   }
255   marker->SetMarkerColor(GetQualityColor());
256   marker->SetY(*fNumberPtr);
257 }
258 //_________________________________________________________________________
259 void AliTPCCalibQAChecker::ProcessEntries()
260 {
261   //
262   // Processing function which analyses the number of affected rows of a tree draw
263   //
264   TString draw=fStrDraw;
265   if (draw.IsNull()) return;
266   
267   TString cuts=fStrCuts;
268   
269   TString opt=fStrDrawOpt;
270   opt+="goff";
271   
272   //draw and get the histogram
273   Int_t res=(*fTreePtr)->Draw(draw.Data(),cuts.Data(),opt.Data());
274   fQualityLevel=GetQuality(res);
275 }
276 //_________________________________________________________________________
277 void AliTPCCalibQAChecker::ProcessMean()
278 {
279   //
280   // Processing function which analyses the mean of the resulting histogram
281   //
282
283   TH1* h=(*fHistPtr);
284   Double_t value=h->GetMean();
285   if (fAlarmType==kNentries) value=h->GetEntries();
286   fQualityLevel=GetQuality(value);
287 }
288 //_________________________________________________________________________
289 void AliTPCCalibQAChecker::ProcessBin()
290 {
291   //
292   // Process a histogram bin by bin and check for thresholds
293   //
294
295   //bin quality counters
296   Int_t nquality[kNQualityFlags];
297   for (Int_t iquality=(Int_t)kINFO; iquality<kNQualityFlags; ++iquality) nquality[iquality]=0;
298     
299   TH1 *h=(*fHistPtr);
300   
301   Int_t nbinsX=h->GetNbinsX();
302   Int_t nbinsY=h->GetNbinsY();
303   Int_t nbinsZ=h->GetNbinsZ();
304   Int_t nbinsTotal=nbinsX*nbinsY*nbinsZ;
305
306   //loop over all bins
307   for (Int_t ibinZ=1;ibinZ<nbinsZ+1;++ibinZ){
308     for (Int_t ibinY=1;ibinY<nbinsY+1;++ibinY){
309       for (Int_t ibinX=1;ibinX<nbinsX+1;++ibinX){
310         Double_t value = (*fHistPtr)->GetBinContent(ibinX, ibinY, ibinZ);
311         QualityFlag_t quality=GetQuality(value);
312         nquality[quality]++;
313       }
314     }
315   }
316
317   //loop over Quality levels and set quality
318   for (Int_t iquality=(Int_t)kINFO; iquality<kNQualityFlags; ++iquality){
319     if (fAlarmType==kBinAny){
320       if (nquality[iquality]) fQualityLevel=(QualityFlag_t)iquality;
321     } else if (fAlarmType==kBinAll){
322       if (nquality[iquality]==nbinsTotal) fQualityLevel=(QualityFlag_t)iquality;
323     }
324   }
325 }
326 //_________________________________________________________________________
327 void AliTPCCalibQAChecker::CreateRepresentationHist()
328 {
329   //
330   // Create the representation histogram which will be shown in the draw function
331   //
332   ResetRepresentationHist();
333
334   TString draw=fStrDrawRep;
335   if (draw.IsNull()) {
336     draw=fStrDraw;
337     fStrDrawRepOpt=fStrDrawOpt;
338   } else {
339     draw.ReplaceAll("%alarm%",fStrDraw.Data());
340   }
341   if (draw.IsNull()) return;
342   
343   TString cuts=fStrCuts;
344   
345   TString opt=fStrDrawRepOpt;
346   opt+="goff";
347   
348   Int_t res=(*fTreePtr)->Draw(draw.Data(),cuts.Data(),opt.Data());
349   TH1 *hist=(*fTreePtr)->GetHistogram();
350   if (res<0 || !hist){
351     AliError(Form("Could not create representation histogram of alarm '%s'",GetName()));
352     return;
353   }
354   fHistRep=hist->Clone();
355   TH1 *h=(TH1*)fHistRep;
356   h->SetDirectory(0);
357   h->SetNameTitle(Form("h%s",GetName()),GetTitle());
358 }
359 //_________________________________________________________________________
360 void AliTPCCalibQAChecker::CreateAlarmHist()
361 {
362   //
363   // create alarm histogram from the tree
364   //
365     
366   TString draw=fStrDraw;
367   if (draw.IsNull()) return;
368   
369   TString cuts=fStrCuts;
370   
371   TString opt=fStrDrawOpt;
372   opt+="goff";
373   
374   //draw and get the histogram
375   Int_t res=(*fTreePtr)->Draw(draw.Data(),cuts.Data(),opt.Data());
376   fHist=(*fTreePtr)->GetHistogram();
377   if (res<0 || !fHist){
378     AliError(Form("Could not create alarm histogram of alarm '%s'",GetName()));
379     return;
380   }
381   fHist->SetDirectory(0);
382   fHistPtr=&fHist;
383 }
384 //_________________________________________________________________________
385 void AliTPCCalibQAChecker::ResetAlarmHist()
386 {
387   //
388   // delete the alarm histogram and reset the pointer
389   //
390   if (fHistPtr){
391     if (*fHistPtr) delete *fHistPtr;
392     fHistPtr=0x0;
393   }
394 }
395 //_________________________________________________________________________
396 void AliTPCCalibQAChecker::Draw(Option_t *option)
397 {
398   //
399   // object draw function
400   // by default the pad backgound color is set to the quality level color
401   // use 'nobc' to change this
402   //
403
404   //case of a node with subcheckers and no specific representation histogram
405   if (HasSubCheckers()&&!fHistRep) {DrawSubNodes(option); return;}
406   if (fHistRep) {DrawRepresentationHist(option); return;}
407 }
408 //_________________________________________________________________________
409 void AliTPCCalibQAChecker::Print(Option_t * const option) const
410 {
411   //
412   // print the quality status. If we have sub checkers print recursively
413   //
414   TString sOpt(option);
415   cout << sOpt << GetName() << ": " << GetQualityName() << endl;
416   if (fArrSubCheckers && fArrSubCheckers->GetEntries()>0){
417     sOpt.ReplaceAll("+-","  ");
418     sOpt+="+-";
419     TIter next(fArrSubCheckers);
420     TObject *o=0x0;
421     while ( (o=next()) ) o->Print(sOpt.Data());
422   }
423 }
424 //_________________________________________________________________________
425 void AliTPCCalibQAChecker::SetAlarmThreshold(Double_t min, Double_t max, QualityFlag_t quality)
426 {
427   //
428   //set the alarm thresholds for a specific quality level
429   //
430   if ((Int_t)quality<(Int_t)kINFO||(Int_t)quality>=kNQualityFlags) return;
431   fThresMin[quality]=min;
432   fThresMax[quality]=max;
433 }
434 //_________________________________________________________________________
435 void AliTPCCalibQAChecker::ResetAlarmThreshold(QualityFlag_t quality)
436 {
437   //
438   //set the alarm thresholds for a specific quality level
439   //
440   if ((Int_t)quality<(Int_t)kINFO||(Int_t)quality>=kNQualityFlags) return;
441   fThresMin[quality]=0;
442   fThresMax[quality]=0;
443 }
444 //_________________________________________________________________________
445 void AliTPCCalibQAChecker::ResetAlarmThresholds()
446 {
447   //
448   //reset all the alarm thresholds
449   //
450   for (Int_t i=0;i<kNQualityFlags;++i){
451     fThresMin[i]=0;
452     fThresMax[i]=0;
453   }
454 }
455 //_________________________________________________________________________
456 void AliTPCCalibQAChecker::SetQualityDescription(const char* text, QualityFlag_t quality)
457 {
458   //
459   // set an description for the quality level
460   // %min and %max will be replaced by the min and max values of the alarm, when the quality
461   // description is queried (see QualityDescription)
462   //
463
464   if (quality<kINFO||quality>kFATAL) return;
465   if (! fArrAlarmDescriptions ) fArrAlarmDescriptions=new TObjArray(kNQualityFlags);
466   TObjString *s=(TObjString*)fArrAlarmDescriptions->At(quality);
467   if (!s) fArrAlarmDescriptions->AddAt(s=new TObjString,quality);
468   s->SetString(text);
469 }
470
471 //_________________________________________________________________________
472 const AliTPCCalibQAChecker* AliTPCCalibQAChecker::GetSubChecker(const char* name, Bool_t recursive) const
473 {
474   //
475   // Return subnode with 'name'
476   //
477   TString sname(name);
478   if (sname==GetName()) return this;
479   if (!fArrSubCheckers || !fArrSubCheckers->GetEntries()) return 0x0;
480   const AliTPCCalibQAChecker *al=0x0;
481   if (recursive){
482     TIter next(fArrSubCheckers);
483     TObject *o=0x0;
484     while ( (o=next()) ){
485       AliTPCCalibQAChecker *sal=(AliTPCCalibQAChecker*)o;
486       al=sal->GetSubChecker(name);
487       if (al) break;
488     }
489   }else{
490     al=dynamic_cast<AliTPCCalibQAChecker*>(fArrSubCheckers->FindObject(name));
491   }
492   return al;
493 }
494 //_________________________________________________________________________
495 Int_t AliTPCCalibQAChecker::GetNumberOfSubCheckers(Bool_t recursive) const
496 {
497   //
498   // get the number of sub checkers
499   // if recursive get total number of non subchecker type sub checkers
500   //
501   Int_t nsub=0;
502   if (recursive){
503     if (!fArrSubCheckers) return 1;
504     if (!fArrSubCheckers->GetEntries()) return 0;
505     TIter next(fArrSubCheckers);
506     TObject *o=0x0;
507     while ( (o=next()) ){
508       AliTPCCalibQAChecker *al=(AliTPCCalibQAChecker*)o;
509       nsub+=al->GetNumberOfSubCheckers();
510     }
511   } else {
512     if (fArrSubCheckers) nsub=fArrSubCheckers->GetEntries();
513   }
514   return nsub;
515 }
516 //_________________________________________________________________________
517 AliTPCCalibQAChecker* AliTPCCalibQAChecker::NextSubChecker()
518 {
519   //
520   // loop over sub checkers
521   // if recursive, recursively return the pointers of non subchecker type sub checkers
522   //
523   if (!fArrSubCheckers || !fArrSubCheckers->GetEntries()) return 0;
524   if (!fIterSubCheckers) fIterSubCheckers=fArrSubCheckers->MakeIterator();
525   AliTPCCalibQAChecker *al=(AliTPCCalibQAChecker*)fIterSubCheckers->Next();
526   if (!al){
527     delete fIterSubCheckers;
528     fIterSubCheckers=0x0;
529   }
530 //   if (recursive && al->GetNumberOfSubCheckers(kFALSE)) al=al->NextSubChecker();
531   return al;
532 }
533 //_________________________________________________________________________
534 const char* AliTPCCalibQAChecker::QualityName(AliTPCCalibQAChecker::QualityFlag_t quality)
535 {
536   //
537   // get quality name for quality
538   //
539   switch (quality){
540   case kINFO:
541     return "Info";
542     break;
543   case kWARNING:
544     return "Warning";
545     break;
546   case kERROR:
547     return "Error";
548     break;
549   case kFATAL:
550     return "Fatal";
551     break;
552   default:
553     return "";
554   }
555 }
556 //_________________________________________________________________________
557 Color_t AliTPCCalibQAChecker::QualityColor(AliTPCCalibQAChecker::QualityFlag_t quality)
558 {
559   //
560   // get quality color for quality
561   //
562   Color_t info = kSpring-8;
563   Color_t warning = kOrange;
564   Color_t error = kRed;
565   Color_t fatal = kRed+2;
566   Color_t none = kWhite;
567   
568   switch(quality) {
569   case kINFO :
570     return info;
571     break;
572   case kWARNING :
573     return warning;
574     break;
575   case kERROR :
576     return error;
577     break;
578   case kFATAL :
579     return fatal;
580     break;
581   default:
582     return none;
583   }
584   return none;
585   
586 }
587 //_________________________________________________________________________
588 const char* AliTPCCalibQAChecker::QualityDescription(QualityFlag_t quality) const
589 {
590   //
591   // return description for quality
592   //
593   if (!fArrAlarmDescriptions || !fArrAlarmDescriptions->At(quality)) return "";
594   TString s(fArrAlarmDescriptions->At(quality)->GetName());
595   TString min, max;
596   min+=fThresMin[quality];
597   max+=fThresMax[quality];
598   s.ReplaceAll("%min",min);
599   s.ReplaceAll("%max",max);
600   return s.Data();
601 }
602 //_________________________________________________________________________
603 Int_t AliTPCCalibQAChecker::DrawInPad(TVirtualPad *pad, Int_t sub)
604 {
605   //
606   // Draw recursively in 'pad'
607   //
608   
609   if (fArrSubCheckers){
610     if (fArrSubCheckers->GetEntries()>0){
611       TIter next(fArrSubCheckers);
612       TObject *o=0x0;
613       while ( (o=next()) ) {
614         AliTPCCalibQAChecker *al=(AliTPCCalibQAChecker*)o;
615         sub=al->DrawInPad(pad,sub);
616       }
617     }
618   } else {
619     pad->cd(sub);
620     ++sub;
621     Draw();
622   }
623   return sub;
624 }
625 //_________________________________________________________________________
626 void AliTPCCalibQAChecker::DrawSubNodes(Option_t */*option*/)
627 {
628   //
629   // divide the current pad in sub pads and draw all sub nodes
630   //
631   if (!gPad) new TCanvas;
632   TPad *mother=(TPad*)gPad;
633   mother->Clear();
634   //find number of sub pads needed
635   Int_t nPads = GetNumberOfSubCheckers();
636   Int_t nCols = (Int_t)TMath::Ceil( TMath::Sqrt(nPads) );
637   Int_t nRows = (Int_t)TMath::Ceil( (Double_t)nPads/(Double_t)nCols );
638   gPad->Divide(nCols,nRows);
639   
640   DrawInPad(gPad);
641   mother->Update();
642   TPad *pad=0;
643   Int_t ipad=1;
644   while ( (pad=(TPad*)mother->GetPad(ipad)) ){
645     TFrame* frame=(TFrame*)pad->GetPrimitive("TFrame");
646     if (frame) frame->SetFillColor(kWhite);
647     else {printf("no frame\n");}
648     pad->Modified();
649     ++ipad;
650   }
651   mother->Update();
652 }
653 //_________________________________________________________________________
654 void AliTPCCalibQAChecker::DrawRepresentationHist(const Option_t *option)
655 {
656   //
657   // Draw the representation histogram
658   //
659   if (!fHistRep) return;
660   if (!gPad) new TCanvas;
661   Bool_t withBackColor=kTRUE;
662   
663   TString opt=option;
664   opt.ToLower();
665   
666   if (opt.Contains("nobc")) withBackColor=kFALSE;
667   opt.ReplaceAll("nobc","");
668   
669   if (opt.IsNull()) opt=fStrDrawRepOpt;
670   opt.ToLower();
671   
672   opt.ReplaceAll("prof","");
673   
674   fHistRep->Draw(opt.Data());
675   if (withBackColor) {
676     gPad->SetFillColor(GetQualityColor());
677   }
678   
679   gPad->Modified();
680 }
681 //_________________________________________________________________________
682 void AliTPCCalibQAChecker::AddQualityLines(TH1 *hist)
683 {
684   //
685   // add lines indicating the quality level to hist
686   //
687
688   Double_t xmin=hist->GetXaxis()->GetXmin();
689   Double_t xmax=hist->GetXaxis()->GetXmax();
690   Double_t min=0;
691   Double_t max=0;
692   
693   for (Int_t i=(Int_t)kINFO; i<kNQualityFlags; ++i){
694     if (fThresMin[i]>=fThresMax[i]) continue;
695     min=fThresMin[i];
696     max=fThresMax[i];
697     TLine *lmin=new TLine(xmin,min,xmax,min);
698     lmin->SetLineWidth(2);
699     lmin->SetLineColor(QualityColor((QualityFlag_t)i));
700     TLine *lmax=new TLine(xmin,max,xmax,max);
701     lmax->SetLineWidth(2);
702     lmax->SetLineColor(QualityColor((QualityFlag_t)i));
703     hist->GetListOfFunctions()->Add(lmin);
704     hist->GetListOfFunctions()->Add(lmax);
705   }
706   hist->SetAxisRange(min,max,"Y");
707 }