Logo ROOT   6.08/07
Reference Guide
TH1Merger.cxx
Go to the documentation of this file.
1 // Helper clas implementing some of the TH1 functionality
2 
3 #include "TH1Merger.h"
4 #include "TH1.h"
5 #include "TH2.h"
6 #include "TH3.h"
7 #include "TAxis.h"
8 #include "TError.h"
9 #include "THashList.h"
10 #include "TClass.h"
11 #include <iostream>
12 
13 
15  Bool_t hasLimits = h->GetXaxis()->GetXmin() < h->GetXaxis()->GetXmax();
16  if (h->GetDimension() > 1) hasLimits &= h->GetYaxis()->GetXmin() < h->GetYaxis()->GetXmax();
17  if (h->GetDimension() > 2) hasLimits &= h->GetZaxis()->GetXmin() < h->GetZaxis()->GetXmax();
18  return hasLimits;
19 }
20 
21 /// Function performing the actual merge
23 
24 
26 
27  if (gDebug) Info("Merge","Histogram Merge type is %d and new axis flag is %d",(int) type,(int) fNewAxisFlag);
28 
29  if (type == kNotCompatible) return kFALSE;
30 
31  if (type == kAllSameAxes)
32  return SameAxesMerge();
33 
34  if (type == kAllLabel)
35  return LabelMerge();
36 
37  if (type == kAllNoLimits)
38  return BufferMerge();
39 
40  // this is the mixed case - more complicated
41  if (type == kHasNewLimits) {
42  // we need to define some new axes
43  DefineNewAxes();
44  // we might need to merge some histogram using the buffer
45  Bool_t ret = BufferMerge();
46  // if ret is true the merge is completed and we can exit
47  if (ret) return kTRUE;
48  // in the other cases then we merge using FindBin
49  return DifferentAxesMerge();
50  }
51  Error("TH1Merger","Unknown type of Merge for histogram %s",fH0->GetName());
52  return kFALSE;
53 }
54 
55 /**
56  Examine the list of histograms to find out which type of Merge we need to do
57  Pass the input list containing the histogram to merge and h0 which is the initial histogram
58  on which all the histogram of the list will be merged
59  This are the possible cases:
60  - 1. All histogram have the same axis (allSameLimits = true)
61  - 2. Histogram have different axis but compatible (allSameLimits = false) and sameLimitsX,Y,Z specifies which axis
62  has different limits
63  - 3. Histogram do not have limits (so the Buffer is used) allHaveLimits = false
64  - 3b. One histogram has limits the other not : allHaveLimits = false AND initialLimitsFound = true
65  - 4. Histogram Have labels = allHaveLabels = true
66 
67 
68 */
70 
71 
72 
73  Bool_t initialLimitsFound = kFALSE;
74  Bool_t allHaveLabels = kTRUE; // assume all histo have labels and check later
75  Bool_t allHaveLimits = kTRUE;
76  Bool_t allSameLimits = kTRUE;
77  Bool_t sameLimitsX = kTRUE;
78  Bool_t sameLimitsY = kTRUE;
79  Bool_t sameLimitsZ = kTRUE;
80  Bool_t foundLabelHist = kFALSE;
81 
82  // TAxis newXAxis;
83  // TAxis newYAxis;
84  // TAxis newZAxis;
85 
86  TIter next(&fInputList);
87  TH1 * h = fH0; // start with fH0
88 
89  int dimension = fH0->GetDimension();
90 
91  // start looping on the histograms
92 
93  do {
94 
95  // check first histogram compatibility
96  if (h != fH0) {
97  if (h->GetDimension() != dimension) {
98  Error("Merge", "Cannot merge histogram - dimensions are different\n "
99  "%s has dim=%d and %s has dim=%d",fH0->GetName(),dimension,h->GetName(),h->GetDimension());
100  return kNotCompatible;
101  }
102  }
103 
104 
105  // do not skip anymore empty histograms
106  // since are used to set the limits
107  Bool_t hasLimits = TH1Merger::AxesHaveLimits(h);
108  allHaveLimits = allHaveLimits && hasLimits;
109  allSameLimits &= allHaveLimits;
110 
111 
112  if (hasLimits) {
113  h->BufferEmpty();
114 
115 // // this is done in case the first histograms are empty and
116 // // the histogram have different limits
117 // #ifdef LATER
118 // if (firstHistWithLimits ) {
119 // // set axis limits in the case the first histogram did not have limits
120 // if (h != this && !SameLimitsAndNBins( fXaxis, *h->GetXaxis()) ) {
121 // if (h->GetXaxis()->GetXbins()->GetSize() != 0) fXaxis.Set(h->GetXaxis()->GetNbins(), h->GetXaxis()->GetXbins()->GetArray());
122 // else fXaxis.Set(h->GetXaxis()->GetNbins(), h->GetXaxis()->GetXmin(), h->GetXaxis()->GetXmax());
123 // }
124 // firstHistWithLimits = kFALSE;
125 // }
126 // #endif
127 
128  // this is executed the first time an histogram with limits is found
129  // to set some initial values on the new axis
130  if (!initialLimitsFound) {
131  initialLimitsFound = kTRUE;
132  if (h->GetXaxis()->GetXbins()->GetSize() != 0)
133  fNewXAxis.Set(h->GetXaxis()->GetNbins(), h->GetXaxis()->GetXbins()->GetArray());
134  else
135  fNewXAxis.Set(h->GetXaxis()->GetNbins(), h->GetXaxis()->GetXmin(), h->GetXaxis()->GetXmax());
136  if (dimension > 1) {
137  if (h->GetYaxis()->GetXbins()->GetSize() != 0)
138  fNewYAxis.Set(h->GetYaxis()->GetNbins(), h->GetYaxis()->GetXbins()->GetArray());
139  else
140  fNewYAxis.Set(h->GetYaxis()->GetNbins(), h->GetYaxis()->GetXmin(), h->GetYaxis()->GetXmax());
141  }
142  if (dimension > 2) {
143  if (h->GetZaxis()->GetXbins()->GetSize() != 0)
144  fNewZAxis.Set(h->GetZaxis()->GetNbins(), h->GetZaxis()->GetXbins()->GetArray());
145  else
146  fNewZAxis.Set(h->GetZaxis()->GetNbins(), h->GetZaxis()->GetXmin(), h->GetZaxis()->GetXmax());
147 
148  }
149  }
150  else {
151  // check first if histograms have same bins in X
152  if (!TH1::SameLimitsAndNBins(fNewXAxis, *(h->GetXaxis())) ) {
153  sameLimitsX = kFALSE;
154  // recompute the limits in this case the optimal limits
155  // The condition to works is that the histogram have same bin with
156  // and one common bin edge
158  Error("Merge", "Cannot merge histograms - limits are inconsistent:\n "
159  "first: %s (%d, %f, %f), second: %s (%d, %f, %f)", fH0->GetName(),
161  h->GetName(),h->GetXaxis()->GetNbins(), h->GetXaxis()->GetXmin(),
162  h->GetXaxis()->GetXmax());
163  return kNotCompatible;
164  }
165  }
166  // check first if histograms have same bins in Y
167  if (dimension > 1 && !TH1::SameLimitsAndNBins(fNewYAxis, *(h->GetYaxis()))) {
168  sameLimitsY = kFALSE;
169  // recompute in this case the optimal limits
170  // The condition to works is that the histogram have same bin with
171  // and one common bin edge
173  Error("Merge", "Cannot merge histograms - limits are inconsistent:\n "
174  "first: %s (%d, %f, %f), second: %s (%d, %f, %f)", fH0->GetName(),
176  h->GetName(), h->GetYaxis()->GetNbins(), h->GetYaxis()->GetXmin(),
177  h->GetYaxis()->GetXmax());
178  return kNotCompatible;
179  }
180  }
181  if(dimension > 2 && !fH0->SameLimitsAndNBins(fNewZAxis, *(h->GetZaxis()))) {
182  sameLimitsZ = kFALSE;
184  Error("Merge", "Cannot merge histograms - limits are inconsistent:\n "
185  "first: %s (%d, %f, %f), second: %s (%d, %f, %f)", fH0->GetName(),
187  h->GetName(),h->GetZaxis()->GetNbins(), h->GetZaxis()->GetXmin(),
188  h->GetZaxis()->GetXmax());
189  return kNotCompatible;
190  }
191  }
192  allSameLimits = sameLimitsX && sameLimitsY && sameLimitsZ;
193 
194 
195  }
196  }
197  Bool_t histoIsEmpty = h->IsEmpty();
198  // std::cout << "considering histo " << h->GetName() << " labels - " << allHaveLabels << " is empty "
199  // << histoIsEmpty << std::endl;
200 
201  // if histogram is empty it does not matter if it has label or not
202  if (allHaveLabels && !histoIsEmpty) {
203  if (histoIsEmpty) continue;
204  THashList* hlabels=h->GetXaxis()->GetLabels();
205  Bool_t haveOneLabel = (hlabels != nullptr);
206  // do here to print message only one time
207  if (foundLabelHist && allHaveLabels && !haveOneLabel) {
208  Warning("Merge","Not all histograms have labels. I will ignore labels,"
209  " falling back to bin numbering mode.");
210  }
211 
212  allHaveLabels &= (haveOneLabel);
213  // for the error message
214  if (haveOneLabel) foundLabelHist = kTRUE;
215 
216  if (foundLabelHist && gDebug)
217  Info("TH1Merger::ExamineHistogram","Histogram %s has labels",h->GetName() );
218 
219  // If histograms have labels but CanExtendAllAxes() is false
220  // use bin center mode
221  if (allHaveLabels && !fH0->CanExtendAllAxes()) {
222  // special case for this histogram when is empty
223  // and axis cannot be extended (because it is the default)
224  if ( fH0->IsEmpty() ) {
225  if (gDebug)
226  Info("TH1Merger::ExamineHistogram","Histogram %s to be merged is empty and we are merging with %s that has labels. Force the axis to be extended",fH0->GetName(),h->GetName());
227  UInt_t bitMaskX = fH0->GetXaxis()->CanBeAlphanumeric() & TH1::kXaxis;
228  UInt_t bitMaskY = (fH0->GetYaxis()->CanBeAlphanumeric() << 1 ) & TH1::kYaxis;
229  UInt_t bitMaskZ = (fH0->GetZaxis()->CanBeAlphanumeric() << 2 ) & TH1::kZaxis;
230  fH0->SetCanExtend(bitMaskX | bitMaskY | bitMaskZ );
231  }
232  if (!fH0->CanExtendAllAxes()) {
233  if (gDebug)
234  Info("TH1Merger::ExamineHistogram","Histogram %s to be merged has label but axis cannot be extended - using bin numeric mode to merge. Call TH1::SetExtendAllAxes() if want to merge using label mode",fH0->GetName());
235  allHaveLabels = kFALSE;
236  }
237  }
238  // I could add a check if histogram contains bins without a label
239  // and with non-zero bin content
240  // Do we want to support this ???
241  // only in case the !h->CanExtendAllAxes()
242  if (allHaveLabels && !h->CanExtendAllAxes()) {
243  // count number of bins with non-null content
244  Int_t non_zero_bins = 0;
245  Int_t nbins = h->GetXaxis()->GetNbins();
246  if (nbins > hlabels->GetEntries() ) {
247  for (Int_t i = 1; i <= nbins; i++) {
248  if (h->RetrieveBinContent(i) != 0 || (fH0->fSumw2.fN && h->GetBinError(i) != 0) ) {
249  non_zero_bins++;
250  }
251  }
252  if (non_zero_bins > hlabels->GetEntries() ) {
253  Warning("TH1Merger::ExamineHistograms","Histogram %s contains non-empty bins without labels - falling back to bin numbering mode",h->GetName() );
254  allHaveLabels = kFALSE;
255  }
256  }
257  }
258  }
259  if (gDebug)
260  Info("TH1Merger::ExamineHistogram","Examine histogram %s - labels %d - same limits %d - axis found %d",h->GetName(),allHaveLabels,allSameLimits,initialLimitsFound );
261 
262  } while ( ( h = dynamic_cast<TH1*> ( next() ) ) != NULL );
263 
264  if (!h && (*next) ) {
265  Error("Merge","Attempt to merge object of class: %s to a %s",
266  (*next)->ClassName(),fH0->ClassName());
267  return kNotCompatible;
268  }
269 
270  // return the type of merge
271  if (allHaveLabels) return kAllLabel;
272  if (allSameLimits) return kAllSameAxes;
273  if (!initialLimitsFound) {
274  R__ASSERT(!allHaveLimits);
275  // case where no limits are found and the buffer is used
276  return kAllNoLimits;
277  }
278  // remaining case should be the mixed one. Some histogram have limits some not
279  fNewAxisFlag = 0;
280  if (!sameLimitsX) fNewAxisFlag |= TH1::kXaxis;
281  if (!sameLimitsY) fNewAxisFlag |= TH1::kYaxis;
282  if (!sameLimitsZ) fNewAxisFlag |= TH1::kZaxis;
283 
284  // we need to set the flag also in case this histogram has no limits
285  // we need to set explicitly the flag to re-define a new axis
287  if (dimension > 1 && fH0->GetYaxis()->GetXmin() >= fH0->GetYaxis()->GetXmax()) fNewAxisFlag |= TH1::kYaxis;
288  if (dimension > 2 && fH0->GetZaxis()->GetXmin() >= fH0->GetZaxis()->GetXmax()) fNewAxisFlag |= TH1::kZaxis;
289 
290 
291  return kHasNewLimits;
292 
293 }
294 
295 /**
296  Function to define new histogram axis when merging
297  It is call only in case of merging with different axis or with the
298  buffer (kHasNewLimits)
299 */
300 
302 
303  // first we need to create a copy of the histogram in case is not empty
304 
305  if (!fH0->IsEmpty() ) {
306  Bool_t mustCleanup = fH0->TestBit(kMustCleanup);
307  if (mustCleanup) fH0->ResetBit(kMustCleanup);
308  fHClone = (TH1*)fH0->IsA()->New();
309  fHClone->SetDirectory(0);
310  fH0->Copy(*fHClone);
311  if (mustCleanup) fH0->SetBit(kMustCleanup);
312  fH0->BufferEmpty(1); // To remove buffer.
313  fH0->Reset(); // BufferEmpty sets limits so we can't use it later.
314  fH0->SetEntries(0);
316 
317  }
318 
319  bool newLimitsX = (fNewAxisFlag & TH1::kXaxis);
320  bool newLimitsY = (fNewAxisFlag & TH1::kYaxis);
321  bool newLimitsZ = (fNewAxisFlag & TH1::kZaxis);
322  if (newLimitsX) {
323  fH0->fXaxis.SetRange(0,0);
324  if (fNewXAxis.GetXbins()->GetSize() != 0)
326  else
328  }
329  if (newLimitsY) {
330  fH0->fYaxis.SetRange(0,0);
331  if (fNewYAxis.GetXbins()->GetSize() != 0)
333  else
335  }
336  if (newLimitsZ) {
337  fH0->fZaxis.SetRange(0,0);
338  if (fNewZAxis.GetXbins()->GetSize() != 0)
340  else
342  }
343 
344  // we need to recompute fNcells and set the array size (as in TH1::SetBins)
345  fH0->fNcells = fH0->fXaxis.GetNbins()+2;
346  if (fH0->fDimension > 1) fH0->fNcells *= fH0->fYaxis.GetNbins()+2;
347  if (fH0->fDimension > 2) fH0->fNcells *= fH0->fZaxis.GetNbins()+2;
349  if (fH0->fSumw2.fN) fH0->fSumw2.Set(fH0->fNcells);
350  // set dummy Y and Z axis for lower dim histogras
351  if (fH0->fDimension < 3) fH0->fZaxis.Set(1,0,1);
352  if (fH0->fDimension < 2) fH0->fYaxis.Set(1,0,1);
353 
354  if (gDebug) {
355  if (newLimitsX) Info("DefineNewAxis","A new X axis has been defined Nbins=%d , [%f,%f]", fH0->fXaxis.GetNbins(),
356  fH0->fXaxis.GetXmin(), fH0->fXaxis.GetXmax() );
357  if (newLimitsY) Info("DefineNewAxis","A new Y axis has been defined Nbins=%d , [%f,%f]", fH0->fYaxis.GetNbins(),
358  fH0->fYaxis.GetXmin(), fH0->fYaxis.GetXmax() );
359  if (newLimitsZ) Info("DefineNewAxis","A new Z axis has been defined Nbins=%d , [%f,%f]", fH0->fZaxis.GetNbins(),
360  fH0->fZaxis.GetXmin(), fH0->fZaxis.GetXmax() );
361  }
362 
363  return;
364 
365 }
366 
368 
369  TIter next(&fInputList);
370  while (TH1* hist = (TH1*)next()) {
371  // support also case where some histogram have limits and some have the buffer
372  if ( !TH1Merger::AxesHaveLimits(hist) && hist->fBuffer ) {
373 
374  if (gDebug)
375  Info("TH1Merger::BufferMerge","Merging histogram %s into %s",hist->GetName(), fH0->GetName() );
376 
377 
378  // case of no limits
379  // Entries from buffers have to be filled one by one
380  // because FillN doesn't resize histograms.
381  Int_t nbentries = (Int_t)hist->fBuffer[0];
382  if (fH0->fDimension == 1) {
383  for (Int_t i = 0; i < nbentries; i++)
384  fH0->Fill(hist->fBuffer[2*i + 2], hist->fBuffer[2*i + 1]);
385  }
386  if (fH0->fDimension == 2) {
387  auto h2 = dynamic_cast<TH2*>(fH0);
388  R__ASSERT(h2);
389  for (Int_t i = 0; i < nbentries; i++)
390  h2->Fill(hist->fBuffer[3*i + 2], hist->fBuffer[3*i + 3],hist->fBuffer[3*i + 1] );
391  }
392  if (fH0->fDimension == 3) {
393  auto h3 = dynamic_cast<TH3*>(fH0);
394  R__ASSERT(h3);
395  for (Int_t i = 0; i < nbentries; i++)
396  h3->Fill(hist->fBuffer[4*i + 2], hist->fBuffer[4*i + 3],hist->fBuffer[4*i + 4], hist->fBuffer[4*i + 1] );
397  }
398  fInputList.Remove(hist);
399  }
400  }
401  // return true if the merge is completed
402  if (fInputList.GetSize() == 0) {
403  // all histo have been merged
404  return kTRUE;
405  }
406  // we need to reset the buffer in case of merging later on
407  // is this really needed ???
408  if (fH0->fBuffer) fH0->BufferEmpty(1);
409 
410  return kFALSE;
411 }
412 
414 
415 
416  Double_t stats[TH1::kNstat], totstats[TH1::kNstat];
417  for (Int_t i=0;i<TH1::kNstat;i++) {
418  totstats[i] = stats[i] = 0;
419  }
420  fH0->GetStats(totstats);
422 
423  TIter next(&fInputList);
424  while (TH1* hist=(TH1*)next()) {
425  // process only if the histogram has limits; otherwise it was processed before
426  // in the case of an existing buffer (see if statement just before)
427 
428  if (gDebug)
429  Info("TH1Merger::SameAxesMerge","Merging histogram %s into %s",hist->GetName(), fH0->GetName() );
430 
431  // skip empty histograms
432  if (hist->IsEmpty()) continue;
433 
434  // import statistics
435  hist->GetStats(stats);
436  for (Int_t i=0; i<TH1::kNstat; i++)
437  totstats[i] += stats[i];
438  nentries += hist->GetEntries();
439 
440  //Int_t nx = hist->GetXaxis()->GetNbins();
441  // loop on bins of the histogram and do the merge
442  for (Int_t ibin = 0; ibin < hist->fNcells; ibin++) {
443 
444  Double_t cu = hist->RetrieveBinContent(ibin);
445  Double_t e1sq = TMath::Abs(cu);
446  if (fH0->fSumw2.fN) e1sq= hist->GetBinErrorSqUnchecked(ibin);
447 
448  fH0->AddBinContent(ibin,cu);
449  if (fH0->fSumw2.fN) fH0->fSumw2.fArray[ibin] += e1sq;
450 
451  }
452  }
453  //copy merged stats
454  fH0->PutStats(totstats);
455  fH0->SetEntries(nentries);
456 
457  return kTRUE;
458 }
459 
460 
461 /**
462  Merged histogram when axis can be different.
463  Histograms are merged looking at bin center positions
464 
465  */
467 
468  Double_t stats[TH1::kNstat], totstats[TH1::kNstat];
469  for (Int_t i=0;i<TH1::kNstat;i++) {totstats[i] = stats[i] = 0;}
470  fH0->GetStats(totstats);
472 
473  TIter next(&fInputList);
474  while (TH1* hist=(TH1*)next()) {
475 
476  if (gDebug)
477  Info("TH1Merger::DifferentAxesMerge","Merging histogram %s into %s",hist->GetName(), fH0->GetName() );
478 
479  // skip empty histograms
480  if (hist->IsEmpty()) continue;
481 
482  // import statistics
483  hist->GetStats(stats);
484  for (Int_t i=0;i<TH1::kNstat;i++)
485  totstats[i] += stats[i];
486  nentries += hist->GetEntries();
487 
488  // loop on bins of the histogram and do the merge
489  for (Int_t ibin = 0; ibin < hist->fNcells; ibin++) {
490 
491  Double_t cu = hist->RetrieveBinContent(ibin);
492  Double_t e1sq = TMath::Abs(cu);
493  if (fH0->fSumw2.fN) e1sq= hist->GetBinErrorSqUnchecked(ibin);
494 
495  // if bin is empty we can skip it
496  if (cu == 0 && e1sq == 0) continue;
497 
498  Int_t binx,biny,binz;
499  hist->GetBinXYZ(ibin, binx, biny, binz);
500 
501  // case of underflow/overflows in the histogram being merged
502  if (binx <= 0 || binx >= hist->GetNbinsX() + 1) {
503  if (fH0->fXaxis.CanExtend() || ( hist->fXaxis.GetBinCenter(binx) > fH0->fXaxis.GetXmin() && hist->fXaxis.GetBinCenter(binx) < fH0->fXaxis.GetXmax()) ) {
504  Error("TH1Merger::DifferentAxesMerge", "Cannot merge histograms - the histograms %s can extend the X axis or have"
505  " different limits and underflows/overflows are present in the histogram %s.",fH0->GetName(),hist->GetName());
506  return kFALSE;
507  }
508  }
509  if (biny <= 0 || biny >= hist->GetNbinsY() + 1) {
510  if (fH0->fYaxis.CanExtend() || ( hist->fYaxis.GetBinCenter(biny) > fH0->fYaxis.GetXmin() && hist->fYaxis.GetBinCenter(biny) < fH0->fYaxis.GetXmax()) ) {
511  Error("TH1Merger::DifferentAxesMerge", "Cannot merge histograms - the histograms %s can extend the Y axis or have"
512  " different limits and underflows/overflows are present in the histogram %s.",fH0->GetName(),hist->GetName());
513  return kFALSE;
514  }
515  }
516  if (binz <= 0 || binz >= hist->GetNbinsZ() + 1) {
517  if (fH0->fZaxis.CanExtend() || ( hist->fZaxis.GetBinCenter(binz) > fH0->fZaxis.GetXmin() && hist->fXaxis.GetBinCenter(binz) < fH0->fZaxis.GetXmax()) ) {
518  Error("TH1Merger::DifferentAxesMerge", "Cannot merge histograms - the histograms %s can extend the Z axis or have"
519  " different limits and underflows/overflows are present in the histogram %s.",fH0->GetName(),hist->GetName());
520  return kFALSE;
521  }
522  }
523 
524  Int_t ix = 0;
525  Int_t iy = 0;
526  Int_t iz = 0;
527 
528  // we can extend eventually the axis if histogram is capable of doing it
529  // by using FindBin
530  ix = fH0->fXaxis.FindBin(hist->GetXaxis()->GetBinCenter(binx));
531  if (fH0->fDimension > 1)
532  iy = fH0->fYaxis.FindBin(hist->GetYaxis()->GetBinCenter(biny));
533  if (fH0->fDimension > 2)
534  iz = fH0->fZaxis.FindBin(hist->GetZaxis()->GetBinCenter(binz));
535 
536  Int_t ib = fH0->GetBin(ix,iy,iz);
537  if (ib < 0 || ib > fH0->fNcells) {
538  Fatal("TH1Merger::LabelMerge","Fatal error merging histogram %s - bin number is %d and array size is %d",
539  fH0->GetName(), ib,fH0->fNcells);
540  }
541 
542  fH0->AddBinContent(ib,cu);
543  if (fH0->fSumw2.fN) fH0->fSumw2.fArray[ib] += e1sq;
544  }
545  }
546  //copy merged stats
547  fH0->PutStats(totstats);
548  fH0->SetEntries(nentries);
549 
550  return kTRUE;
551 }
552 
553 
554 /**
555  Merge histograms with labels
556 */
558 
559 
560  Double_t stats[TH1::kNstat], totstats[TH1::kNstat];
561  for (Int_t i=0;i<TH1::kNstat;i++) {totstats[i] = stats[i] = 0;}
562  fH0->GetStats(totstats);
564 
565  TIter next(&fInputList);
566  while (TH1* hist=(TH1*)next()) {
567 
568  if (gDebug)
569  Info("TH1Merger::LabelMerge","Merging histogram %s into %s",hist->GetName(), fH0->GetName() );
570 
571  // skip empty histograms
572  if (hist->IsEmpty()) continue;
573 
574  // import statistics
575  hist->GetStats(stats);
576  for (Int_t i=0;i<TH1::kNstat;i++)
577  totstats[i] += stats[i];
578  nentries += hist->GetEntries();
579 
580  auto labelsX = hist->GetXaxis()->GetLabels();
581  auto labelsY = hist->GetYaxis()->GetLabels();
582  auto labelsZ = hist->GetZaxis()->GetLabels();
583  R__ASSERT(!( labelsX == nullptr && labelsY == nullptr && labelsZ == nullptr));
584 
585  // loop on bins of the histogram and do the merge
586  for (Int_t ibin = 0; ibin < hist->fNcells; ibin++) {
587 
588  Double_t cu = hist->RetrieveBinContent(ibin);
589  Double_t e1sq = cu;
590  if (fH0->fSumw2.fN) e1sq= hist->GetBinErrorSqUnchecked(ibin);
591 
592  // if bin is empty we can skip it
593  if (cu == 0 && e1sq == 0) continue;
594 
595  Int_t binx,biny,binz;
596  hist->GetBinXYZ(ibin, binx, biny, binz);
597 
598  // here only in the case of bins with labels
599  const char * labelX = 0;
600  const char * labelY = 0;
601  const char * labelZ = 0;
602  labelX=hist->GetXaxis()->GetBinLabel(binx);
603  if (fH0->fDimension > 1) labelY = hist->GetYaxis()->GetBinLabel(biny);
604  if (fH0->fDimension > 2) labelZ = hist->GetYaxis()->GetBinLabel(binz);
605  // do we need to support case when there are bins with labels and bins without them ??
606  // this case should have been detected before when examining the histograms
607 
608 
609  Int_t ix = -1;
610  Int_t iy = (fH0->fDimension > 1) ? -1 : 0;
611  Int_t iz = (fH0->fDimension > 2) ? -1 : 0;
612 
613  // special case for underflow/overflows which have normally empty labels
614  if (binx == 0 && TString(labelX) == "" ) ix = 0;
615  if (binx == hist->fXaxis.GetNbins() +1 && TString(labelX) == "" ) ix = fH0->fXaxis.GetNbins() +1;
616  if (fH0->fDimension > 1 ) {
617  if (biny == 0 && TString(labelY) == "" ) iy = 0;
618  if (biny == hist->fYaxis.GetNbins() +1 && TString(labelY) == "" ) iy = fH0->fYaxis.GetNbins() +1;
619  }
620  if (fH0->fDimension > 2 ) {
621  if (binz == 0 && TString(labelZ) == "" ) iz = 0;
622  if (binz == hist->fZaxis.GetNbins() +1 && TString(labelZ) == "" ) iz = fH0->fZaxis.GetNbins() +1;
623  }
624 
625 
626 
627  // find corresponding case (in case bin is not overflow)
628  if (ix == -1) {
629  if (labelsX)
630  ix = fH0->fXaxis.FindBin(labelX);
631  else
632  ix = FindFixBinNumber(binx, hist->fXaxis, fH0->fXaxis);
633  }
634 
635  if (iy == -1 && fH0->fDimension> 1 ) { // check on dim should not be needed
636  if (labelsY)
637  iy= fH0->fYaxis.FindBin(labelY);
638  else
639  iy = FindFixBinNumber(biny, hist->fYaxis, fH0->fYaxis);
640  }
641  if (iz == -1 && fH0->fDimension> 2) {
642  if (labelsZ)
643  iz= fH0->fZaxis.FindBin(labelZ);
644  else
645  iz = FindFixBinNumber(binz, hist->fZaxis, fH0->fZaxis);
646  }
647 
648  if (gDebug)
649  Info("TH1Merge::LabelMerge","Merge bin [%d,%d,%d] with label [%s,%s,%s] into bin [%d,%d,%d]",
650  binx,biny,binz,labelX,labelY,labelZ,ix,iy,iz);
651 
652  Int_t ib = fH0->GetBin(ix,iy,iz);
653  if (ib < 0 || ib >= fH0->fNcells) {
654  Fatal("TH1Merger::LabelMerge","Fatal error merging histogram %s - bin number is %d and array size is %d",
655  fH0->GetName(), ib,fH0->fNcells);
656  }
657 
658  fH0->AddBinContent(ib,cu);
659  if (fH0->fSumw2.fN) fH0->fSumw2.fArray[ib] += e1sq;
660  }
661  }
662  //copy merged stats
663  fH0->PutStats(totstats);
664  fH0->SetEntries(nentries);
665 
666  return kTRUE;
667 }
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:51
virtual Int_t Fill(Double_t x)
Increment bin with abscissa X by 1.
Definition: TH1.cxx:3125
TH1 * fHClone
histogram on which the list is merged
Definition: TH1Merger.h:70
static Bool_t AxesHaveLimits(const TH1 *h)
Definition: TH1Merger.cxx:14
void DefineNewAxes()
Function to define new histogram axis when merging It is call only in case of merging with different ...
Definition: TH1Merger.cxx:301
void Fatal(const char *location, const char *msgfmt,...)
virtual void SetDirectory(TDirectory *dir)
By default when an histogram is created, it is added to the list of histogram objects in the current ...
Definition: TH1.cxx:8051
TAxis fNewYAxis
Definition: TH1Merger.h:73
TAxis fYaxis
Y axis descriptor.
Definition: TH1.h:105
virtual void PutStats(Double_t *stats)
Replace current statistics with the values in array stats.
Definition: TH1.cxx:7070
const Double_t * GetArray() const
Definition: TArrayD.h:45
Bool_t TestBit(UInt_t f) const
Definition: TObject.h:157
TH1 * h
Definition: legend2.C:5
static Bool_t SameLimitsAndNBins(const TAxis &axis1, const TAxis &axis2)
Same limits and bins.
Definition: TH1.cxx:5219
virtual Int_t GetEntries() const
Definition: TCollection.h:92
Bool_t LabelMerge()
Merge histograms with labels.
Definition: TH1Merger.cxx:557
virtual void AddFirst(TObject *obj)
Add object at the beginning of the list.
Definition: TList.cxx:93
#define R__ASSERT(e)
Definition: TError.h:98
static Int_t FindFixBinNumber(Int_t ibin, const TAxis &inAxis, const TAxis &outAxis)
Definition: TH1Merger.h:21
Basic string class.
Definition: TString.h:137
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
TList fInputList
copy of fH0 - managed by this class
Definition: TH1Merger.h:71
const Bool_t kFALSE
Definition: Rtypes.h:92
int nbins[3]
TArrayD fSumw2
Array of sum of squares of weights.
Definition: TH1.h:118
static Bool_t RecomputeAxisLimits(TAxis &destAxis, const TAxis &anAxis)
Finds new limits for the axis for the Merge function.
Definition: TH1.cxx:5230
TAxis fZaxis
Z axis descriptor.
Definition: TH1.h:106
Bool_t CanExtend() const
Definition: TAxis.h:88
Short_t Abs(Short_t d)
Definition: TMathBase.h:110
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition: TObject.cxx:739
virtual void GetStats(Double_t *stats) const
fill the array stats from the contents of this histogram The array stats must be correctly dimensione...
Definition: TH1.cxx:7018
virtual Bool_t CanExtendAllAxes() const
Returns true if all axes are extendable.
Definition: TH1.cxx:5960
virtual void Reset(Option_t *option="")
Reset this histogram: contents, errors, etc.
Definition: TH1.cxx:6418
TAxis fNewZAxis
Definition: TH1Merger.h:74
virtual Int_t GetDimension() const
Definition: TH1.h:287
Double_t GetXmin() const
Definition: TAxis.h:139
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition: TObject.cxx:188
Bool_t operator()()
Function performing the actual merge.
Definition: TH1Merger.cxx:22
THashList implements a hybrid collection class consisting of a hash table and a list to store TObject...
Definition: THashList.h:36
THashList * GetLabels() const
Definition: TAxis.h:123
void Info(const char *location, const char *msgfmt,...)
Double_t * fArray
Definition: TArrayD.h:32
virtual void AddBinContent(Int_t bin)
Increment bin content by 1.
Definition: TH1.cxx:1193
void Error(const char *location, const char *msgfmt,...)
The 3-D histogram classes derived from the 1-D histogram classes.
Definition: TH3.h:35
Bool_t DifferentAxesMerge()
Merged histogram when axis can be different.
Definition: TH1Merger.cxx:466
UInt_t fNewAxisFlag
Definition: TH1Merger.h:75
Int_t fN
Definition: TArray.h:40
virtual void SetRange(Int_t first=0, Int_t last=0)
Set the viewing range for the axis from bin first to last.
Definition: TAxis.cxx:887
TAxis fNewXAxis
Definition: TH1Merger.h:72
Service class for 2-Dim histogram classes.
Definition: TH2.h:36
Int_t GetSize() const
Definition: TArray.h:49
virtual TObject * Remove(TObject *obj)
Remove object from the list.
Definition: TList.cxx:675
unsigned int UInt_t
Definition: RtypesCore.h:42
virtual void Copy(TObject &hnew) const
Copy this histogram structure to newth1.
Definition: TH1.cxx:2468
Bool_t SameAxesMerge()
Definition: TH1Merger.cxx:413
TAxis * GetYaxis()
Definition: TH1.h:325
void Warning(const char *location, const char *msgfmt,...)
virtual Int_t GetBin(Int_t binx, Int_t biny=0, Int_t binz=0) const
Return Global bin number corresponding to binx,y,z.
Definition: TH1.cxx:4540
virtual Double_t RetrieveBinContent(Int_t bin) const
Raw retrieval of bin content on internal data structure see convention for numbering bins in TH1::Get...
Definition: TH1.cxx:8541
virtual Int_t FindBin(Double_t x)
Find bin number corresponding to abscissa x.
Definition: TAxis.cxx:279
Bool_t CanBeAlphanumeric()
Definition: TAxis.h:89
Bool_t BufferMerge()
Definition: TH1Merger.cxx:367
double Double_t
Definition: RtypesCore.h:55
EMergerType ExamineHistograms()
Examine the list of histograms to find out which type of Merge we need to do Pass the input list cont...
Definition: TH1Merger.cxx:69
int type
Definition: TGX11.cxx:120
int nentries
Definition: THbookFile.cxx:89
The TH1 histogram class.
Definition: TH1.h:80
virtual Double_t GetEntries() const
Return the current number of entries.
Definition: TH1.cxx:4053
TAxis * GetZaxis()
Definition: TH1.h:326
virtual UInt_t SetCanExtend(UInt_t extendBitMask)
Make the histogram axes extendable / not extendable according to the bit mask returns the previous bi...
Definition: TH1.cxx:5973
virtual void SetBinsLength(Int_t=-1)
Definition: TH1.h:377
#define NULL
Definition: Rtypes.h:82
Int_t fDimension
!Histogram dimension (1, 2 or 3 dim)
Definition: TH1.h:124
R__EXTERN Int_t gDebug
Definition: Rtypes.h:128
virtual Int_t BufferEmpty(Int_t action=0)
Fill histogram with all entries in the buffer.
Definition: TH1.cxx:1236
virtual void SetEntries(Double_t n)
Definition: TH1.h:387
TAxis fXaxis
X axis descriptor.
Definition: TH1.h:104
Bool_t IsEmpty() const
Definition: TH1.h:154
void ResetBit(UInt_t f)
Definition: TObject.h:156
TH1 * fH0
Definition: TH1Merger.h:69
Int_t GetNbins() const
Definition: TAxis.h:127
virtual Int_t GetSize() const
Definition: TCollection.h:95
virtual void Set(Int_t nbins, Double_t xmin, Double_t xmax)
Initialize axis with fix bins.
Definition: TAxis.cxx:716
const Bool_t kTRUE
Definition: Rtypes.h:91
Double_t * fBuffer
[fBufferSize] entry buffer
Definition: TH1.h:122
void Set(Int_t n)
Set size of this array to n doubles.
Definition: TArrayD.cxx:105
Double_t GetXmax() const
Definition: TAxis.h:140
const TArrayD * GetXbins() const
Definition: TAxis.h:136
TAxis * GetXaxis()
Definition: TH1.h:324
if(line.BeginsWith("/*"))
Definition: HLFactory.cxx:443
virtual Double_t GetBinError(Int_t bin) const
Return value of error associated to bin number bin.
Definition: TH1.cxx:8173
Int_t fNcells
number of bins(1D), cells (2D) +U/Overflows
Definition: TH1.h:103