source: trunk/MagicSoft/Mars/mhist/MHArray.cc@ 2173

Last change on this file since 2173 was 2173, checked in by tbretz, 21 years ago
*** empty log message ***
File size: 20.2 KB
Line 
1/* ======================================================================== *\
2!
3! *
4! * This file is part of MARS, the MAGIC Analysis and Reconstruction
5! * Software. It is distributed to you in the hope that it can be a useful
6! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
7! * It is distributed WITHOUT ANY WARRANTY.
8! *
9! * Permission to use, copy, modify and distribute this software and its
10! * documentation for any purpose is hereby granted without fee,
11! * provided that the above copyright notice appear in all copies and
12! * that both that copyright notice and this permission notice appear
13! * in supporting documentation. It is provided "as is" without express
14! * or implied warranty.
15! *
16!
17!
18! Author(s): Thomas Bretz 07/2001 <mailto:tbretz@astro.uni-wuerzburg.de>
19!
20! Copyright: MAGIC Software Development, 2000-2002
21!
22!
23\* ======================================================================== */
24
25//////////////////////////////////////////////////////////////////////////////
26//
27// MHArray
28//
29// is a sequential collection of mars histograms. If the given index to
30// call the Fill function of the histogram excceeds the size of the
31// array by 1 a new entry is created.
32//
33// With Set/Inc/DecIndex you may specify the actual index of the histogram
34// wich should be filles by Fill.
35//
36// Use GetH to get the current histogram, the []-operator get the histogram
37// by its index.
38//
39// To access the histograms by a key instead of an index use SetIndexByKey
40// instead of Set/Inc/DecIndex. It will take the integerpart of the
41// floating point value (2 in case of 2.9). For each new key a new
42// index in the Mapping Table is created. So that you can access your
43// histograms by the key (eg in case of the Angle Theta=23.2deg use
44// SetIndexByKey(23.2)
45//
46// If the index is equal to the number of histograms in the array a call
47// to the Fill-member-function will create a new histogram.
48//
49// In the constructor istempl leads to two different behaviours of the
50// MHArray:
51//
52// - istempl=kTRUE tells MHArray to use the first histogram retrieved from
53// the Parameterlist by hname to be used as a template. New histograms
54// are not created using the root dictionary, but the New-member function
55// (see MParConatiner)
56// - In the case istempl=kFALSE new histograms are created using the root
57// dictionary while hname is the class name. For the creation their
58// default constructor is used.
59//
60//////////////////////////////////////////////////////////////////////////////
61#include "MHArray.h"
62
63#include <TH1.h>
64#include <TH2.h>
65#include <TH3.h>
66#include <TStyle.h>
67#include <TGaxis.h>
68#include <TCanvas.h>
69#include <TLegend.h>
70#include <TPaveStats.h>
71
72#include "MLog.h"
73#include "MLogManip.h"
74
75#include "MParList.h"
76#include "MParContainer.h"
77
78#include "MBinning.h"
79
80ClassImp(MHArray);
81
82using namespace std;
83
84//////////////////////////////////////////////////////////////////////////////
85//
86// MMap
87//
88// This class maps a key-value to a given value. In its simple versions it
89// maps a key to an index.
90//
91//////////////////////////////////////////////////////////////////////////////
92#include <TArrayI.h>
93
94class MMap
95{
96private:
97 TArrayI fKeys;
98 TArrayI fValues;
99
100 Int_t K(Int_t i) const { return ((TArrayI)fKeys)[i]; }
101 Int_t V(Int_t i) const { return ((TArrayI)fValues)[i]; }
102
103public:
104 // --------------------------------------------------------------------------
105 //
106 // Return the size of the table
107 //
108 Int_t GetSize() const
109 {
110 return fKeys.GetSize();
111 }
112
113 // --------------------------------------------------------------------------
114 //
115 // Get the value which corresponds to the given key-value
116 //
117 Int_t GetValue(Int_t key) const
118 {
119 const Int_t n = fKeys.GetSize();
120 for (int i=0; i<n; i++)
121 {
122 if (K(i)==key)
123 return V(i);
124 }
125 return -1;
126 }
127
128 // --------------------------------------------------------------------------
129 //
130 // Get the key which corresponds to the given index
131 //
132 Int_t GetKey(Int_t value) const
133 {
134 const Int_t n = fKeys.GetSize();
135 for (int i=0; i<n; i++)
136 {
137 if (V(i)==value)
138 return K(i);
139 }
140 return -1;
141 }
142
143 // --------------------------------------------------------------------------
144 //
145 // Adds a new pair key-value. While the key is the key to the value.
146 // if the key already exists the pair is ignored.
147 //
148 void Add(Int_t key, Int_t value)
149 {
150 if (GetValue(key)>=0)
151 return;
152
153 const Int_t n = fKeys.GetSize();
154
155 fKeys.Set(n+1);
156 fValues.Set(n+1);
157
158 fKeys[n] = key;
159 fValues[n] = value;
160 }
161
162 // --------------------------------------------------------------------------
163 //
164 // Adds a new pair key-value. While the key is the key to the value.
165 // In this case the value is an automatically sequential created index.
166 // if the key already exists the pair is ignored.
167 //
168 Int_t Add(Int_t key)
169 {
170 const Int_t k = GetValue(key);
171 if (k>=0)
172 return k;
173
174 const Int_t n = fKeys.GetSize();
175
176 fKeys.Set(n+1);
177 fValues.Set(n+1);
178
179 fKeys[n] = key;
180 fValues[n] = n;
181
182 return n;
183 }
184};
185
186void MHArray::Init(const char *name)
187{
188 fName = name ? name : "MHArray";
189
190 fMapIdx = new MMap;
191
192 fArray = new TList;
193 fArray->SetOwner();
194}
195
196// --------------------------------------------------------------------------
197//
198// Can replace a constructor. Use the default constructor and afterwards
199// the Set function of your need.
200//
201void MHArray::Set(const TString hname, Bool_t istempl)
202{
203 if (fTemplate || fClass || fTemplateName!="<dummy>")
204 {
205 *fLog << warn << "WARNING - MHArray already setup... Set ignored." << endl;
206 return;
207 }
208
209 if (istempl)
210 {
211 fTemplateName = hname;
212 return;
213 }
214
215 //
216 // try to get class from root environment
217 //
218 fClass = gROOT->GetClass(hname);
219 if (!fClass)
220 {
221 //
222 // if class is not existing in the root environment
223 //
224 *fLog << err << dbginf << "Class '" << hname << "' not existing in dictionary." << endl;
225 }
226
227 //
228 // check for ineritance from MH
229 //
230 if (!fClass->InheritsFrom(MH::Class()))
231 {
232 //
233 // if class doesn't inherit from MH --> error
234 //
235 *fLog << err << dbginf << "Class '" << hname << "' doesn't inherit from MH." << endl;
236 fClass = NULL;
237 }
238}
239
240// --------------------------------------------------------------------------
241//
242// Can replace a constructor. Use the default constructor and afterwards
243// the Set function of your need.
244//
245void MHArray::Set(const MH *hist)
246{
247 fIdx=0;
248 fClass=NULL;
249 fTemplate=hist;
250 fTemplateName="<dummy>";
251}
252
253
254// --------------------------------------------------------------------------
255//
256// hname is the name of the histogram class which is in the array.
257//
258// istempl=kTRUE tells MHArray to use the first histogram retrieved from the
259// ParameterList by hname to be used as a template. New histograms are not
260// created using the root dictionary, but the New-member function (see
261// MParConatiner)
262// In the case istempl=kFALSE new histograms are created using the root
263// dictionary while hname is the class name. For the creation their
264// default constructor is used.
265//
266MHArray::MHArray(const TString hname, Bool_t istempl, const char *name, const char *title)
267 : fIdx(0), fClass(NULL), fTemplate(NULL)
268{
269 //
270 // set the name and title of this object
271 //
272 Init(name);
273 fTitle = title ? TString(title) : (TString("Base class for Mars histogram arrays:") + hname);
274
275 Set(hname, istempl);
276}
277
278// --------------------------------------------------------------------------
279//
280// Default constructor. Use MHArray::Set to setup the MHArray afterwards
281//
282MHArray::MHArray(const char *name, const char *title)
283 : fIdx(0), fClass(NULL), fTemplate(NULL), fTemplateName("<dummy>")
284{
285 //
286 // set the name and title of this object
287 //
288 Init(name);
289 fTitle = title ? title : "A Mars histogram array";
290}
291
292// --------------------------------------------------------------------------
293//
294// hname is the name of the histogram class which is in the array.
295//
296// istempl=kTRUE tells MHArray to use the first histogram retrieved from the
297// ParameterList by hname to be used as a template. New histograms are not
298// created using the root dictionary, but the New-member function (see
299// MParConatiner)
300// In the case istempl=kFALSE new histograms are created using the root
301// dictionary while hname is the class name. For the creation their
302// default constructor is used.
303//
304MHArray::MHArray(const MH *hist, const char *name, const char *title)
305 : fIdx(0), fClass(NULL), fTemplate(hist), fTemplateName("<dummy>")
306{
307 //
308 // set the name and title of this object
309 //
310 Init(name);
311 fTitle = title ? TString(title) : (TString("Base class for Mars histogram arrays:") + hist->GetName());
312}
313
314// --------------------------------------------------------------------------
315//
316// Destructor: Deleteing the array and all histograms which are part of the
317// array.
318//
319MHArray::~MHArray()
320{
321 fArray->Delete();
322 delete fArray;
323 delete fMapIdx;
324}
325
326// --------------------------------------------------------------------------
327//
328// Use this to access the histograms by a key. If you use values like
329// (in this order) 2.5, 7.2, 2.5, 9.3, 9.3, 3.3, 2.2, 1.1
330// it will be mapped to the following indices internally:
331// 0 1 0 2 2 3 4 5
332//
333// WARNING: Make sure that you don't create new histograms by setting
334// a new index (SetIndex or IncIndex) which is equal the size
335// of the array and create new histogram by CreateH. In this
336// case you will confuse the mapping completely.
337//
338void MHArray::SetIndexByKey(Double_t key)
339{
340 fIdx = fMapIdx->Add((Int_t)key);
341}
342
343// --------------------------------------------------------------------------
344//
345// Use this function to access a histogram by its index in the array.
346// Becarefull the index isn't checked!
347//
348MH &MHArray::operator[](Int_t i)
349{
350 return *(MH*)fArray->At(i);
351}
352
353// --------------------------------------------------------------------------
354//
355// Use this function to access a histogram by its index in the array.
356// Becarefull the index isn't checked!
357//
358MH *MHArray::At(Int_t i)
359{
360 return (MH*)fArray->At(i);
361}
362
363// --------------------------------------------------------------------------
364//
365// Use this function to access the histogram corresponding to the
366// currently set index (by Set/Inc/DecIndex or SetIndexByKey)
367// Becarefull the index set isn't checked!
368//
369MH *MHArray::GetH()
370{
371 return (MH*)fArray->At(fIdx);
372}
373
374// --------------------------------------------------------------------------
375//
376// Tries to create a new histogram, adds it as last entry to the array
377// and tries to call SetupFill for it. In case of success the last entry
378// in the array is the new histogram and kTRUE is returned. Otherwise
379// kFALSE is returned.
380//
381Bool_t MHArray::CreateH()
382{
383 TString cname = fClass ? fClass->GetName() : fTemplate->IsA()->GetName();
384
385 MH *hist = NULL;
386 if (fTemplate)
387 {
388 //
389 // create the parameter container as a clone of the existing
390 // template histogram.
391 //
392 hist = (MH*)fTemplate->New();
393 }
394 else
395 {
396 //
397 // create the parameter container of the the given class type
398 //
399 hist = (MH*)fClass->New();
400 }
401 if (!hist)
402 {
403 *fLog << err << dbginf << "Cannot create new instance of class '";
404 *fLog << cname << "' (Maybe no def. constructor)" << endl;
405 return kFALSE;
406 }
407
408 //
409 // Set the name of the container
410 //
411 if (!fTemplate)
412 {
413 TString name = TString(hist->GetName())+";";
414 name += fIdx;
415
416 hist->SetName(name);
417 }
418
419 //
420 // Try to setup filling for the histogram
421 //
422 if (!hist->SetupFill(fParList))
423 {
424 *fLog << err << dbginf << "SetupFill for new histogram of type '";
425 *fLog << cname << "' with Index #" << fIdx << " failed." << endl;
426 delete hist;
427 return kFALSE;
428 }
429
430 fArray->AddLast(hist);
431
432 return kTRUE;
433}
434
435// --------------------------------------------------------------------------
436//
437// Returns kFALSE if the class couldn't be found in the root dictionary or
438// if it doesn't inherit from MH.
439// The parameter list is remembert to be used for SetupFill in case a new
440// histogram is created.
441// The index is reset to 0
442//
443Bool_t MHArray::SetupFill(const MParList *pList)
444{
445 fParList = pList;
446 fIdx = 0;
447
448 if (fTemplate)
449 return kTRUE;
450
451 if (!fTemplateName.IsNull())
452 {
453 fTemplate = (MH*)pList->FindObject(fTemplateName, "MH");
454 return fTemplate ? kTRUE : kFALSE;
455 }
456
457 return fClass ? kTRUE : kFALSE;
458}
459
460// --------------------------------------------------------------------------
461//
462// Call Fill for the present histogram index. If the index is out of
463// bounds the event is skipped. If the index is the number of current
464// histograms in the array a new histogram is created and if creation was
465// successfull filled.
466//
467Bool_t MHArray::Fill(const MParContainer *par, const Stat_t w)
468{
469 const Int_t n = fArray->GetSize();
470
471 if (fIdx<0 || fIdx>n)
472 {
473 *fLog << warn << "Histogram Index #" << fIdx << " out of bounds (>";
474 *fLog << n << ")... skipped." << endl;
475 return kCONTINUE;
476 }
477
478 if (fIdx==n)
479 if (!CreateH())
480 return kFALSE;
481
482 return GetH()->Fill(par, w);
483}
484
485Bool_t MHArray::AddHistogram()
486{
487 fIdx=fArray->GetSize();
488
489 return CreateH();
490}
491
492// --------------------------------------------------------------------------
493//
494// Calls Finalize for all histograms in the list. If at least one Finalize
495// fails kFALSE is returned.
496//
497Bool_t MHArray::Finalize()
498{
499 Bool_t rc = kTRUE;
500
501 TIter Next(fArray);
502 MH *hist = NULL;
503
504 while ((hist=(MH*)Next()))
505 if (!hist->Finalize())
506 rc = kFALSE;
507
508 return rc;
509}
510
511// --------------------------------------------------------------------------
512//
513// Print the number of entries in the array
514//
515void MHArray::Print(Option_t *option) const
516{
517 *fLog << all << GetDescriptor() << " contains " << fArray->GetSize();
518 *fLog << " histograms." << endl;
519
520 if (fMapIdx->GetSize()<=0)
521 return;
522
523 *fLog << " idx\t key" << endl;
524 for (int i=0; i<fMapIdx->GetSize(); i++)
525 *fLog << " " << i << "\t<--> " << fMapIdx->GetKey(i) << endl;
526 *fLog << endl;
527}
528
529// --------------------------------------------------------------------------
530//
531// Adds the given object to the given legend (if != NULL). The Legend
532// entry name is created from the key...
533//
534void MHArray::AddLegendEntry(TLegend *leg, TObject *obj, Int_t idx) const
535{
536 if (!leg)
537 return;
538
539 TString name = " ";
540 name += fMapIdx->GetKey(idx);
541 leg->AddEntry(obj, name, "lpf"); // l=line, p=polymarker, f=fill
542}
543
544
545// --------------------------------------------------------------------------
546//
547// The option is the name of the histogram, used to get a histogram from
548// the MH entries by calling their GetHist function.
549//
550void MHArray::Draw(Option_t *opt)
551{
552 if (!gPad)
553 MH::MakeDefCanvas(this);
554
555 const Int_t sstyle = gStyle->GetOptStat();
556 gStyle->SetOptStat(0);
557
558 //
559 // if the keymapping is used create a legend to identify the histograms
560 //
561 TLegend *leg = NULL;
562 if (fMapIdx->GetSize()>0)
563 {
564 leg = new TLegend(0.85, 0.80, 0.99, 0.99);
565 leg->SetBit(kCanDelete);
566 }
567
568 TIter Next(fArray);
569 MH *hist = (MH*)Next();
570
571 Int_t idx=0;
572 Double_t max=0;
573 Double_t min=0;
574
575 TH1 *h1=NULL;
576
577 //
578 // If the array has at least one entry:
579 // - find the starting boundaries
580 // - draw it and set its line color
581 //
582 if (hist)
583 {
584 if ((h1 = hist->GetHistByName(opt)))
585 {
586 h1->Draw();
587 h1->SetLineColor(idx+2);
588 max = h1->GetMaximum();
589 min = h1->GetMinimum();
590
591 AddLegendEntry(leg, h1, idx);
592 }
593 }
594
595 //
596 // For all following histograms:
597 // - update the boundaries
598 // - draw it and set its line color
599 //
600 while ((hist=(MH*)Next()))
601 {
602 TH1 *h=NULL;
603
604 if (!(h = hist->GetHistByName(opt)))
605 continue;
606
607 h->Draw("same");
608 h->SetLineColor(idx+2);
609 if (max<h->GetMaximum())
610 max = h->GetMaximum();
611 if (min>h->GetMinimum())
612 min = h->GetMinimum();
613
614 AddLegendEntry(leg, h, idx++);
615 }
616
617 //
618 // Now update the drawing region so that everything is displayed
619 //
620 if (h1)
621 {
622 h1->SetMinimum(min>0 ? min*0.95 : min*1.05);
623 h1->SetMaximum(max>0 ? max*1.05 : max*0.95);
624 }
625
626 if (leg)
627 leg->Draw();
628
629 gPad->Modified();
630 gPad->Update();
631
632 gStyle->SetOptStat(sstyle);
633}
634
635// --------------------------------------------------------------------------
636//
637// The option is the name of the histogram, used to get a histogram from
638// the MH entries by calling their GetHistByName function.
639// If the option also contains 'nonew' no new canvas is created.
640// The option "Scale=1" scales the area of all histogram to 1
641// The option "Scale=max" scales the maximum of all histogram to 1
642//
643TObject *MHArray::DrawClone(Option_t *opt) const
644{
645 TString o(opt);
646
647 TCanvas *c = NULL;
648
649 Int_t scale1 = o.Index("scale=1", TString::kIgnoreCase);
650 Int_t scalemax = o.Index("scale=max", TString::kIgnoreCase);
651 Int_t nonew = o.Index("nonew", TString::kIgnoreCase);
652
653 if (o.BeginsWith("scale=1", TString::kIgnoreCase))
654 scale1 = 0;
655 if (o.BeginsWith("scale=max", TString::kIgnoreCase))
656 scalemax = 0;
657 if (o.BeginsWith("nonew", TString::kIgnoreCase))
658 nonew = 0;
659
660 if (nonew>=0)
661 {
662 c = MH::MakeDefCanvas(this);
663
664 //
665 // This is necessary to get the expected bahviour of DrawClone
666 //
667 gROOT->SetSelectedPad(NULL);
668
669 o.Remove(nonew, 5);
670 }
671 if (scale1>=0)
672 o.Remove(scale1, 7);
673 if (scalemax>=0)
674 o.Remove(scalemax, 9);
675
676 const Int_t sstyle = gStyle->GetOptStat();
677 gStyle->SetOptStat(0);
678
679 //
680 // if the keymapping is used create a legend to identify the histograms
681 //
682 TLegend *leg = NULL;
683 if (fMapIdx->GetSize()>0)
684 {
685 leg = new TLegend(0.85, 0.80, 0.99, 0.99);
686 leg->SetBit(kCanDelete);
687 }
688
689 TIter Next(fArray);
690 MH *hist = (MH*)Next();
691
692 Int_t idx=0;
693 Double_t max=0;
694 Double_t min=0;
695
696 TH1 *h1=NULL;
697
698 //
699 // If the array has at least one entry:
700 // - find the starting boundaries
701 // - draw it and set its line color
702 //
703 if (hist)
704 {
705 if ((h1 = hist->GetHistByName(o)))
706 {
707 h1 = (TH1*)h1->DrawCopy();
708
709 if (scale1>=0)
710 h1->Scale(1./h1->Integral());
711 if (scalemax>=0)
712 h1->Scale(1./h1->GetMaximum());
713
714 h1->SetMarkerColor(idx);
715 h1->SetLineColor(idx+2);
716 h1->SetFillStyle(4000);
717 max = h1->GetMaximum();
718 min = h1->GetMinimum();
719
720 AddLegendEntry(leg, h1, idx++);
721 }
722 }
723
724 //
725 // For all following histograms:
726 // - update the boundaries
727 // - draw it and set its line color
728 //
729 while ((hist=(MH*)Next()))
730 {
731 TH1 *h=NULL;
732
733 if (!(h = hist->GetHistByName(o)))
734 continue;
735
736 h = (TH1*)h->DrawCopy("same");
737
738 if (scale1>=0)
739 h->Scale(1./h->Integral());
740 if (scalemax>=0)
741 h->Scale(1./h->GetMaximum());
742
743 h->SetMarkerColor(idx);
744 h->SetLineColor(idx+2);
745 h->SetFillStyle(4000); // transperent (why is this necessary?)
746 if (max<h->GetMaximum())
747 max = h->GetMaximum();
748 if (min>h->GetMinimum())
749 min = h->GetMinimum();
750
751 AddLegendEntry(leg, h, idx++);
752 }
753
754 //
755 // Now update the drawing region so that everything is displayed
756 //
757 if (h1)
758 {
759 h1->SetMinimum(min>0 ? min*0.95 : min*1.05);
760 h1->SetMaximum(max>0 ? max*1.05 : max*0.95);
761 }
762
763 if (leg)
764 leg->Draw();
765
766 gPad->Modified();
767 gPad->Update();
768
769 gStyle->SetOptStat(sstyle);
770
771 return c;
772}
Note: See TracBrowser for help on using the repository browser.