Logo ROOT  
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 #include <limits>
13 #include <utility>
14 
15 #define PRINTRANGE(a, b, bn) \
16  Printf(" base: %f %f %d, %s: %f %f %d", a->GetXmin(), a->GetXmax(), a->GetNbins(), bn, b->GetXmin(), b->GetXmax(), \
17  b->GetNbins());
18 
20  Bool_t hasLimits = h->GetXaxis()->GetXmin() < h->GetXaxis()->GetXmax();
21  if (h->GetDimension() > 1) hasLimits &= h->GetYaxis()->GetXmin() < h->GetYaxis()->GetXmax();
22  if (h->GetDimension() > 2) hasLimits &= h->GetZaxis()->GetXmin() < h->GetZaxis()->GetXmax();
23  return hasLimits;
24 }
25 
26 /// Function performing the actual merge
28 
29 
31 
32  if (gDebug) Info("Merge","Histogram Merge type is %d and new axis flag is %d",(int) type,(int) fNewAxisFlag);
33 
34  if (type == kNotCompatible) return kFALSE;
35 
36  if (type == kAllSameAxes)
37  return SameAxesMerge();
38 
39  if (type == kAllLabel)
40  return LabelMerge();
41 
42  if (type == kAllNoLimits)
43  return BufferMerge();
44 
46  return AutoP2Merge();
47 
48  // this is the mixed case - more complicated
49  if (type == kHasNewLimits) {
50  // we need to define some new axes
51  DefineNewAxes();
52  // we might need to merge some histogram using the buffer
53  Bool_t ret = BufferMerge();
54  // if ret is true the merge is completed and we can exit
55  if (ret) return kTRUE;
56  // in the other cases then we merge using FindBin
57  return DifferentAxesMerge();
58  }
59  Error("TH1Merger","Unknown type of Merge for histogram %s",fH0->GetName());
60  return kFALSE;
61 }
62 
63 /////////////////////////////////////////////////////////////////////////////////////////
64 /// Determine final boundaries and number of bins for histograms created in power-of-2
65 /// autobin mode.
66 ///
67 /// Return kTRUE if compatible, updating fNewXaxis accordingly; return kFALSE if something
68 /// wrong.
69 ///
70 /// The histograms are not merge-compatible if
71 ///
72 /// 1. have different variable-size bins
73 /// 2. larger bin size is not an integer multiple of the smaller one
74 /// 3. the final estimated range is smalle then the bin size
75 ///
76 
78 {
79  // They must be both defined
80  if (!h) {
81  Error("AutoP2BuildAxes", "undefined histogram: %p", h);
82  return kFALSE;
83  }
84 
85  // They must be created in power-of-2 autobin mode
86  if (!h->TestBit(TH1::kAutoBinPTwo)) {
87  Error("AutoP2BuildAxes", "not in autobin-power-of-2 mode!");
88  return kFALSE;
89  }
90 
91  // Point to axes
92  TAxis *a0 = &fNewXAxis, *a1 = h->GetXaxis();
93 
94  // This is for future merging of detached ranges (only possible if no over/underflows)
95  Bool_t canextend = (h->GetBinContent(0) > 0 || h->GetBinContent(a1->GetNbins() + 1) > 0) ? kFALSE : kTRUE;
96 
97  // The first time we just copy the boundaries and bins
98  if (a0->GetFirst() == a0->GetLast()) {
99  a0->Set(a1->GetNbins(), a1->GetXmin(), a1->GetXmax());
100  // This is for future merging of detached ranges (only possible if no over/underflows)
101  a0->SetCanExtend(canextend);
102  return kTRUE;
103  }
104 
105  // Bin sizes must be in integer ratio
106  Double_t bwmax = (a0->GetXmax() - a0->GetXmin()) / a0->GetNbins();
107  Double_t bwmin = (a1->GetXmax() - a1->GetXmin()) / a1->GetNbins();
108  Bool_t b0 = kTRUE;
109  if (bwmin > bwmax) {
110  std::swap(bwmax, bwmin);
111  b0 = kFALSE;
112  }
113  if (!(bwmin > 0.)) {
114  PRINTRANGE(a0, a1, h->GetName());
115  Error("AutoP2BuildAxes", "minimal bin width negative or null: %f", bwmin);
116  return kFALSE;
117  }
118 
119  Double_t rt;
120  Double_t re = std::modf(bwmax / bwmin, &rt);
122  PRINTRANGE(a0, a1, h->GetName());
123  Error("AutoP2BuildAxes", "bin widths not in integer ratio: %f", re);
124  return kFALSE;
125  }
126 
127  // Range of the merged histogram, taking into account overlaps
128  Bool_t domax = kFALSE;
129  Double_t xmax, xmin;
130  if (a0->GetXmin() < a1->GetXmin()) {
131  if (a0->GetXmax() < a1->GetXmin()) {
132  if (!a0->CanExtend() || !canextend) {
133  PRINTRANGE(a0, a1, h->GetName());
134  Error("AutoP2BuildAxes", "ranges are disconnected and under/overflows: cannot merge");
135  return kFALSE;
136  }
137  xmax = a1->GetXmax();
138  xmin = a0->GetXmin();
139  domax = b0 ? kTRUE : kFALSE;
140  } else {
141  if (a0->GetXmax() >= a1->GetXmax()) {
142  xmax = a1->GetXmax();
143  xmin = a1->GetXmin();
144  domax = !b0 ? kTRUE : kFALSE;
145  } else {
146  xmax = a0->GetXmax();
147  xmin = a1->GetXmin();
148  domax = !b0 ? kTRUE : kFALSE;
149  }
150  }
151  } else {
152  if (a1->GetXmax() < a0->GetXmin()) {
153  if (!a0->CanExtend() || !canextend) {
154  PRINTRANGE(a0, a1, h->GetName());
155  Error("AutoP2BuildAxes", "ranges are disconnected and under/overflows: cannot merge");
156  return kFALSE;
157  }
158  xmax = a0->GetXmax();
159  xmin = a1->GetXmin();
160  domax = !b0 ? kTRUE : kFALSE;
161  } else {
162  if (a1->GetXmax() >= a0->GetXmax()) {
163  xmax = a0->GetXmax();
164  xmin = a0->GetXmin();
165  domax = b0 ? kTRUE : kFALSE;
166  } else {
167  xmax = a1->GetXmax();
168  xmin = a0->GetXmin();
169  domax = b0 ? kTRUE : kFALSE;
170  }
171  }
172  }
173  Double_t range = xmax - xmin;
174 
175  re = std::modf(range / bwmax, &rt);
176  if (rt < 1.) {
177  PRINTRANGE(a0, a1, h->GetName());
178  Error("MergeCompatibleHistograms", "range smaller than bin width: %f %f %f", range, bwmax, rt);
179  return kFALSE;
180  }
182  if (domax) {
183  xmax -= bwmax * re;
184  } else {
185  xmin += bwmax * re;
186  }
187  }
188  // Number of bins
189  Int_t nb = (Int_t)rt;
190 
191  // Set the result
192  a0->Set(nb, xmin, xmax);
193 
194  // This is for future merging of detached ranges (only possible if no over/underflows)
195  if (!a0->CanExtend())
196  a0->SetCanExtend(canextend);
197 
198  // Done
199  return kTRUE;
200 }
201 
202 /**
203  Examine the list of histograms to find out which type of Merge we need to do
204  Pass the input list containing the histogram to merge and h0 which is the initial histogram
205  on which all the histogram of the list will be merged
206  This are the possible cases:
207  - 1. All histogram have the same axis (allSameLimits = true)
208  - 2. Histogram have different axis but compatible (allSameLimits = false) and sameLimitsX,Y,Z specifies which axis
209  has different limits
210  - 3. Histogram do not have limits (so the Buffer is used) allHaveLimits = false
211  - 3b. One histogram has limits the other not : allHaveLimits = false AND initialLimitsFound = true
212  - 4. Histogram Have labels = allHaveLabels = true
213 
214 
215 */
217 
218 
219 
220  Bool_t initialLimitsFound = kFALSE;
221  Bool_t allHaveLabels = kTRUE; // assume all histo have labels and check later
222  UInt_t labelAxisType = TH1::kNoAxis; // type of axes that have label
223  Bool_t allHaveLimits = kTRUE;
224  Bool_t allSameLimits = kTRUE;
225  Bool_t sameLimitsX = kTRUE;
226  Bool_t sameLimitsY = kTRUE;
227  Bool_t sameLimitsZ = kTRUE;
228  Bool_t foundLabelHist = kFALSE;
229  Bool_t haveWeights = kFALSE;
230 
231  Bool_t isAutoP2 = kFALSE;
232 
233  // TAxis newXAxis;
234  // TAxis newYAxis;
235  // TAxis newZAxis;
236 
237  TIter next(&fInputList);
238  TH1 * h = fH0; // start with fH0
239 
240  int dimension = fH0->GetDimension();
241 
242  isAutoP2 = fH0->TestBit(TH1::kAutoBinPTwo) ? kTRUE : kFALSE;
243 
244  // if the option alphanumeric merge is set
245  // we assume we do not have labels
246  if (fNoLabelMerge) allHaveLabels = kFALSE;
247 
248  // start looping on the histograms
249 
250  do {
251 
252  // check first histogram compatibility
253  if (h != fH0) {
254  if (h->GetDimension() != dimension) {
255  Error("Merge", "Cannot merge histogram - dimensions are different\n "
256  "%s has dim=%d and %s has dim=%d",fH0->GetName(),dimension,h->GetName(),h->GetDimension());
257  return kNotCompatible;
258  }
259  }
260 
261  // check if one of the histogram is weighted
262  haveWeights |= h->GetSumw2N() != 0;
263 
264  // do not skip anymore empty histograms
265  // since are used to set the limits
266  Bool_t hasLimits = TH1Merger::AxesHaveLimits(h);
267  allHaveLimits = allHaveLimits && hasLimits;
268  allSameLimits &= allHaveLimits;
269 
270  if (isAutoP2 && !h->TestBit(TH1::kAutoBinPTwo)) {
271  Error("Merge", "Cannot merge histogram - some are in autobin-power-of-2 mode, but not %s!", h->GetName());
272  return kNotCompatible;
273  }
274  if (!isAutoP2 && h->TestBit(TH1::kAutoBinPTwo)) {
275  Error("Merge", "Cannot merge histogram - %s is in autobin-power-of-2 mode, but not the previous ones",
276  h->GetName());
277  return kNotCompatible;
278  }
279 
280  if (hasLimits) {
281  h->BufferEmpty();
282 
283 // // this is done in case the first histograms are empty and
284 // // the histogram have different limits
285 // #ifdef LATER
286 // if (firstHistWithLimits ) {
287 // // set axis limits in the case the first histogram did not have limits
288 // if (h != this && !SameLimitsAndNBins( fXaxis, *h->GetXaxis()) ) {
289 // if (h->GetXaxis()->GetXbins()->GetSize() != 0) fXaxis.Set(h->GetXaxis()->GetNbins(), h->GetXaxis()->GetXbins()->GetArray());
290 // else fXaxis.Set(h->GetXaxis()->GetNbins(), h->GetXaxis()->GetXmin(), h->GetXaxis()->GetXmax());
291 // }
292 // firstHistWithLimits = kFALSE;
293 // }
294 // #endif
295 
296  // this is executed the first time an histogram with limits is found
297  // to set some initial values on the new axis
298  if (!initialLimitsFound) {
299  initialLimitsFound = kTRUE;
300  if (h->GetXaxis()->GetXbins()->GetSize() != 0)
301  fNewXAxis.Set(h->GetXaxis()->GetNbins(), h->GetXaxis()->GetXbins()->GetArray());
302  else
303  fNewXAxis.Set(h->GetXaxis()->GetNbins(), h->GetXaxis()->GetXmin(), h->GetXaxis()->GetXmax());
304  if (dimension > 1) {
305  if (h->GetYaxis()->GetXbins()->GetSize() != 0)
306  fNewYAxis.Set(h->GetYaxis()->GetNbins(), h->GetYaxis()->GetXbins()->GetArray());
307  else
308  fNewYAxis.Set(h->GetYaxis()->GetNbins(), h->GetYaxis()->GetXmin(), h->GetYaxis()->GetXmax());
309  }
310  if (dimension > 2) {
311  if (h->GetZaxis()->GetXbins()->GetSize() != 0)
312  fNewZAxis.Set(h->GetZaxis()->GetNbins(), h->GetZaxis()->GetXbins()->GetArray());
313  else
314  fNewZAxis.Set(h->GetZaxis()->GetNbins(), h->GetZaxis()->GetXmin(), h->GetZaxis()->GetXmax());
315 
316  }
317  }
318  else {
319  // check first if histograms have same bins in X
320  if (!TH1::SameLimitsAndNBins(fNewXAxis, *(h->GetXaxis())) ) {
321  sameLimitsX = kFALSE;
322  // recompute the limits in this case the optimal limits
323  // The condition to works is that the histogram have same bin with
324  // and one common bin edge
325  if (!TH1::RecomputeAxisLimits(fNewXAxis, *(h->GetXaxis()))) {
326  Error("Merge", "Cannot merge histograms - limits are inconsistent:\n "
327  "first: %s (%d, %f, %f), second: %s (%d, %f, %f)", fH0->GetName(),
329  h->GetName(),h->GetXaxis()->GetNbins(), h->GetXaxis()->GetXmin(),
330  h->GetXaxis()->GetXmax());
331  return kNotCompatible;
332  }
333  }
334  // check first if histograms have same bins in Y
335  if (dimension > 1 && !TH1::SameLimitsAndNBins(fNewYAxis, *(h->GetYaxis()))) {
336  sameLimitsY = kFALSE;
337  // recompute in this case the optimal limits
338  // The condition to works is that the histogram have same bin with
339  // and one common bin edge
340  if (!TH1::RecomputeAxisLimits(fNewYAxis, *(h->GetYaxis()))) {
341  Error("Merge", "Cannot merge histograms - limits are inconsistent:\n "
342  "first: %s (%d, %f, %f), second: %s (%d, %f, %f)", fH0->GetName(),
344  h->GetName(), h->GetYaxis()->GetNbins(), h->GetYaxis()->GetXmin(),
345  h->GetYaxis()->GetXmax());
346  return kNotCompatible;
347  }
348  }
349  if(dimension > 2 && !fH0->SameLimitsAndNBins(fNewZAxis, *(h->GetZaxis()))) {
350  sameLimitsZ = kFALSE;
351  if (!TH1::RecomputeAxisLimits(fNewZAxis, *(h->GetZaxis()))) {
352  Error("Merge", "Cannot merge histograms - limits are inconsistent:\n "
353  "first: %s (%d, %f, %f), second: %s (%d, %f, %f)", fH0->GetName(),
355  h->GetName(),h->GetZaxis()->GetNbins(), h->GetZaxis()->GetXmin(),
356  h->GetZaxis()->GetXmax());
357  return kNotCompatible;
358  }
359  }
360  allSameLimits = sameLimitsX && sameLimitsY && sameLimitsZ;
361 
362 
363  }
364  }
365  Bool_t histoIsEmpty = h->IsEmpty();
366  // std::cout << "considering histo " << h->GetName() << " labels - " << allHaveLabels << " is empty "
367  // << histoIsEmpty << std::endl;
368 
369  // if histogram is empty it does not matter if it has label or not
370  if (allHaveLabels && !histoIsEmpty) {
371  THashList* hlabelsX = h->GetXaxis()->GetLabels();
372  THashList* hlabelsY = (dimension > 1) ? h->GetYaxis()->GetLabels() : nullptr;
373  THashList* hlabelsZ = (dimension > 2) ? h->GetZaxis()->GetLabels() : nullptr;
374  Bool_t haveOneLabelX = hlabelsX != nullptr;
375  Bool_t haveOneLabelY = hlabelsY != nullptr;
376  Bool_t haveOneLabelZ = hlabelsZ != nullptr;
377  Bool_t haveOneLabel = haveOneLabelX || haveOneLabelY || haveOneLabelZ;
378  // do here to print message only one time
379  if (foundLabelHist && allHaveLabels && !haveOneLabel) {
380  Warning("Merge","Not all histograms have labels. I will ignore labels,"
381  " falling back to bin numbering mode.");
382  }
383 
384  allHaveLabels &= (haveOneLabel);
385 
386  if (haveOneLabel) {
387  foundLabelHist = kTRUE;
388  UInt_t type = 0;
389  if (haveOneLabelX) type |= TH1::kXaxis;
390  if (haveOneLabelY) type |= TH1::kYaxis;
391  if (haveOneLabelZ) type |= TH1::kZaxis;
392  if (labelAxisType == TH1::kNoAxis) labelAxisType = type;
393  // check if all histogram have consistent label axis
394  // this means that there is at least one axis where boith histogram have labels
395  Bool_t consistentLabels = (type & labelAxisType) != TH1::kNoAxis;
396  allHaveLabels &= consistentLabels;
397  if (!consistentLabels)
398  Warning("TH1Merger::ExamineHistogram","Histogram %s has inconsistent labels: %d is not consistent with %d",
399  h->GetName(), (int) type, (int) labelAxisType );
400  if (gDebug && consistentLabels)
401  Info("TH1Merger::ExamineHistogram","Histogram %s has consistent labels",h->GetName() );
402  }
403 
404  // Check compatibility of axis that have labels with axis that can be extended
405  UInt_t extendAxisType = TH1::kNoAxis;
406  if (fH0->GetXaxis()->CanExtend()) extendAxisType |= TH1::kXaxis;
407  if (dimension > 1 && fH0->GetYaxis()->CanExtend()) extendAxisType |= TH1::kYaxis;
408  if (dimension > 2 && fH0->GetZaxis()->CanExtend()) extendAxisType |= TH1::kZaxis;
409  // it is sufficient to have a consistent label axis that can be extended
410  Bool_t labelAxisCanBeExtended = ((extendAxisType & labelAxisType) != TH1::kNoAxis);
411  // If histograms have labels but corresponding axes cannot be extended use bin center mode
412  if (allHaveLabels && !labelAxisCanBeExtended) {
413  // special case for this histogram when is empty
414  // and axis cannot be extended (because it is the default)
415  if ( fH0->IsEmpty() ) {
416  if (gDebug)
417  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());
418  fH0->SetCanExtend( labelAxisType );
419  }
420  else { // histogram is not empty
421  if (gDebug)
422  Info("TH1Merger::ExamineHistogram","Histogram %s to be merged has labels but corresponding axis cannot be extended - using bin numeric mode to merge. Call TH1::SetCanExtend(TH1::kAllAxes) if want to merge using label mode",fH0->GetName());
423  allHaveLabels = kFALSE;
424  }
425  }
426  // we don;t need to check anymore for case of non=empty histograms with some labels.
427  // If we have some labels set ans axis is not extendable the LabelsMerge function handles
428  // that case correctly
429 #if 0
430  if (allHaveLabels ) {
431  // count number of bins with non-null content
432  Int_t non_zero_bins = 0;
433  // loop on axis that have labels. Support this only for 1D histogram
434  if (hlabelsX && dimension == 1 && !h->GetXaxis()->CanExtend()) {
435  Int_t nbins = h->GetXaxis()->GetNbins();
436  if (nbins > hlabelsX->GetEntries() ) {
437  for (Int_t i = 1; i <= nbins; i++) {
438  if (h->RetrieveBinContent(i) != 0 || (h->fSumw2.fN && h->GetBinError(i) != 0) ) {
439  non_zero_bins++;
440  }
441  }
442  if (non_zero_bins > hlabelsX->GetEntries() ) {
443  Warning("TH1Merger::ExamineHistograms","Histogram %s contains non-empty bins without labels - falling back to bin numbering mode",h->GetName() );
444  allHaveLabels = kFALSE;
445  }
446  }
447  }
448  // for multidimensional case check that labels size is less than axis size
449 
450  if (dimension > 1 ) {
451  if (hlabelsX && !h->GetXaxis()->CanExtend() && hlabelsX->GetEntries() < h->GetXaxis()->GetNbins()-1 ) { // use -1 because one bin without label is like a dummy label
452  Warning("TH1Merger::ExamineHistograms","Histogram %s has the X axis containing more than one bin without labels - falling back to bin numbering mode",h->GetName() );
453  allHaveLabels = kFALSE;
454  }
455  if (hlabelsY && !h->GetYaxis()->CanExtend() && hlabelsY->GetEntries() < h->GetYaxis()->GetNbins()-1 ) { // use -1 because one bin without label is like a dummy label
456  Warning("TH1Merger::ExamineHistograms","Histogram %s has the Y axis containing more than one bin without labels - falling back to bin numbering mode",h->GetName() );
457  allHaveLabels = kFALSE;
458  }
459  if (hlabelsZ && !h->GetZaxis()->CanExtend() && hlabelsZ->GetEntries() < h->GetZaxis()->GetNbins()-1 ) { // use -1 because one bin without label is like a dummy label
460  Warning("TH1Merger::ExamineHistograms","Histogram %s has the Z axis containing more than one bin without labels - falling back to bin numbering mode",h->GetName() );
461  allHaveLabels = kFALSE;
462  }
463  }
464  }
465 #endif
466  }
467  if (gDebug)
468  Info("TH1Merger::ExamineHistogram","Examine histogram %s - labels %d - same limits %d - axis found %d",h->GetName(),allHaveLabels,allSameLimits,initialLimitsFound );
469 
470  } while ( ( h = dynamic_cast<TH1*> ( next() ) ) != NULL );
471 
472  if (!h && (*next) ) {
473  Error("Merge","Attempt to merge object of class: %s to a %s",
474  (*next)->ClassName(),fH0->ClassName());
475  return kNotCompatible;
476  }
477 
478  // in case of weighted histogram set Sumw2() on fH0 is is not weighted
479  if (haveWeights && fH0->GetSumw2N() == 0)
480  fH0->Sumw2();
481 
482  // AutoP2
483  if (isAutoP2) {
484  if (allHaveLimits)
485  return kAutoP2HaveLimits;
486  return kAutoP2NeedLimits;
487  }
488 
489  // return the type of merge
490  if (allHaveLabels) return kAllLabel;
491  if (allSameLimits) return kAllSameAxes;
492  if (!initialLimitsFound) {
493  R__ASSERT(!allHaveLimits);
494  // case where no limits are found and the buffer is used
495  return kAllNoLimits;
496  }
497  // remaining case should be the mixed one. Some histogram have limits some not
498  fNewAxisFlag = 0;
499  if (!sameLimitsX) fNewAxisFlag |= TH1::kXaxis;
500  if (!sameLimitsY) fNewAxisFlag |= TH1::kYaxis;
501  if (!sameLimitsZ) fNewAxisFlag |= TH1::kZaxis;
502 
503  // we need to set the flag also in case this histogram has no limits
504  // we need to set explicitly the flag to re-define a new axis
506  if (dimension > 1 && fH0->GetYaxis()->GetXmin() >= fH0->GetYaxis()->GetXmax()) fNewAxisFlag |= TH1::kYaxis;
507  if (dimension > 2 && fH0->GetZaxis()->GetXmin() >= fH0->GetZaxis()->GetXmax()) fNewAxisFlag |= TH1::kZaxis;
508 
509 
510  return kHasNewLimits;
511 
512 }
513 
514 /**
515  Function to define new histogram axis when merging
516  It is call only in case of merging with different axis or with the
517  buffer (kHasNewLimits)
518 */
519 
521 
522  // first we need to create a copy of the histogram in case is not empty
523 
524  if (!fH0->IsEmpty() ) {
525  Bool_t mustCleanup = fH0->TestBit(kMustCleanup);
526  if (mustCleanup) fH0->ResetBit(kMustCleanup);
527  fHClone = (TH1*)fH0->IsA()->New();
528  fHClone->SetDirectory(0);
529  fH0->Copy(*fHClone);
530  if (mustCleanup) fH0->SetBit(kMustCleanup);
531  fH0->BufferEmpty(1); // To remove buffer.
532  fH0->Reset(); // BufferEmpty sets limits so we can't use it later.
533  fH0->SetEntries(0);
535 
536  }
537 
538  bool newLimitsX = (fNewAxisFlag & TH1::kXaxis);
539  bool newLimitsY = (fNewAxisFlag & TH1::kYaxis);
540  bool newLimitsZ = (fNewAxisFlag & TH1::kZaxis);
541  if (newLimitsX) {
542  fH0->fXaxis.SetRange(0,0);
543  if (fNewXAxis.GetXbins()->GetSize() != 0)
545  else
547  }
548  if (newLimitsY) {
549  fH0->fYaxis.SetRange(0,0);
550  if (fNewYAxis.GetXbins()->GetSize() != 0)
552  else
554  }
555  if (newLimitsZ) {
556  fH0->fZaxis.SetRange(0,0);
557  if (fNewZAxis.GetXbins()->GetSize() != 0)
559  else
561  }
562 
563  // we need to recompute fNcells and set the array size (as in TH1::SetBins)
564  fH0->fNcells = fH0->fXaxis.GetNbins()+2;
565  if (fH0->fDimension > 1) fH0->fNcells *= fH0->fYaxis.GetNbins()+2;
566  if (fH0->fDimension > 2) fH0->fNcells *= fH0->fZaxis.GetNbins()+2;
568  if (fH0->fSumw2.fN) fH0->fSumw2.Set(fH0->fNcells);
569  // set dummy Y and Z axis for lower dim histogras
570  if (fH0->fDimension < 3) fH0->fZaxis.Set(1,0,1);
571  if (fH0->fDimension < 2) fH0->fYaxis.Set(1,0,1);
572 
573  if (gDebug) {
574  if (newLimitsX) Info("DefineNewAxis","A new X axis has been defined Nbins=%d , [%f,%f]", fH0->fXaxis.GetNbins(),
575  fH0->fXaxis.GetXmin(), fH0->fXaxis.GetXmax() );
576  if (newLimitsY) Info("DefineNewAxis","A new Y axis has been defined Nbins=%d , [%f,%f]", fH0->fYaxis.GetNbins(),
577  fH0->fYaxis.GetXmin(), fH0->fYaxis.GetXmax() );
578  if (newLimitsZ) Info("DefineNewAxis","A new Z axis has been defined Nbins=%d , [%f,%f]", fH0->fZaxis.GetNbins(),
579  fH0->fZaxis.GetXmin(), fH0->fZaxis.GetXmax() );
580  }
581 
582  return;
583 
584 }
585 
586 void TH1Merger::CopyBuffer(TH1 *hsrc, TH1 *hdes)
587 {
588  // Check inputs
589  //if (!hsrc || !hsrc->fBuffer || !hdes || !hdes->fBuffer) {
590  if (!hsrc || !hsrc->fBuffer || !hdes ) {
591  void *p1 = hsrc ? hsrc->fBuffer : 0;
592  //void *p2 = hdes ? hdes->fBuffer : 0;
593  //Warning("TH1Merger::CopyMerge", "invalid inputs: %p, %p, %p, %p -> do nothing", hsrc, hdes, p1, p2);
594  Warning("TH1Merger::CopyMerge", "invalid inputs: %p, %p, %p, -> do nothing", hsrc, hdes, p1);
595  }
596 
597  // Entries from buffers have to be filled one by one
598  // because FillN doesn't resize histograms.
599  Int_t nbentries = (Int_t)hsrc->fBuffer[0];
600  if (hdes->fDimension == 1) {
601  for (Int_t i = 0; i < nbentries; i++)
602  hdes->Fill(hsrc->fBuffer[2 * i + 2], hsrc->fBuffer[2 * i + 1]);
603  }
604  if (hdes->fDimension == 2) {
605  auto h2 = dynamic_cast<TH2 *>(hdes);
606  R__ASSERT(h2);
607  for (Int_t i = 0; i < nbentries; i++)
608  h2->Fill(hsrc->fBuffer[3 * i + 2], hsrc->fBuffer[3 * i + 3], hsrc->fBuffer[3 * i + 1]);
609  }
610  if (hdes->fDimension == 3) {
611  auto h3 = dynamic_cast<TH3 *>(hdes);
612  R__ASSERT(h3);
613  for (Int_t i = 0; i < nbentries; i++)
614  h3->Fill(hsrc->fBuffer[4 * i + 2], hsrc->fBuffer[4 * i + 3], hsrc->fBuffer[4 * i + 4],
615  hsrc->fBuffer[4 * i + 1]);
616  }
617 }
618 
620 {
621 
622  TH1 *href = 0, *hist = 0;
623  TIter nextref(&fInputList);
625  href = fH0;
626  } else {
627  while ((hist = (TH1 *)nextref()) && !href) {
628  if (TH1Merger::AxesHaveLimits(hist))
629  href = hist;
630  }
631  }
632  Bool_t resetfH0 = kFALSE;
633  if (!href) {
634  // Merge all histograms to fH0 and do a final projection
635  href = fH0;
636  } else {
637  if (href != fH0) {
638  // Temporary add fH0 to the list for buffer merging
639  fInputList.Add(fH0);
640  resetfH0 = kTRUE;
641  }
642  }
643  TIter next(&fInputList);
644  while ((hist = (TH1 *)next())) {
645  if (!TH1Merger::AxesHaveLimits(hist) && hist->fBuffer) {
646  if (gDebug)
647  Info("AutoP2BufferMerge", "merging buffer of %s into %s", hist->GetName(), href->GetName());
648  CopyBuffer(hist, href);
649  fInputList.Remove(hist);
650  }
651  }
652  // Final projection
653  if (href->fBuffer)
654  href->BufferEmpty(1);
655  // Reset fH0, if already added, to avoid double counting
656  if (resetfH0)
657  fH0->Reset("ICES");
658  // Done, all histos have been processed
659  return kTRUE;
660 }
661 
663 {
664 
665  Double_t stats[TH1::kNstat], totstats[TH1::kNstat];
666  for (Int_t i = 0; i < TH1::kNstat; i++) {
667  totstats[i] = stats[i] = 0;
668  }
669 
670  TIter next(&fInputList);
671  TH1 *hist = 0;
672  // Calculate boundaries and bins
673  Double_t xmin = 0., xmax = 0.;
674  if (!(fH0->IsEmpty())) {
675  hist = fH0;
676  } else {
677  while ((hist = (TH1 *)next())) {
678  if (!hist->IsEmpty())
679  break;
680  }
681  }
682 
683  if (!hist) {
684  if (gDebug)
685  Info("TH1Merger::AutoP2Merge", "all histograms look empty!");
686  return kFALSE;
687  }
688 
689  // Start building the axes from the reference histogram
690  if (!AutoP2BuildAxes(hist)) {
691  Error("TH1Merger::AutoP2Merge", "cannot create axes from %s", hist->GetName());
692  return kFALSE;
693  }
694  TH1 *h = 0;
695  while ((h = (TH1 *)next())) {
696  if (!AutoP2BuildAxes(h)) {
697  Error("TH1Merger::AutoP2Merge", "cannot merge histogram %s: not merge compatible", h->GetName());
698  return kFALSE;
699  }
700  }
701  xmin = fNewXAxis.GetXmin();
702  xmax = fNewXAxis.GetXmax();
703  Int_t nbins = fNewXAxis.GetNbins();
704 
705  // Prepare stats
706  fH0->GetStats(totstats);
707  // Clone fH0 and add it to the list
708  if (!fH0->IsEmpty())
709  fInputList.Add(fH0->Clone());
710 
711  // reset fH0
712  fH0->Reset("ICES");
713  // Set the new boundaries
714  fH0->SetBins(nbins, xmin, xmax);
715 
716  next.Reset();
717  Double_t nentries = 0.;
718  while ((hist = (TH1 *)next())) {
719  // process only if the histogram has limits; otherwise it was processed before
720  // in the case of an existing buffer (see if statement just before)
721 
722  if (gDebug)
723  Info("TH1Merger::AutoP2Merge", "merging histogram %s into %s (entries: %f)", hist->GetName(), fH0->GetName(),
724  hist->GetEntries());
725 
726  // skip empty histograms
727  if (hist->IsEmpty())
728  continue;
729 
730  // import statistics
731  hist->GetStats(stats);
732  for (Int_t i = 0; i < TH1::kNstat; i++)
733  totstats[i] += stats[i];
734  nentries += hist->GetEntries();
735 
736  // Int_t nx = hist->GetXaxis()->GetNbins();
737  // loop on bins of the histogram and do the merge
738  for (Int_t ibin = 0; ibin < hist->fNcells; ibin++) {
739 
740  Double_t cu = hist->RetrieveBinContent(ibin);
741  Double_t e1sq = TMath::Abs(cu);
742  if (fH0->fSumw2.fN)
743  e1sq = hist->GetBinErrorSqUnchecked(ibin);
744 
745  Double_t xu = hist->GetBinCenter(ibin);
746  Int_t jbin = fH0->FindBin(xu);
747 
748  fH0->AddBinContent(jbin, cu);
749  if (fH0->fSumw2.fN)
750  fH0->fSumw2.fArray[jbin] += e1sq;
751  }
752  }
753  // copy merged stats
754  fH0->PutStats(totstats);
756 
757  return kTRUE;
758 }
759 
761 {
762 
763  TIter next(&fInputList);
764  while (TH1* hist = (TH1*)next()) {
765  // support also case where some histogram have limits and some have the buffer
766  if ( !TH1Merger::AxesHaveLimits(hist) && hist->fBuffer ) {
767 
768  if (gDebug)
769  Info("TH1Merger::BufferMerge","Merging histogram %s into %s",hist->GetName(), fH0->GetName() );
770  CopyBuffer(hist, fH0);
771  fInputList.Remove(hist);
772  }
773  }
774  // return true if the merge is completed
775  if (fInputList.GetSize() == 0) {
776  // all histo have been merged
777  return kTRUE;
778  }
779  // we need to reset the buffer in case of merging later on
780  // is this really needed ???
781  if (fH0->fBuffer) fH0->BufferEmpty(1);
782 
783  return kFALSE;
784 }
785 
787 
788 
789  Double_t stats[TH1::kNstat], totstats[TH1::kNstat];
790  for (Int_t i=0;i<TH1::kNstat;i++) {
791  totstats[i] = stats[i] = 0;
792  }
793  fH0->GetStats(totstats);
795 
796  TIter next(&fInputList);
797  while (TH1* hist=(TH1*)next()) {
798  // process only if the histogram has limits; otherwise it was processed before
799  // in the case of an existing buffer (see if statement just before)
800 
801  if (gDebug)
802  Info("TH1Merger::SameAxesMerge","Merging histogram %s into %s",hist->GetName(), fH0->GetName() );
803 
804  // skip empty histograms
805  if (hist->IsEmpty()) continue;
806 
807  // import statistics
808  hist->GetStats(stats);
809  for (Int_t i=0; i<TH1::kNstat; i++)
810  totstats[i] += stats[i];
811  nentries += hist->GetEntries();
812 
813  //Int_t nx = hist->GetXaxis()->GetNbins();
814  // loop on bins of the histogram and do the merge
815  for (Int_t ibin = 0; ibin < hist->fNcells; ibin++) {
816  MergeBin(hist, ibin, ibin);
817  }
818  }
819  //copy merged stats
820  fH0->PutStats(totstats);
822 
823  return kTRUE;
824 }
825 
826 
827 /**
828  Merged histogram when axis can be different.
829  Histograms are merged looking at bin center positions
830 
831  */
833 
834  Double_t stats[TH1::kNstat], totstats[TH1::kNstat];
835  for (Int_t i=0;i<TH1::kNstat;i++) {totstats[i] = stats[i] = 0;}
836  fH0->GetStats(totstats);
838 
839  TIter next(&fInputList);
840  while (TH1* hist=(TH1*)next()) {
841 
842  if (gDebug)
843  Info("TH1Merger::DifferentAxesMerge","Merging histogram %s into %s",hist->GetName(), fH0->GetName() );
844 
845  // skip empty histograms
846  if (hist->IsEmpty()) continue;
847 
848  // import statistics
849  hist->GetStats(stats);
850  for (Int_t i=0;i<TH1::kNstat;i++)
851  totstats[i] += stats[i];
852  nentries += hist->GetEntries();
853 
854  // loop on bins of the histogram and do the merge
855  for (Int_t ibin = 0; ibin < hist->fNcells; ibin++) {
856 
857  // if bin is empty we can skip it
858  if (IsBinEmpty(hist,ibin)) continue;
859 
860  Int_t binx,biny,binz;
861  hist->GetBinXYZ(ibin, binx, biny, binz);
862 
863  // case of underflow/overflows in the histogram being merged
864  if (binx <= 0 || binx >= hist->GetNbinsX() + 1) {
865  if (fH0->fXaxis.CanExtend() || ( hist->fXaxis.GetBinCenter(binx) > fH0->fXaxis.GetXmin() && hist->fXaxis.GetBinCenter(binx) < fH0->fXaxis.GetXmax()) ) {
866  Error("TH1Merger::DifferentAxesMerge", "Cannot merge histograms - the histograms %s can extend the X axis or have"
867  " different limits and underflows/overflows are present in the histogram %s.",fH0->GetName(),hist->GetName());
868  return kFALSE;
869  }
870  }
871  if (biny <= 0 || biny >= hist->GetNbinsY() + 1) {
872  if (fH0->fYaxis.CanExtend() || ( hist->fYaxis.GetBinCenter(biny) > fH0->fYaxis.GetXmin() && hist->fYaxis.GetBinCenter(biny) < fH0->fYaxis.GetXmax()) ) {
873  Error("TH1Merger::DifferentAxesMerge", "Cannot merge histograms - the histograms %s can extend the Y axis or have"
874  " different limits and underflows/overflows are present in the histogram %s.",fH0->GetName(),hist->GetName());
875  return kFALSE;
876  }
877  }
878  if (binz <= 0 || binz >= hist->GetNbinsZ() + 1) {
879  if (fH0->fZaxis.CanExtend() || ( hist->fZaxis.GetBinCenter(binz) > fH0->fZaxis.GetXmin() && hist->fZaxis.GetBinCenter(binz) < fH0->fZaxis.GetXmax()) ) {
880  Error("TH1Merger::DifferentAxesMerge", "Cannot merge histograms - the histograms %s can extend the Z axis or have"
881  " different limits and underflows/overflows are present in the histogram %s.",fH0->GetName(),hist->GetName());
882  return kFALSE;
883  }
884  }
885 
886  Int_t ix = 0;
887  Int_t iy = 0;
888  Int_t iz = 0;
889 
890  // we can extend eventually the axis if histogram is capable of doing it
891  // by using FindBin
892  ix = fH0->fXaxis.FindBin(hist->GetXaxis()->GetBinCenter(binx));
893  if (fH0->fDimension > 1)
894  iy = fH0->fYaxis.FindBin(hist->GetYaxis()->GetBinCenter(biny));
895  if (fH0->fDimension > 2)
896  iz = fH0->fZaxis.FindBin(hist->GetZaxis()->GetBinCenter(binz));
897 
898  Int_t ib = fH0->GetBin(ix,iy,iz);
899  if (ib < 0 || ib > fH0->fNcells) {
900  Fatal("TH1Merger::LabelMerge","Fatal error merging histogram %s - bin number is %d and array size is %d",
901  fH0->GetName(), ib,fH0->fNcells);
902  }
903 
904  MergeBin(hist, ibin, ib);
905 
906  }
907  }
908  //copy merged stats
909  fH0->PutStats(totstats);
911 
912  return kTRUE;
913 }
914 
915 /**
916  Find a duplicate labels in an axis label list
917 */
919 
920  if (!labels) return kFALSE;
921 
922  for (const auto * obj: *labels) {
923  auto objList = labels->GetListForObject(obj);
924  //objList->ls();
925  if (objList->GetSize() > 1 ) {
926  // check here if in the list we have duplicates
927  std::unordered_set<std::string> s;
928  for ( const auto * o: *objList) {
929  auto ret = s.insert(std::string(o->GetName() ));
930  if (!ret.second) return kTRUE;
931  }
932  }
933  }
934  return kFALSE;
935 }
936 
937 /**
938  Check if histogram has duplicate labels
939  Return an integer with bit set correponding
940  on the axis that has duplicate labels
941  e.g. duplicate labels on x axis : return 1
942  duplicate labels on x and z axis : return 5
943 
944 */
946 
947  R__ASSERT(hist != nullptr);
948 
949  auto labelsX = hist->GetXaxis()->GetLabels();
950  auto labelsY = hist->GetYaxis()->GetLabels();
951  auto labelsZ = hist->GetZaxis()->GetLabels();
952 
953  Int_t res = 0;
954  if (HasDuplicateLabels(labelsX) ) {
955  Warning("TH1Merger::CheckForDuplicateLabels","Histogram %s has duplicate labels in the x axis. "
956  "Bin contents will be merged in a single bin",hist->GetName());
957  res |= 1;
958  }
959  if (HasDuplicateLabels(labelsY) ) {
960  Warning("TH1Merger::CheckForDuplicateLabels","Histogram %s has duplicate labels in the y axis. "
961  "Bin contents will be merged in a single bin",hist->GetName());
962  res |= 2;
963  }
964  if (HasDuplicateLabels(labelsZ) ) {
965  Warning("TH1Merger::CheckForDuplicateLabels","Histogram %s has duplicate labels in the z axis. "
966  "Bin contents will be merged in a single bin",hist->GetName());
967  res |= 4;
968  }
969  return res;
970 }
971 
972 /**
973  Merge histograms with labels
974 */
976 
977  Double_t stats[TH1::kNstat], totstats[TH1::kNstat];
978  for (Int_t i=0;i<TH1::kNstat;i++) {totstats[i] = stats[i] = 0;}
979  fH0->GetStats(totstats);
981 
982  // check for duplicate labels
984 
985  TIter next(&fInputList);
986  while (TH1* hist=(TH1*)next()) {
987 
988  if (gDebug)
989  Info("TH1Merger::LabelMerge","Merging histogram %s into %s",hist->GetName(), fH0->GetName() );
990 
991  // skip empty histograms
992  if (hist->IsEmpty()) continue;
993 
994  // import statistics
995  hist->GetStats(stats);
996  for (Int_t i=0;i<TH1::kNstat;i++)
997  totstats[i] += stats[i];
998  nentries += hist->GetEntries();
999 
1000  auto labelsX = hist->GetXaxis()->GetLabels();
1001  auto labelsY = hist->GetYaxis()->GetLabels();
1002  auto labelsZ = hist->GetZaxis()->GetLabels();
1003  R__ASSERT(!( labelsX == nullptr && labelsY == nullptr && labelsZ == nullptr));
1004 
1005  Bool_t mergeLabelsX = labelsX && fH0->fXaxis.CanExtend() && hist->fXaxis.CanExtend();
1006  Bool_t mergeLabelsY = labelsY && fH0->fYaxis.CanExtend() && hist->fYaxis.CanExtend();
1007  Bool_t mergeLabelsZ = labelsZ && fH0->fZaxis.CanExtend() && hist->fZaxis.CanExtend();
1008 
1009  if (gDebug) {
1010  if (mergeLabelsX)
1011  Info("TH1Merger::LabelMerge","Merging X axis in label mode");
1012  else
1013  Info("TH1Merger::LabelMerge","Merging X axis in numeric mode");
1014  if (mergeLabelsY)
1015  Info("TH1Merger::LabelMerge","Merging Y axis in label mode");
1016  else if (hist->GetDimension() > 1)
1017  Info("TH1Merger::LabelMerge","Merging Y axis in numeric mode");
1018  if (mergeLabelsZ)
1019  Info("TH1Merger::LabelMerge","Merging Z axis in label mode" );
1020  else if (hist->GetDimension() > 2)
1021  Info("TH1Merger::LabelMerge","Merging Z axis in numeric mode");
1022  }
1023 
1024  // check if histogram has duplicate labels
1025  if (!fNoCheck && hist->GetEntries() > 0) CheckForDuplicateLabels(hist);
1026 
1027  // loop on bins of the histogram and do the merge
1028  if (gDebug) {
1029  // print bins original histogram
1030  std::cout << "Bins of original histograms\n";
1031  for (int ix = 1; ix <= fH0->GetXaxis()->GetNbins(); ++ix) {
1032  for (int iy = 1; iy <= fH0->GetYaxis()->GetNbins(); ++iy) {
1033  for (int iz = 1; iz <= fH0->GetZaxis()->GetNbins(); ++iz) {
1034  int i = fH0->GetBin(ix,iy,iz);
1035  std::cout << "bin" << ix << "," << iy << "," << iz
1036  << " : " << fH0->RetrieveBinContent(i) /* << " , " << fH0->fBinEntries.fArray[i] */ << std::endl;
1037  }
1038  }
1039  }
1040  }
1041  for (Int_t ibin = 0; ibin < hist->fNcells; ibin++) {
1042 
1043  // if bin is empty we can skip it
1044  if (IsBinEmpty(hist,ibin)) continue;
1045 
1046  Int_t binx,biny,binz;
1047  hist->GetBinXYZ(ibin, binx, biny, binz);
1048 
1049  // here only in the case of bins with labels
1050  const char * labelX = 0;
1051  const char * labelY = 0;
1052  const char * labelZ = 0;
1053  labelX=hist->GetXaxis()->GetBinLabel(binx);
1054  if (fH0->fDimension > 1) labelY = hist->GetYaxis()->GetBinLabel(biny);
1055  if (fH0->fDimension > 2) labelZ = hist->GetYaxis()->GetBinLabel(binz);
1056  // do we need to support case when there are bins with labels and bins without them ??
1057  // this case should have been detected before when examining the histograms
1058 
1059 
1060  Int_t ix = -1;
1061  Int_t iy = (fH0->fDimension > 1) ? -1 : 0;
1062  Int_t iz = (fH0->fDimension > 2) ? -1 : 0;
1063 
1064  // special case for underflow/overflows which have normally empty labels
1065  if (binx == 0 && TString(labelX) == "" ) ix = 0;
1066  if (binx == hist->fXaxis.GetNbins() +1 && TString(labelX) == "" ) ix = fH0->fXaxis.GetNbins() +1;
1067  if (fH0->fDimension > 1 ) {
1068  if (biny == 0 && TString(labelY) == "" ) iy = 0;
1069  if (biny == hist->fYaxis.GetNbins() +1 && TString(labelY) == "" ) iy = fH0->fYaxis.GetNbins() +1;
1070  }
1071  if (fH0->fDimension > 2 ) {
1072  if (binz == 0 && TString(labelZ) == "" ) iz = 0;
1073  if (binz == hist->fZaxis.GetNbins() +1 && TString(labelZ) == "" ) iz = fH0->fZaxis.GetNbins() +1;
1074  }
1075 
1076 
1077 
1078  // find corresponding case (in case bin is not overflow)
1079  // and see if for that axis we need to merge using labels or bin numbers
1080  if (ix == -1) {
1081  if (mergeLabelsX) {
1082  // std::cout << "find bin for label " << labelX << " " << fH0->GetBinContent(1,1,1) << " nbins "
1083  // << fH0->GetXaxis()->GetNbins() << std::endl;
1084  ix = fH0->fXaxis.FindBin(labelX);
1085  // std::cout << "bin for label " << ix << " " << fH0->GetBinContent(1,1,1) << " nbins "
1086  // << fH0->GetXaxis()->GetNbins() << std::endl;
1087  }
1088  else
1089  ix = FindFixBinNumber(binx, hist->fXaxis, fH0->fXaxis);
1090  }
1091 
1092  if (iy == -1 && fH0->fDimension> 1 ) { // check on dim should not be needed
1093  if (mergeLabelsY)
1094  iy= fH0->fYaxis.FindBin(labelY);
1095  else
1096  iy = FindFixBinNumber(biny, hist->fYaxis, fH0->fYaxis);
1097  }
1098  if (iz == -1 && fH0->fDimension> 2) {
1099  if (mergeLabelsZ)
1100  iz= fH0->fZaxis.FindBin(labelZ);
1101  else
1102  iz = FindFixBinNumber(binz, hist->fZaxis, fH0->fZaxis);
1103  }
1104 
1105  if (gDebug)
1106  Info("TH1Merge::LabelMerge","Merge bin [%d,%d,%d] with label [%s,%s,%s] into bin [%d,%d,%d]",
1107  binx,biny,binz,labelX,labelY,labelZ,ix,iy,iz);
1108 
1109 
1110  Int_t ib = fH0->GetBin(ix,iy,iz);
1111  if (ib < 0 || ib >= fH0->fNcells) {
1112  Fatal("TH1Merger::LabelMerge","Fatal error merging histogram %s - bin number is %d and array size is %d",
1113  fH0->GetName(), ib,fH0->fNcells);
1114  }
1115 
1116  MergeBin(hist, ibin, ib);
1117  }
1118  }
1119  //copy merged stats
1120  fH0->PutStats(totstats);
1122 
1123  return kTRUE;
1124 }
1125 
1126 /// helper function for merging
1127 
1128 Bool_t TH1Merger::IsBinEmpty(const TH1 * hist, Int_t ibin) {
1129  Double_t cu = hist->RetrieveBinContent(ibin);
1130  Double_t e1sq = (hist->fSumw2.fN) ? hist->GetBinErrorSqUnchecked(ibin) : cu;
1131  return cu == 0 && e1sq == 0;
1132 }
1133 
1134 // merge input bin (ibin) of histograms hist ibin into current bin cbin of this histogram
1135 void TH1Merger::MergeBin(const TH1 *hist, Int_t ibin, Int_t cbin)
1136 {
1137  if (!fIsProfileMerge) {
1138  Double_t cu = hist->RetrieveBinContent(ibin);
1139  fH0->AddBinContent(cbin, cu);
1140  if (fH0->fSumw2.fN) {
1141  Double_t e1sq = (hist->fSumw2.fN) ? hist->GetBinErrorSqUnchecked(ibin) : cu;
1142  fH0->fSumw2.fArray[cbin] += e1sq;
1143  }
1144  } else {
1145  if (fIsProfile1D)
1146  MergeProfileBin(static_cast<const TProfile *> (hist), ibin, cbin);
1147  else if (fIsProfile2D)
1148  MergeProfileBin(static_cast<const TProfile2D *> (hist), ibin, cbin);
1149  else if (fIsProfile3D)
1150  MergeProfileBin(static_cast<const TProfile3D *> (hist), ibin, cbin);
1151  }
1152  return;
1153 }
1154 
1155 // merge profile input bin (ibin) of histograms hist ibin into current bin cbin of this histogram
1156 template<class TProfileType>
1157 void TH1Merger::MergeProfileBin(const TProfileType *h, Int_t hbin, Int_t pbin)
1158 {
1159  TProfileType *p = static_cast<TProfileType *>(fH0);
1160  p->fArray[pbin] += h->fArray[hbin];
1161  p->fSumw2.fArray[pbin] += h->fSumw2.fArray[hbin];
1162  p->fBinEntries.fArray[pbin] += h->fBinEntries.fArray[hbin];
1163  if (p->fBinSumw2.fN) {
1164  if (h->fBinSumw2.fN)
1165  p->fBinSumw2.fArray[pbin] += h->fBinSumw2.fArray[hbin];
1166  else
1167  p->fBinSumw2.fArray[pbin] += h->fArray[hbin];
1168  }
1169  if (gDebug)
1170  Info("TH1Merge::MergeProfileBin", "Merge bin %d of profile %s with content %f in bin %d - result is %f", hbin,
1171  h->GetName(), h->fArray[hbin], pbin, p->fArray[pbin]);
1172 }
TH1Merger::kAutoP2HaveLimits
@ kAutoP2HaveLimits
Definition: TH1Merger.h:29
TH1::RetrieveBinContent
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:9280
TAxis
Class to manage histogram axis.
Definition: TAxis.h:30
TH1::GetSumw2N
virtual Int_t GetSumw2N() const
Definition: TH1.h:314
TH1Merger::IsBinEmpty
static Bool_t IsBinEmpty(const TH1 *hist, Int_t bin)
helper function for merging
Definition: TH1Merger.cxx:1128
TH1::Copy
virtual void Copy(TObject &hnew) const
Copy this histogram structure to newth1.
Definition: TH1.cxx:2663
kTRUE
const Bool_t kTRUE
Definition: RtypesCore.h:91
TObject::TestBit
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition: TObject.h:172
TH1Merger::AutoP2Merge
Bool_t AutoP2Merge()
Definition: TH1Merger.cxx:662
TH1Merger::MergeProfileBin
void MergeProfileBin(const TProfileType *p, Int_t ibin, Int_t outbin)
Definition: TH1Merger.cxx:1157
TH1Merger::AutoP2BuildAxes
Bool_t AutoP2BuildAxes(TH1 *)
Determine final boundaries and number of bins for histograms created in power-of-2 autobin mode.
Definition: TH1Merger.cxx:77
TH1::fYaxis
TAxis fYaxis
Y axis descriptor.
Definition: TH1.h:90
TList::AddFirst
virtual void AddFirst(TObject *obj)
Add object at the beginning of the list.
Definition: TList.cxx:100
TAxis::Set
virtual void Set(Int_t nbins, Double_t xmin, Double_t xmax)
Initialize axis with fix bins.
Definition: TAxis.cxx:731
TH1Merger::FindFixBinNumber
static Int_t FindFixBinNumber(Int_t ibin, const TAxis &inAxis, const TAxis &outAxis)
Definition: TH1Merger.h:35
TH1::SameLimitsAndNBins
static Bool_t SameLimitsAndNBins(const TAxis &axis1, const TAxis &axis2)
Same limits and bins.
Definition: TH1.cxx:5829
Warning
void Warning(const char *location, const char *msgfmt,...)
Use this function in warning situations.
Definition: TError.cxx:231
TCollection::GetEntries
virtual Int_t GetEntries() const
Definition: TCollection.h:177
TAxis::CanExtend
Bool_t CanExtend() const
Definition: TAxis.h:82
TH1Merger::fNoCheck
Bool_t fNoCheck
Definition: TH1Merger.h:133
TH1::fZaxis
TAxis fZaxis
Z axis descriptor.
Definition: TH1.h:91
TH1::kXaxis
@ kXaxis
Definition: TH1.h:72
TH1Merger::kAutoP2NeedLimits
@ kAutoP2NeedLimits
Definition: TH1Merger.h:30
xmax
float xmax
Definition: THbookFile.cxx:95
TH1Merger::HasDuplicateLabels
static Bool_t HasDuplicateLabels(const THashList *labels)
Find a duplicate labels in an axis label list.
Definition: TH1Merger.cxx:918
TH1Merger::MergeBin
void MergeBin(const TH1 *hist, Int_t inbin, Int_t outbin)
Definition: TH1Merger.cxx:1135
TH1Merger::BufferMerge
Bool_t BufferMerge()
Definition: TH1Merger.cxx:760
TProfile2D
Profile2D histograms are used to display the mean value of Z and its error for each cell in X,...
Definition: TProfile2D.h:27
TH1::SetBins
virtual void SetBins(Int_t nx, Double_t xmin, Double_t xmax)
Redefine x axis parameters.
Definition: TH1.cxx:8607
TH1Merger::kHasNewLimits
@ kHasNewLimits
Definition: TH1Merger.h:27
TH1Merger::kAllLabel
@ kAllLabel
Definition: TH1Merger.h:28
TAxis::GetFirst
Int_t GetFirst() const
Return first bin on the axis i.e.
Definition: TAxis.cxx:458
TGeant4Unit::s
static constexpr double s
Definition: TGeant4SystemOfUnits.h:162
Int_t
int Int_t
Definition: RtypesCore.h:45
TH1::SetCanExtend
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:6609
TH1::fBuffer
Double_t * fBuffer
[fBufferSize] entry buffer
Definition: TH1.h:107
TH1::GetEntries
virtual Double_t GetEntries() const
Return the current number of entries.
Definition: TH1.cxx:4386
TClass.h
nentries
int nentries
Definition: THbookFile.cxx:91
TIter::Reset
void Reset()
Definition: TCollection.h:252
TH1Merger::LabelMerge
Bool_t LabelMerge()
Merge histograms with labels.
Definition: TH1Merger.cxx:975
TH1Merger::fInputList
TList fInputList
copy of fH0 - managed by this class
Definition: TH1Merger.h:140
TMath::Abs
Short_t Abs(Short_t d)
Definition: TMathBase.h:120
TH1::fNcells
Int_t fNcells
number of bins(1D), cells (2D) +U/Overflows
Definition: TH1.h:88
TArray::fN
Int_t fN
Definition: TArray.h:38
TH1::kNoAxis
@ kNoAxis
NOTE: Must always be 0 !!!
Definition: TH1.h:71
TH1::fDimension
Int_t fDimension
!Histogram dimension (1, 2 or 3 dim)
Definition: TH1.h:109
TString
Basic string class.
Definition: TString.h:136
TH1::RecomputeAxisLimits
static Bool_t RecomputeAxisLimits(TAxis &destAxis, const TAxis &anAxis)
Finds new limits for the axis for the Merge function.
Definition: TH1.cxx:5839
TH1::GetZaxis
TAxis * GetZaxis()
Definition: TH1.h:322
bool
TH1::GetDimension
virtual Int_t GetDimension() const
Definition: TH1.h:282
TH1Merger::CopyBuffer
void CopyBuffer(TH1 *hsrc, TH1 *hdes)
Definition: TH1Merger.cxx:586
TH1Merger::DefineNewAxes
void DefineNewAxes()
Function to define new histogram axis when merging It is call only in case of merging with different ...
Definition: TH1Merger.cxx:520
TH1::Clone
TObject * Clone(const char *newname=0) const
Make a complete copy of the underlying object.
Definition: TH1.cxx:2740
TH1Merger::fH0
TH1 * fH0
Definition: TH1Merger.h:138
TH1Merger::fNewXAxis
TAxis fNewXAxis
Definition: TH1Merger.h:141
TAxis::GetLabels
THashList * GetLabels() const
Definition: TAxis.h:117
TH1Merger::fNewYAxis
TAxis fNewYAxis
Definition: TH1Merger.h:142
TH1Merger::kAllNoLimits
@ kAllNoLimits
Definition: TH1Merger.h:26
TH1::PutStats
virtual void PutStats(Double_t *stats)
Replace current statistics with the values in array stats.
Definition: TH1.cxx:7777
TAxis::SetRange
virtual void SetRange(Int_t first=0, Int_t last=0)
Set the viewing range for the axis using bin numbers.
Definition: TAxis.cxx:920
TArrayD::GetArray
const Double_t * GetArray() const
Definition: TArrayD.h:43
TAxis::GetXmin
Double_t GetXmin() const
Definition: TAxis.h:133
TObject::ResetBit
void ResetBit(UInt_t f)
Definition: TObject.h:171
TH1::GetYaxis
TAxis * GetYaxis()
Definition: TH1.h:321
xmin
float xmin
Definition: THbookFile.cxx:95
THashList
THashList implements a hybrid collection class consisting of a hash table and a list to store TObject...
Definition: THashList.h:34
TH3
The 3-D histogram classes derived from the 1-D histogram classes.
Definition: TH3.h:31
h
#define h(i)
Definition: RSha256.hxx:106
TObject::SetBit
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition: TObject.cxx:696
TH1Merger::CheckForDuplicateLabels
static Int_t CheckForDuplicateLabels(const TH1 *hist)
Check if histogram has duplicate labels Return an integer with bit set correponding on the axis that ...
Definition: TH1Merger.cxx:945
TH1::BufferEmpty
virtual Int_t BufferEmpty(Int_t action=0)
Fill histogram with all entries in the buffer.
Definition: TH1.cxx:1402
TH1::SetEntries
virtual void SetEntries(Double_t n)
Definition: TH1.h:385
epsilon
REAL epsilon
Definition: triangle.c:617
TH1Merger::DifferentAxesMerge
Bool_t DifferentAxesMerge()
Merged histogram when axis can be different.
Definition: TH1Merger.cxx:832
TH1Merger::fIsProfile3D
Bool_t fIsProfile3D
Definition: TH1Merger.h:137
TArrayD::Set
void Set(Int_t n)
Set size of this array to n doubles.
Definition: TArrayD.cxx:106
kFALSE
const Bool_t kFALSE
Definition: RtypesCore.h:92
Fatal
void Fatal(const char *location, const char *msgfmt,...)
Use this function in case of a fatal error. It will abort the program.
Definition: TError.cxx:245
TH1::GetBinCenter
virtual Double_t GetBinCenter(Int_t bin) const
Return bin center for 1D histogram.
Definition: TH1.cxx:8981
TH1::GetBin
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:4893
TH1::Fill
virtual Int_t Fill(Double_t x)
Increment bin with abscissa X by 1.
Definition: TH1.cxx:3350
TH1::GetBinErrorSqUnchecked
virtual Double_t GetBinErrorSqUnchecked(Int_t bin) const
Definition: TH1.h:443
TH2
Service class for 2-Dim histogram classes.
Definition: TH2.h:30
TAxis::GetLast
Int_t GetLast() const
Return last bin on the axis i.e.
Definition: TAxis.cxx:469
TH1::SetBinsLength
virtual void SetBinsLength(Int_t=-1)
Definition: TH1.h:375
gDebug
Int_t gDebug
Definition: TROOT.cxx:590
TH1Merger::fNewAxisFlag
UInt_t fNewAxisFlag
Definition: TH1Merger.h:144
TH1::SetDirectory
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:8777
TAxis::SetCanExtend
void SetCanExtend(Bool_t canExtend)
Definition: TAxis.h:86
TH1Merger::fNewZAxis
TAxis fNewZAxis
Definition: TH1Merger.h:143
TH1Merger::ExamineHistograms
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:216
TH2.h
TProfile3D
Profile3D histograms are used to display the mean value of T and its RMS for each cell in X,...
Definition: TProfile3D.h:27
TH1Merger::kNotCompatible
@ kNotCompatible
Definition: TH1Merger.h:24
TH1Merger::fIsProfileMerge
Bool_t fIsProfileMerge
Definition: TH1Merger.h:134
unsigned int
TH3.h
TH1Merger::SameAxesMerge
Bool_t SameAxesMerge()
Definition: TH1Merger.cxx:786
THashList.h
TProfile
Profile Histogram.
Definition: TProfile.h:32
TArrayD::fArray
Double_t * fArray
Definition: TArrayD.h:30
TH1Merger::fIsProfile1D
Bool_t fIsProfile1D
Definition: TH1Merger.h:135
Double_t
double Double_t
Definition: RtypesCore.h:59
TH1::GetStats
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:7726
R__ASSERT
#define R__ASSERT(e)
Definition: TError.h:120
TList::Remove
virtual TObject * Remove(TObject *obj)
Remove object from the list.
Definition: TList.cxx:822
TCollection::GetSize
virtual Int_t GetSize() const
Return the capacity of the collection, i.e.
Definition: TCollection.h:182
Info
void Info(const char *location, const char *msgfmt,...)
Use this function for informational messages.
Definition: TError.cxx:220
TH1::FindBin
virtual Int_t FindBin(Double_t x, Double_t y=0, Double_t z=0)
Return Global bin number corresponding to x,y,z.
Definition: TH1.cxx:3680
kMustCleanup
@ kMustCleanup
Definition: TObject.h:340
TH1::kZaxis
@ kZaxis
Definition: TH1.h:74
TH1Merger::AutoP2BufferMerge
Bool_t AutoP2BufferMerge()
Definition: TH1Merger.cxx:619
TH1::fSumw2
TArrayD fSumw2
Array of sum of squares of weights.
Definition: TH1.h:103
TList::Add
virtual void Add(TObject *obj)
Definition: TList.h:87
TAxis.h
TH1::Sumw2
virtual void Sumw2(Bool_t flag=kTRUE)
Create structure to store sum of squares of weights.
Definition: TH1.cxx:8860
TH1::Reset
virtual void Reset(Option_t *option="")
Reset this histogram: contents, errors, etc.
Definition: TH1.cxx:7069
TH1::AddBinContent
virtual void AddBinContent(Int_t bin)
Increment bin content by 1.
Definition: TH1.cxx:1257
TH1
TH1 is the base class of all histogram classes in ROOT.
Definition: TH1.h:58
ROOT::Experimental::Internal::swap
void swap(RDirectoryEntry &e1, RDirectoryEntry &e2) noexcept
Definition: RDirectoryEntry.hxx:94
TH1Merger::EMergerType
EMergerType
Definition: TH1Merger.h:23
TH1::fXaxis
TAxis fXaxis
X axis descriptor.
Definition: TH1.h:89
TAxis::FindBin
virtual Int_t FindBin(Double_t x)
Find bin number corresponding to abscissa x.
Definition: TAxis.cxx:293
TH1::IsEmpty
Bool_t IsEmpty() const
Check if an histogram is empty (this a protected method used mainly by TH1Merger )
Definition: TH1.cxx:5096
TH1Merger.h
TIter
Definition: TCollection.h:233
TH1Merger::operator()
Bool_t operator()()
Function performing the actual merge.
Definition: TH1Merger.cxx:27
TNamed::GetName
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:47
type
int type
Definition: TGX11.cxx:121
TAxis::GetXmax
Double_t GetXmax() const
Definition: TAxis.h:134
TH1::GetXaxis
TAxis * GetXaxis()
Get the behaviour adopted by the object about the statoverflows. See EStatOverflows for more informat...
Definition: TH1.h:320
TAxis::GetXbins
const TArrayD * GetXbins() const
Definition: TAxis.h:130
TH1Merger::fHClone
TH1 * fHClone
histogram on which the list is merged
Definition: TH1Merger.h:139
TH1Merger::fIsProfile2D
Bool_t fIsProfile2D
Definition: TH1Merger.h:136
TH1.h
TObject::ClassName
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition: TObject.cxx:130
TH1Merger::kAllSameAxes
@ kAllSameAxes
Definition: TH1Merger.h:25
TH1::kNstat
@ kNstat
Definition: TH1.h:183
TAxis::GetNbins
Int_t GetNbins() const
Definition: TAxis.h:121
TH1::kYaxis
@ kYaxis
Definition: TH1.h:73
TH1Merger::AxesHaveLimits
static Bool_t AxesHaveLimits(const TH1 *h)
Definition: TH1Merger.cxx:19
TArray::GetSize
Int_t GetSize() const
Definition: TArray.h:47
PRINTRANGE
#define PRINTRANGE(a, b, bn)
Definition: TH1Merger.cxx:15
TH1::kAutoBinPTwo
@ kAutoBinPTwo
Use Power(2)-based algorithm for autobinning.
Definition: TH1.h:173
int
Error
void Error(const char *location, const char *msgfmt,...)
Use this function in case an error occurred.
Definition: TError.cxx:187
TError.h
TH1Merger::fNoLabelMerge
Bool_t fNoLabelMerge
Definition: TH1Merger.h:132