source: trunk/Mars/mhbase/MBinning.cc@ 10107

Last change on this file since 10107 was 9851, checked in by tbretz, 14 years ago
Changed MH::SetBinning and similar functions to take references instead of pointers as arguments. For convenience wrappers for the old style functions are provided.
File size: 19.1 KB
Line 
1/* ======================================================================== *\
2! $Name: not supported by cvs2svn $:$Id: MBinning.cc,v 1.20 2009-03-01 21:48:14 tbretz Exp $
3! --------------------------------------------------------------------------
4!
5! *
6! * This file is part of MARS, the MAGIC Analysis and Reconstruction
7! * Software. It is distributed to you in the hope that it can be a useful
8! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
9! * It is distributed WITHOUT ANY WARRANTY.
10! *
11! * Permission to use, copy, modify and distribute this software and its
12! * documentation for any purpose is hereby granted without fee,
13! * provided that the above copyright notice appear in all copies and
14! * that both that copyright notice and this permission notice appear
15! * in supporting documentation. It is provided "as is" without express
16! * or implied warranty.
17! *
18!
19!
20! Author(s): Thomas Bretz, 01/2002 <mailto:tbretz@astro.uni-wuerzburg.de>
21!
22! Copyright: MAGIC Software Development, 2000-2004
23!
24!
25\* ======================================================================== */
26
27//////////////////////////////////////////////////////////////////////////////
28//
29// MBinning
30//
31// This is a MParCOntainer storing a binning for a histogram. Doing this
32// you are able to distribute a single binning to several histograms
33// in your parameter list.
34//
35// In some classes the title of the container is used to set the
36// axis-title of the corresponding axis in your histogram.
37//
38// For all the features supported see the function descriptions in
39// MBinning and MH
40//
41//////////////////////////////////////////////////////////////////////////////
42#include "MBinning.h"
43
44#include <ctype.h> // tolower
45#include <fstream>
46
47#include <TH1.h> // InheritsFrom
48#include <TMath.h>
49
50#include "MLog.h"
51#include "MLogManip.h"
52
53#include "MParList.h"
54
55#include "MH.h"
56
57ClassImp(MBinning);
58
59using namespace std;
60
61const TString MBinning::gsDefName = "MBinning";
62const TString MBinning::gsDefTitle = "Container describing the binning of an axis";
63
64// --------------------------------------------------------------------------
65//
66// Default Constructor. It sets name and title only. Typically you won't
67// need to change this.
68//
69MBinning::MBinning(const char *name, const char *title)
70{
71 //
72 // set the name and title of this object
73 //
74 fName = name ? name : gsDefName.Data();
75 fTitle = title ? title : gsDefTitle.Data();
76
77 SetEdges(10, 0, 1);
78 fType = kIsDefault;
79}
80
81// --------------------------------------------------------------------------
82//
83// Copy Constructor. If necessary give also name and title.
84//
85MBinning::MBinning(const MBinning &bins, const char *name, const char *title)
86{
87 fName = name ? name : gsDefName.Data();
88 fTitle = title ? title : gsDefTitle.Data();
89
90 SetEdges(bins);
91}
92
93// --------------------------------------------------------------------------
94//
95// Instantiate MBinning with nbins number of bins between lo (lower edge)
96// and hi (upper edge), name name and title title.
97//
98MBinning::MBinning(Int_t nbins, Axis_t lo, Axis_t hi, const char *name, const char *opt, const char *title)
99{
100 fName = name ? name : gsDefName.Data();
101 fTitle = title ? title : gsDefTitle.Data();
102
103 SetEdges(nbins, lo, hi, opt);
104}
105
106// --------------------------------------------------------------------------
107//
108// Initialize Binning from an axis of a TH1. If no title given,
109// a title combined from the axis titles and the TH1 title is
110// used.
111//
112MBinning::MBinning(const TH1 &h, const Char_t axis, const char *name, const char *title)
113{
114 fName = name ? name : gsDefName.Data();
115 fTitle = title ? Form("%s;%s;%s;%s", h.GetTitle(),
116 h.GetXaxis()->GetTitle(),
117 h.GetYaxis()->GetTitle(),
118 h.GetZaxis()->GetTitle()) : gsDefTitle.Data();
119
120 SetEdges(h, axis);
121}
122
123// --------------------------------------------------------------------------
124//
125// Initialize Binning from TAxis.
126//
127MBinning::MBinning(const TAxis &axis, const char *name, const char *title)
128{
129 fName = name ? name : gsDefName.Data();
130 fTitle = title ? title : gsDefTitle.Data();
131
132 SetEdges(axis);
133}
134
135// --------------------------------------------------------------------------
136//
137// Initialize Binning from TArrayD.
138//
139MBinning::MBinning(const TArrayD &axis, const char *name, const char *title)
140{
141 fName = name ? name : gsDefName.Data();
142 fTitle = title ? title : gsDefTitle.Data();
143
144 SetEdges(axis);
145}
146
147// --------------------------------------------------------------------------
148//
149// Search in the parameter list for the binning with name "name". If found,
150// set the edges and title accordingly. Default is name of object.
151// return kTRUE if object found, kFALSE otherwise.
152//
153Bool_t MBinning::SetEdges(const MParList &list, const char *name)
154{
155 MBinning *bins = (MBinning*)list.FindObject(name ? name : fName.Data(), "MBinning");
156 if (!bins)
157 return kFALSE;
158
159 SetEdges(*bins);
160 return kTRUE;
161}
162
163// --------------------------------------------------------------------------
164//
165// Setup the edges stored in MBinning from the TAxis axe
166//
167void MBinning::SetEdges(const TAxis &axe)
168{
169 const TArrayD &arr = *axe.GetXbins();
170 if (arr.GetSize()>0)
171 {
172 SetEdges(arr);
173 return;
174 }
175
176 SetEdges(axe.GetNbins(), axe.GetXmin(), axe.GetXmax());
177}
178
179// --------------------------------------------------------------------------
180//
181// Add a new upper edge to the edges stored in MBinning. The new upper
182// edge must be greater than the current greatest. Using this you can
183// enhance a histogram bin-by-bin, eg:
184// TH1F h("", "", 2, 0, 1);
185// MBinning b;
186// b.SetEdges(h);
187// b.AddEdge(2);
188// b.Apply(h);
189// b.AddEdge(3);
190// b.Apply(h);
191// [...]
192//
193void MBinning::AddEdge(Axis_t up)
194{
195 const UInt_t n = fEdges.GetSize();
196
197 if (up<=fEdges[n-1])
198 {
199 *fLog << warn << dbginf << "WARNING - New upper edge not greater than old upper edge... ignored." << endl;
200 return;
201 }
202
203 fEdges.Set(n+1);
204 fEdges[n] = up;
205
206 fType = kIsUserArray;
207}
208
209// --------------------------------------------------------------------------
210//
211// Removes the first edge
212//
213void MBinning::RemoveFirstEdge()
214{
215 const Int_t n = fEdges.GetSize();
216 for (int i=0; i<n-1; i++)
217 fEdges[i] = fEdges[i+1];
218 fEdges.Set(n-1);
219}
220
221// --------------------------------------------------------------------------
222//
223// Removes the last edge
224//
225void MBinning::RemoveLastEdge()
226{
227 fEdges.Set(fEdges.GetSize()-1);
228}
229
230// --------------------------------------------------------------------------
231//
232// Set the edges in MBinning from a histogram-axis. Which axis is
233// specified by axis ('x', 'y', 'z')
234//
235void MBinning::SetEdges(const TH1 &h, const Char_t axis)
236{
237 switch (tolower(axis))
238 {
239 case 'x':
240 SetEdges(*h.GetXaxis());
241 return;
242 case 'y':
243 SetEdges(*h.GetYaxis());
244 return;
245 case 'z':
246 SetEdges(*h.GetZaxis());
247 return;
248 default:
249 *fLog << warn << "MBinning::SetEdges: Axis '" << axis << "' unknown... using x." << endl;
250 SetEdges(*h.GetXaxis());
251 }
252}
253
254// --------------------------------------------------------------------------
255//
256// Specify the number of bins <nbins> (not the number of edges), the
257// lowest <lo> and highest <up> Edge (of your histogram)
258//
259void MBinning::SetEdgesLin(Int_t nbins, Axis_t lo, Axis_t up)
260{
261 if (nbins<=0)
262 {
263 *fLog << warn << "WARNING - Number of bins cannot be <= 0... reset to 1." << endl;
264 nbins = 1;
265 }
266
267 if (up<lo)
268 {
269 *fLog << warn << "WARNING - Upper edge must be greater than lower edge... exchanging." << endl;
270
271 const Axis_t dummy(lo);
272 lo = up;
273 up = dummy;
274 }
275
276 const Double_t binsize = nbins<=0 ? 0 : (up-lo)/nbins;
277 fEdges.Set(nbins+1);
278 for (int i=0; i<=nbins; i++)
279 fEdges[i] = binsize*i + lo;
280
281 fType = kIsLinear;
282}
283
284// --------------------------------------------------------------------------
285//
286// Set edged from text. With the following structure:
287//
288// n lo hi [type [title]]
289//
290// n: number of bins
291// lo: lowest edge
292// hi: highest edge
293// type: "lin" <default>, "log", "cos", "asin" (without quotationmarks)
294// title: Whatever the title might be
295//
296// For example:
297// SetEdgesRaw("12 0 1 lin This is the title");
298//
299Bool_t MBinning::SetEdgesRaw(const char *txt)
300{
301 Int_t nbins = 0;
302 Float_t loedge = 0;
303 Float_t upedge = 0;
304 Int_t len = 0;
305 if (3!=sscanf(txt, " %d %f %f %n", &nbins, &loedge, &upedge, &len))
306 {
307 *fLog << warn << GetDescriptor() << "::SetEdges: Not enough arguments... ignored." << endl;
308 return kFALSE;
309 }
310
311 if (loedge>=upedge)
312 {
313 *fLog << warn << GetDescriptor() << "::SetEdges: Lowest edge >= highest edge... ignored." << endl;
314 return kFALSE;
315 }
316
317 TString str(txt);
318 str.Remove(0, len);
319 str = str.Strip(TString::kBoth);
320
321 TString typ(str);
322 Ssiz_t pos = str.First(' ');
323 if (pos>=0)
324 {
325 typ = str(0, pos);
326 str.Remove(0, pos);
327 str = str.Strip(TString::kBoth);
328 if (typ!=(TString)"lin" && typ!=(TString)"log" && typ!=(TString)"cos" && typ!=(TString)"asin")
329 {
330 *fLog << warn << GetDescriptor() << "::SetEdges: Type " << typ << " unknown... ignored." << endl;
331 return kFALSE;
332 }
333 }
334
335 SetEdges(nbins, loedge, upedge, typ.Data());
336
337 if (!str.IsNull())
338 fTitle = str;
339
340 return kTRUE;
341}
342/*
343// --------------------------------------------------------------------------
344//
345// Set edged from text. With the following structure:
346//
347// n= lo= hi= type= title="my title"
348//
349// n: number of bins
350// lo: lowest edge
351// hi: highest edge
352// type: "lin" <default>, "log", "cos" (without quotationmarks)
353// title: Whatever the title might be
354//
355// For example:
356// SetEdgesRaw("12 0 1 lin This is the title");
357//
358Bool_t MBinning::SetEdgesRaw(const char *txt)
359{
360 Int_t nbins = 0;
361 Float_t loedge = 0;
362 Float_t upedge = 0;
363 Int_t len = 0;
364 if (3!=sscanf(txt, " %d %f %f %n", &nbins, &loedge, &upedge, &len))
365 {
366 *fLog << warn << GetDescriptor() << "::SetEdges: Not enough arguments... ignored." << endl;
367 return kFALSE;
368 }
369
370 if (loedge>=upedge)
371 {
372 *fLog << warn << GetDescriptor() << "::SetEdges: Lowest edge >= highest edge... ignored." << endl;
373 return kFALSE;
374 }
375
376 TString str(txt);
377 str.Remove(0, len);
378 str = str.Strip(TString::kBoth);
379
380 TString typ;
381 Ssiz_t pos = str.First(' ');
382 if (pos>=0)
383 {
384 typ = str(0, pos);
385 if (typ!=(TString)"lin" && typ!=(TString)"log" && typ!=(TString)"cos")
386 {
387 *fLog << warn << GetDescriptor() << "::SetEdges: Type " << typ << " unknown... ignored." << endl;
388 return kFALSE;
389 }
390 }
391
392 SetEdges(nbins, loedge, upedge, typ.Data());
393
394 str = str.Strip(TString::kBoth);
395
396 if (!str.IsNull())
397 fTitle = str;
398
399 return kTRUE;
400}
401*/
402// --------------------------------------------------------------------------
403//
404// Calls SetEdgesLog if opt contains "log"
405// Calls SetEdgesCos if opt contains "cos"
406// Calls SetEdges in all other cases
407//
408void MBinning::SetEdges(const Int_t nbins, const Axis_t lo, Axis_t up, const char *opt)
409{
410 const TString o(opt);
411 if (o.Contains("log", TString::kIgnoreCase))
412 {
413 SetEdgesLog(nbins, lo, up);
414 return;
415 }
416 if (o.Contains("asin", TString::kIgnoreCase))
417 {
418 SetEdgesASin(nbins, lo, up);
419 return;
420 }
421 if (o.Contains("cos", TString::kIgnoreCase))
422 {
423 SetEdgesCos(nbins, lo, up);
424 return;
425 }
426 SetEdges(nbins, lo, up);
427}
428
429// --------------------------------------------------------------------------
430//
431// Specify the number of bins <nbins> (not the number of edges), the
432// lowest <lo> and highest <up> Edge (of your histogram)
433//
434void MBinning::SetEdgesLog(Int_t nbins, Axis_t lo, Axis_t up)
435{
436 // if (lo==0) ...
437 if (nbins<=0)
438 {
439 *fLog << warn << "WARNING - Number of bins cannot be <= 0... reset to 1." << endl;
440 nbins = 1;
441 }
442
443 if (up<lo)
444 {
445 *fLog << warn << "WARNING - Upper edge must be greater than lower edge... exchanging." << endl;
446
447 const Axis_t dummy(lo);
448 lo = up;
449 up = dummy;
450 }
451
452 const Double_t binsize = log10(up/lo)/nbins;
453 fEdges.Set(nbins+1);
454 for (int i=0; i<=nbins; i++)
455 fEdges[i] = pow(10, binsize*i) * lo;
456
457 fType = kIsLogarithmic;
458}
459
460// --------------------------------------------------------------------------
461//
462// Specify the number of bins <nbins> (not the number of edges), the
463// lowest [deg] <lo> and highest [deg] <up> Edge (of your histogram)
464//
465void MBinning::SetEdgesCos(Int_t nbins, Axis_t lo, Axis_t up)
466{
467 if (nbins<=0)
468 {
469 *fLog << warn << "WARNING - Number of bins cannot be <= 0... reset to 1." << endl;
470 nbins = 1;
471 }
472
473 if (up<lo)
474 {
475 *fLog << warn << "WARNING - Upper edge must be greater than lower edge... exchanging." << endl;
476
477 const Axis_t dummy(lo);
478 lo = up;
479 up = dummy;
480 }
481
482 // if (lo==0) ...
483 const Axis_t ld = lo/kRad2Deg;
484 const Axis_t ud = up/kRad2Deg;
485
486 const Double_t cld = ld<0 ? cos(ld)-1 : 1-cos(ld);
487 const Double_t cud = ud<0 ? cos(ud)-1 : 1-cos(ud);
488
489 SetEdgesASin(nbins, cld, cud);
490}
491
492// --------------------------------------------------------------------------
493//
494// Specify the number of bins <nbins> (not the number of edges), the
495// lowest [deg] <lo> and highest [deg] <up> Edge (of your histogram)
496//
497void MBinning::SetEdgesASin(Int_t nbins, Axis_t lo, Axis_t up)
498{
499 if (nbins<=0)
500 {
501 *fLog << warn << "WARNING - Number of bins cannot be <= 0... reset to 1." << endl;
502 nbins = 1;
503 }
504
505 if (up<lo)
506 {
507 *fLog << warn << "WARNING - Upper edge must be greater than lower edge... exchanging." << endl;
508
509 const Axis_t dummy(lo);
510 lo = up;
511 up = dummy;
512 }
513
514 const Double_t binsize = nbins<=0 ? 0 : (up-lo)/nbins;
515 fEdges.Set(nbins+1);
516 for (int i=0; i<=nbins; i++)
517 {
518 const Double_t a = binsize*i + lo;
519 fEdges[i] = a<0 ? -acos(1+a)*kRad2Deg : acos(1-a)*kRad2Deg;
520 }
521
522 fType = kIsCosinic;
523}
524
525// --------------------------------------------------------------------------
526//
527// Apply this binning to the given histogram.
528// (By definition this works only for 1D-histograms. For 2D- and 3D-
529// histograms use MH::SetBinning directly)
530//
531void MBinning::Apply(TH1 &h) const
532{
533 if (h.InheritsFrom("TH2") || h.InheritsFrom("TH3"))
534 {
535 *fLog << warn << "MBinning::Apply: '" << h.GetName() << "' is not a basic TH1 object... no binning applied." << endl;
536 return;
537 }
538
539 MH::SetBinning(h, *this);
540}
541
542// --------------------------------------------------------------------------
543//
544// Print binning.
545//
546void MBinning::Print(Option_t *o) const
547{
548 *fLog << all;
549 *fLog << GetDescriptor() << ": nbins=" << GetNumBins() << " [";
550 *fLog << GetEdgeLo() << ", " << GetEdgeHi() << "] <";
551 switch (fType)
552 {
553 case kIsDefault: *fLog << "default"; break;
554 case kIsLinear: *fLog << "linear"; break;
555 case kIsLogarithmic: *fLog << "logarithmic"; break;
556 case kIsCosinic: *fLog << "consinic"; break;
557 case kIsUserArray: *fLog << "user-array"; break;
558 }
559 *fLog << ">";
560
561 if (fTitle!=gsDefTitle)
562 *fLog << " title=" << fTitle;
563
564 *fLog << endl;
565}
566
567// --------------------------------------------------------------------------
568//
569// Implementation of SavePrimitive. Used to write the call to a constructor
570// to a macro. In the original root implementation it is used to write
571// gui elements to a macro-file.
572//
573void MBinning::StreamPrimitive(ostream &out) const
574{
575 out << " MBinning " << GetUniqueName();
576 if (fName!=gsDefName || fTitle!=gsDefTitle)
577 {
578 out << "(\"" << fName << "\"";
579 if (fTitle!=gsDefTitle)
580 out << ", \"" << fTitle << "\"";
581 out <<")";
582 }
583 out << ";" << endl;
584
585 if (IsDefault())
586 return;
587
588 if (IsLinear() || IsLogarithmic() || IsCosinic())
589 {
590 out << " " << GetUniqueName() << ".SetEdges";
591 if (IsLogarithmic())
592 out << "Log";
593 if (IsCosinic())
594 out << "Cos";
595 out << "(" << GetNumBins() << ", " << GetEdgeLo() << ", " << GetEdgeHi() << ");" << endl;
596 return;
597 }
598
599 out << " {" << endl;
600 out << " TArrayD dummy;" << endl;
601 for (int i=0; i<GetNumEdges(); i++)
602 out << " dummy[" << i << "]=" << GetEdges()[i] << ";" << endl;
603 out << " " << GetUniqueName() << ".SetEdges(dummy);" << endl;
604 out << " }" << endl;
605}
606
607// --------------------------------------------------------------------------
608//
609// Allows reading a binning from resource files. The structure is as follows
610//
611Int_t MBinning::ReadEnv(const TEnv &env, TString prefix, Bool_t print)
612{
613 Bool_t rc = kFALSE;
614
615 UInt_t nbins = GetNumBins();
616 Float_t edgelo = GetEdgeLo();
617 Float_t edgehi = GetEdgeHi();
618 TString type;
619 if (IsEnvDefined(env, prefix, "NumBins", print))
620 {
621 nbins = GetEnvValue(env, prefix, "NumBins", GetNumBins());
622 rc = kTRUE;
623 }
624 if (IsEnvDefined(env, prefix, "EdgeLo", print))
625 {
626 edgelo = GetEnvValue(env, prefix, "EdgeLo", GetEdgeLo());
627 rc = kTRUE;
628 }
629 if (IsEnvDefined(env, prefix, "EdgeHi", print))
630 {
631 edgehi = GetEnvValue(env, prefix, "EdgeHi", GetEdgeHi());
632 rc = kTRUE;
633 }
634 if (rc==kTRUE && (type==kIsUserArray || type==kIsDefault))
635 type = kIsLinear;
636
637 if (IsEnvDefined(env, prefix, "Type", print))
638 {
639 type = GetEnvValue(env, prefix, "Type", "lin");
640 if (type!=(TString)"lin" && type!=(TString)"log" && type!=(TString)"cos" && type!=(TString)"acos")
641 {
642 *fLog << warn << GetDescriptor() << "::ReadEnv - WARNING: Type is not lin, log nor cos... assuming lin." << endl;
643 type = "lin";
644 }
645 rc = kTRUE;
646 }
647 if (IsEnvDefined(env, prefix, "Edges", print))
648 {
649 if (rc==kTRUE)
650 *fLog << warn << GetDescriptor() << "::ReadEnv - WARNING: 'Edges' found... ignoring any 'NumBins', 'EdgeLo' and 'EdgeHi'" << endl;
651
652 const TString etype = GetEnvValue(env, prefix, "Edges", "");
653 //type = kIsUserArray;
654 /* MISSING */
655 rc = kTRUE;
656 *fLog << err << " SORRY USER ARRAY NOT YET IMPLEMENTED" << endl;
657 return kERROR;
658 }
659
660 const Bool_t raw = IsEnvDefined(env, prefix, "Raw", print);
661 //const Bool_t fullbins = IsEnvDefined(env, prefix, "Binning", print);
662 if (!raw && /*!fullbins &&*/ rc==kTRUE)
663 SetEdges(nbins, edgelo, edgehi, type.Data());
664
665 if (rc==kTRUE)
666 *fLog << warn << GetDescriptor() << "::ReadEnv - WARNING: 'Binning' found... ignoring any 'NumBins', 'EdgeLo', 'EdgeHi' and 'Edges'" << endl;
667
668 if (IsEnvDefined(env, prefix, "Title", print))
669 {
670 fTitle = GetEnvValue(env, prefix, "Title", gsDefTitle.Data());
671 rc = kTRUE;
672 }
673
674 if (raw)
675 {
676 const TString txt = GetEnvValue(env, prefix, "Raw", "");
677 if (!SetEdgesRaw(txt.Data()))
678 return kERROR;
679 }
680/*
681 if (fullbins)
682 {
683 TString txt = GetEnvValue(env, prefix, "Binning", "");
684 SetEdgesRaw(txt.Data());
685 }
686 */
687
688 return rc;
689}
Note: See TracBrowser for help on using the repository browser.