]> git.uio.no Git - u/mrichter/AliRoot.git/blame - TPC/AliTPCCalibQAChecker.cxx
Possibility to make PT sorting (Jochen)
[u/mrichter/AliRoot.git] / TPC / AliTPCCalibQAChecker.cxx
CommitLineData
949d8707 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>
cc65e4f5 27#include <TStyle.h>
28#include <TMarker.h>
29#include <TAxis.h>
30#include <TLine.h>
31#include <TList.h>
949d8707 32#include <TTree.h>
cc65e4f5 33#include <TMath.h>
949d8707 34#include <TGraph.h>
35#include <TFrame.h>
36#include <TIterator.h>
37#include <TPad.h>
cc65e4f5 38#include <TCanvas.h>
949d8707 39#include <TH1.h>
40#include <TH2.h>
41#include <TStopwatch.h>
42
43#include <AliLog.h>
44
45#include "AliTPCCalibQAChecker.h"
46
47using namespace std;
48
49AliTPCCalibQAChecker::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//_________________________________________________________________________
74AliTPCCalibQAChecker::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//_________________________________________________________________________
99AliTPCCalibQAChecker::~AliTPCCalibQAChecker()
100{
101 //
102 // Default ctor
103 //
104 if (fHistRep) delete fHistRep;
105 if (fIterSubCheckers) delete fIterSubCheckers;
106 if (fArrAlarmDescriptions) delete fArrAlarmDescriptions;
7442bceb 107 if (fArrSubCheckers) delete fArrSubCheckers;
949d8707 108}
109//_________________________________________________________________________
110void 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//_________________________________________________________________________
123void 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//_________________________________________________________________________
144void 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//_________________________________________________________________________
163void 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//_________________________________________________________________________
190void 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 }
cc65e4f5 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 }
949d8707 222}
223//_________________________________________________________________________
224void 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//_________________________________________________________________________
234void AliTPCCalibQAChecker::ProcessNumber()
235{
236 //
237 // process number type checker
238 //
239 if (!fNumberPtr) return;
240 fQualityLevel=GetQuality(*fNumberPtr);
cc65e4f5 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);
949d8707 257}
258//_________________________________________________________________________
259void 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//_________________________________________________________________________
277void 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//_________________________________________________________________________
289void 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//_________________________________________________________________________
327void 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 }
cc65e4f5 354 fHistRep=hist->Clone();
355 TH1 *h=(TH1*)fHistRep;
356 h->SetDirectory(0);
357 h->SetNameTitle(Form("h%s",GetName()),GetTitle());
949d8707 358}
359//_________________________________________________________________________
360void 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//_________________________________________________________________________
385void 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//_________________________________________________________________________
396void 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
cc65e4f5 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;}
949d8707 407}
408//_________________________________________________________________________
7442bceb 409void AliTPCCalibQAChecker::Print(Option_t * const option) const
949d8707 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//_________________________________________________________________________
425void AliTPCCalibQAChecker::SetAlarmThreshold(const Double_t min, const Double_t max, const 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//_________________________________________________________________________
435void AliTPCCalibQAChecker::ResetAlarmThreshold(const 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//_________________________________________________________________________
445void 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//_________________________________________________________________________
456void AliTPCCalibQAChecker::SetQualityDescription(const char* text, const 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//_________________________________________________________________________
472const AliTPCCalibQAChecker* AliTPCCalibQAChecker::GetSubChecker(const char* name, Bool_t recursive) const
473{
474 //
7442bceb 475 // Return subnode with 'name'
949d8707 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//_________________________________________________________________________
495Int_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//_________________________________________________________________________
517AliTPCCalibQAChecker* AliTPCCalibQAChecker::NextSubChecker()
518{
519 //
520 // loop over sub checkers
521 // if recursive, recursively return the pointers of non subchecker type sub checkers
522 //
a3b590cf 523 if (!fArrSubCheckers || !fArrSubCheckers->GetEntries()) return 0;
949d8707 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//_________________________________________________________________________
534const char* AliTPCCalibQAChecker::QualityName(const 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//_________________________________________________________________________
557Color_t AliTPCCalibQAChecker::QualityColor(const 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//_________________________________________________________________________
588const char* AliTPCCalibQAChecker::QualityDescription(const 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//_________________________________________________________________________
cc65e4f5 603Int_t AliTPCCalibQAChecker::DrawInPad(TVirtualPad *pad, Int_t sub)
949d8707 604{
605 //
7442bceb 606 // Draw recursively in 'pad'
949d8707 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}
cc65e4f5 625//_________________________________________________________________________
626void 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//_________________________________________________________________________
7442bceb 654void AliTPCCalibQAChecker::DrawRepresentationHist(const Option_t *option)
cc65e4f5 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//_________________________________________________________________________
682void 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}