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
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;
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
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();
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(),
576 if (newLimitsY) Info("DefineNewAxis","A new Y axis has been defined Nbins=%d , [%f,%f]", fH0->fYaxis.GetNbins(),
578 if (newLimitsZ) Info("DefineNewAxis","A new Z axis has been defined Nbins=%d , [%f,%f]", fH0->fZaxis.GetNbins(),
580 }
581
582 return;
583
584}
585
586void 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 return;
596 }
597
598 // Entries from buffers have to be filled one by one
599 // because FillN doesn't resize histograms.
600 Int_t nbentries = (Int_t)hsrc->fBuffer[0];
601 if (hdes->fDimension == 1) {
602 for (Int_t i = 0; i < nbentries; i++)
603 hdes->Fill(hsrc->fBuffer[2 * i + 2], hsrc->fBuffer[2 * i + 1]);
604 }
605 if (hdes->fDimension == 2) {
606 auto h2 = dynamic_cast<TH2 *>(hdes);
607 R__ASSERT(h2);
608 for (Int_t i = 0; i < nbentries; i++)
609 h2->Fill(hsrc->fBuffer[3 * i + 2], hsrc->fBuffer[3 * i + 3], hsrc->fBuffer[3 * i + 1]);
610 }
611 if (hdes->fDimension == 3) {
612 auto h3 = dynamic_cast<TH3 *>(hdes);
613 R__ASSERT(h3);
614 for (Int_t i = 0; i < nbentries; i++)
615 h3->Fill(hsrc->fBuffer[4 * i + 2], hsrc->fBuffer[4 * i + 3], hsrc->fBuffer[4 * i + 4],
616 hsrc->fBuffer[4 * i + 1]);
617 }
618}
619
621{
622
623 TH1 *href = 0, *hist = 0;
624 TIter nextref(&fInputList);
626 href = fH0;
627 } else {
628 while ((hist = (TH1 *)nextref()) && !href) {
630 href = hist;
631 }
632 }
633 Bool_t resetfH0 = kFALSE;
634 if (!href) {
635 // Merge all histograms to fH0 and do a final projection
636 href = fH0;
637 } else {
638 if (href != fH0) {
639 // Temporary add fH0 to the list for buffer merging
641 resetfH0 = kTRUE;
642 }
643 }
644 TIter next(&fInputList);
645 while ((hist = (TH1 *)next())) {
646 if (!TH1Merger::AxesHaveLimits(hist) && hist->fBuffer) {
647 if (gDebug)
648 Info("AutoP2BufferMerge", "merging buffer of %s into %s", hist->GetName(), href->GetName());
649 CopyBuffer(hist, href);
650 fInputList.Remove(hist);
651 }
652 }
653 // Final projection
654 if (href->fBuffer)
655 href->BufferEmpty(1);
656 // Reset fH0, if already added, to avoid double counting
657 if (resetfH0)
658 fH0->Reset("ICES");
659 // Done, all histos have been processed
660 return kTRUE;
661}
662
664{
665
666 Double_t stats[TH1::kNstat], totstats[TH1::kNstat];
667 for (Int_t i = 0; i < TH1::kNstat; i++) {
668 totstats[i] = stats[i] = 0;
669 }
670
671 TIter next(&fInputList);
672 TH1 *hist = 0;
673 // Calculate boundaries and bins
674 Double_t xmin = 0., xmax = 0.;
675 if (!(fH0->IsEmpty())) {
676 hist = fH0;
677 } else {
678 while ((hist = (TH1 *)next())) {
679 if (!hist->IsEmpty())
680 break;
681 }
682 }
683
684 if (!hist) {
685 if (gDebug)
686 Info("TH1Merger::AutoP2Merge", "all histograms look empty!");
687 return kFALSE;
688 }
689
690 // Start building the axes from the reference histogram
691 if (!AutoP2BuildAxes(hist)) {
692 Error("TH1Merger::AutoP2Merge", "cannot create axes from %s", hist->GetName());
693 return kFALSE;
694 }
695 TH1 *h = 0;
696 while ((h = (TH1 *)next())) {
697 if (!AutoP2BuildAxes(h)) {
698 Error("TH1Merger::AutoP2Merge", "cannot merge histogram %s: not merge compatible", h->GetName());
699 return kFALSE;
700 }
701 }
704 Int_t nbins = fNewXAxis.GetNbins();
705
706 // Prepare stats
707 fH0->GetStats(totstats);
708 // Clone fH0 and add it to the list
709 if (!fH0->IsEmpty())
711
712 // reset fH0
713 fH0->Reset("ICES");
714 // Set the new boundaries
715 fH0->SetBins(nbins, xmin, xmax);
716
717 next.Reset();
718 Double_t nentries = 0.;
719 while ((hist = (TH1 *)next())) {
720 // process only if the histogram has limits; otherwise it was processed before
721 // in the case of an existing buffer (see if statement just before)
722
723 if (gDebug)
724 Info("TH1Merger::AutoP2Merge", "merging histogram %s into %s (entries: %f)", hist->GetName(), fH0->GetName(),
725 hist->GetEntries());
726
727 // skip empty histograms
728 if (hist->IsEmpty())
729 continue;
730
731 // import statistics
732 hist->GetStats(stats);
733 for (Int_t i = 0; i < TH1::kNstat; i++)
734 totstats[i] += stats[i];
735 nentries += hist->GetEntries();
736
737 // Int_t nx = hist->GetXaxis()->GetNbins();
738 // loop on bins of the histogram and do the merge
739 for (Int_t ibin = 0; ibin < hist->fNcells; ibin++) {
740
741 Double_t cu = hist->RetrieveBinContent(ibin);
742 Double_t e1sq = TMath::Abs(cu);
743 if (fH0->fSumw2.fN)
744 e1sq = hist->GetBinErrorSqUnchecked(ibin);
745
746 Double_t xu = hist->GetBinCenter(ibin);
747 Int_t jbin = fH0->FindBin(xu);
748
749 fH0->AddBinContent(jbin, cu);
750 if (fH0->fSumw2.fN)
751 fH0->fSumw2.fArray[jbin] += e1sq;
752 }
753 }
754 // copy merged stats
755 fH0->PutStats(totstats);
757
758 return kTRUE;
759}
760
762{
763
764 TIter next(&fInputList);
765 while (TH1* hist = (TH1*)next()) {
766 // support also case where some histogram have limits and some have the buffer
767 if ( !TH1Merger::AxesHaveLimits(hist) && hist->fBuffer ) {
768
769 if (gDebug)
770 Info("TH1Merger::BufferMerge","Merging histogram %s into %s",hist->GetName(), fH0->GetName() );
771 CopyBuffer(hist, fH0);
772 fInputList.Remove(hist);
773 }
774 }
775 // return true if the merge is completed
776 if (fInputList.GetSize() == 0) {
777 // all histo have been merged
778 return kTRUE;
779 }
780 // we need to reset the buffer in case of merging later on
781 // is this really needed ???
782 if (fH0->fBuffer) fH0->BufferEmpty(1);
783
784 return kFALSE;
785}
786
788
789
790 Double_t stats[TH1::kNstat], totstats[TH1::kNstat];
791 for (Int_t i=0;i<TH1::kNstat;i++) {
792 totstats[i] = stats[i] = 0;
793 }
794 fH0->GetStats(totstats);
796
797 TIter next(&fInputList);
798 while (TH1* hist=(TH1*)next()) {
799 // process only if the histogram has limits; otherwise it was processed before
800 // in the case of an existing buffer (see if statement just before)
801
802 if (gDebug)
803 Info("TH1Merger::SameAxesMerge","Merging histogram %s into %s",hist->GetName(), fH0->GetName() );
804
805 // skip empty histograms
806 if (hist->IsEmpty()) continue;
807
808 // import statistics
809 hist->GetStats(stats);
810 for (Int_t i=0; i<TH1::kNstat; i++)
811 totstats[i] += stats[i];
812 nentries += hist->GetEntries();
813
814 //Int_t nx = hist->GetXaxis()->GetNbins();
815 // loop on bins of the histogram and do the merge
816 for (Int_t ibin = 0; ibin < hist->fNcells; ibin++) {
817 MergeBin(hist, ibin, ibin);
818 }
819 }
820 //copy merged stats
821 fH0->PutStats(totstats);
823
824 return kTRUE;
825}
826
827
828/**
829 Merged histogram when axis can be different.
830 Histograms are merged looking at bin center positions
831
832 */
834
835 Double_t stats[TH1::kNstat], totstats[TH1::kNstat];
836 for (Int_t i=0;i<TH1::kNstat;i++) {totstats[i] = stats[i] = 0;}
837 fH0->GetStats(totstats);
839
840 TIter next(&fInputList);
841 while (TH1* hist=(TH1*)next()) {
842
843 if (gDebug)
844 Info("TH1Merger::DifferentAxesMerge","Merging histogram %s into %s",hist->GetName(), fH0->GetName() );
845
846 // skip empty histograms
847 if (hist->IsEmpty()) continue;
848
849 // import statistics
850 hist->GetStats(stats);
851 for (Int_t i=0;i<TH1::kNstat;i++)
852 totstats[i] += stats[i];
853 nentries += hist->GetEntries();
854
855 // loop on bins of the histogram and do the merge
856 for (Int_t ibin = 0; ibin < hist->fNcells; ibin++) {
857
858 // if bin is empty we can skip it
859 if (IsBinEmpty(hist,ibin)) continue;
860
861 Int_t binx,biny,binz;
862 hist->GetBinXYZ(ibin, binx, biny, binz);
863
864 // case of underflow/overflows in the histogram being merged
865 if (binx <= 0 || binx >= hist->GetNbinsX() + 1) {
866 if (fH0->fXaxis.CanExtend() || ( hist->fXaxis.GetBinCenter(binx) > fH0->fXaxis.GetXmin() && hist->fXaxis.GetBinCenter(binx) < fH0->fXaxis.GetXmax()) ) {
867 Error("TH1Merger::DifferentAxesMerge", "Cannot merge histograms - the histograms %s can extend the X axis or have"
868 " different limits and underflows/overflows are present in the histogram %s.",fH0->GetName(),hist->GetName());
869 return kFALSE;
870 }
871 }
872 if (biny <= 0 || biny >= hist->GetNbinsY() + 1) {
873 if (fH0->fYaxis.CanExtend() || ( hist->fYaxis.GetBinCenter(biny) > fH0->fYaxis.GetXmin() && hist->fYaxis.GetBinCenter(biny) < fH0->fYaxis.GetXmax()) ) {
874 Error("TH1Merger::DifferentAxesMerge", "Cannot merge histograms - the histograms %s can extend the Y axis or have"
875 " different limits and underflows/overflows are present in the histogram %s.",fH0->GetName(),hist->GetName());
876 return kFALSE;
877 }
878 }
879 if (binz <= 0 || binz >= hist->GetNbinsZ() + 1) {
880 if (fH0->fZaxis.CanExtend() || ( hist->fZaxis.GetBinCenter(binz) > fH0->fZaxis.GetXmin() && hist->fZaxis.GetBinCenter(binz) < fH0->fZaxis.GetXmax()) ) {
881 Error("TH1Merger::DifferentAxesMerge", "Cannot merge histograms - the histograms %s can extend the Z axis or have"
882 " different limits and underflows/overflows are present in the histogram %s.",fH0->GetName(),hist->GetName());
883 return kFALSE;
884 }
885 }
886
887 Int_t ix = 0;
888 Int_t iy = 0;
889 Int_t iz = 0;
890
891 // we can extend eventually the axis if histogram is capable of doing it
892 // by using FindBin
893 ix = fH0->fXaxis.FindBin(hist->GetXaxis()->GetBinCenter(binx));
894 if (fH0->fDimension > 1)
895 iy = fH0->fYaxis.FindBin(hist->GetYaxis()->GetBinCenter(biny));
896 if (fH0->fDimension > 2)
897 iz = fH0->fZaxis.FindBin(hist->GetZaxis()->GetBinCenter(binz));
898
899 Int_t ib = fH0->GetBin(ix,iy,iz);
900 if (ib < 0 || ib > fH0->fNcells) {
901 Fatal("TH1Merger::LabelMerge","Fatal error merging histogram %s - bin number is %d and array size is %d",
902 fH0->GetName(), ib,fH0->fNcells);
903 }
904
905 MergeBin(hist, ibin, ib);
906
907 }
908 }
909 //copy merged stats
910 fH0->PutStats(totstats);
912
913 return kTRUE;
914}
915
916/**
917 Find a duplicate labels in an axis label list
918*/
920
921 if (!labels) return kFALSE;
922
923 for (const auto * obj: *labels) {
924 auto objList = labels->GetListForObject(obj);
925 //objList->ls();
926 if (objList->GetSize() > 1 ) {
927 // check here if in the list we have duplicates
928 std::unordered_set<std::string> s;
929 for ( const auto * o: *objList) {
930 auto ret = s.insert(std::string(o->GetName() ));
931 if (!ret.second) return kTRUE;
932 }
933 }
934 }
935 return kFALSE;
936}
937
938/**
939 Check if histogram has duplicate labels
940 Return an integer with bit set correponding
941 on the axis that has duplicate labels
942 e.g. duplicate labels on x axis : return 1
943 duplicate labels on x and z axis : return 5
944
945*/
947
948 R__ASSERT(hist != nullptr);
949
950 auto labelsX = hist->GetXaxis()->GetLabels();
951 auto labelsY = hist->GetYaxis()->GetLabels();
952 auto labelsZ = hist->GetZaxis()->GetLabels();
953
954 Int_t res = 0;
955 if (HasDuplicateLabels(labelsX) ) {
956 Warning("TH1Merger::CheckForDuplicateLabels","Histogram %s has duplicate labels in the x axis. "
957 "Bin contents will be merged in a single bin",hist->GetName());
958 res |= 1;
959 }
960 if (HasDuplicateLabels(labelsY) ) {
961 Warning("TH1Merger::CheckForDuplicateLabels","Histogram %s has duplicate labels in the y axis. "
962 "Bin contents will be merged in a single bin",hist->GetName());
963 res |= 2;
964 }
965 if (HasDuplicateLabels(labelsZ) ) {
966 Warning("TH1Merger::CheckForDuplicateLabels","Histogram %s has duplicate labels in the z axis. "
967 "Bin contents will be merged in a single bin",hist->GetName());
968 res |= 4;
969 }
970 return res;
971}
972
973/**
974 Merge histograms with labels
975*/
977
978 Double_t stats[TH1::kNstat], totstats[TH1::kNstat];
979 for (Int_t i=0;i<TH1::kNstat;i++) {totstats[i] = stats[i] = 0;}
980 fH0->GetStats(totstats);
982
983 // check for duplicate labels
985
986 TIter next(&fInputList);
987 while (TH1* hist=(TH1*)next()) {
988
989 if (gDebug)
990 Info("TH1Merger::LabelMerge","Merging histogram %s into %s",hist->GetName(), fH0->GetName() );
991
992 // skip empty histograms
993 if (hist->IsEmpty()) continue;
994
995 // import statistics
996 hist->GetStats(stats);
997 for (Int_t i=0;i<TH1::kNstat;i++)
998 totstats[i] += stats[i];
999 nentries += hist->GetEntries();
1000
1001 auto labelsX = hist->GetXaxis()->GetLabels();
1002 auto labelsY = hist->GetYaxis()->GetLabels();
1003 auto labelsZ = hist->GetZaxis()->GetLabels();
1004 R__ASSERT(!( labelsX == nullptr && labelsY == nullptr && labelsZ == nullptr));
1005
1006 Bool_t mergeLabelsX = labelsX && fH0->fXaxis.CanExtend() && hist->fXaxis.CanExtend();
1007 Bool_t mergeLabelsY = labelsY && fH0->fYaxis.CanExtend() && hist->fYaxis.CanExtend();
1008 Bool_t mergeLabelsZ = labelsZ && fH0->fZaxis.CanExtend() && hist->fZaxis.CanExtend();
1009
1010 if (gDebug) {
1011 if (mergeLabelsX)
1012 Info("TH1Merger::LabelMerge","Merging X axis in label mode");
1013 else
1014 Info("TH1Merger::LabelMerge","Merging X axis in numeric mode");
1015 if (mergeLabelsY)
1016 Info("TH1Merger::LabelMerge","Merging Y axis in label mode");
1017 else if (hist->GetDimension() > 1)
1018 Info("TH1Merger::LabelMerge","Merging Y axis in numeric mode");
1019 if (mergeLabelsZ)
1020 Info("TH1Merger::LabelMerge","Merging Z axis in label mode" );
1021 else if (hist->GetDimension() > 2)
1022 Info("TH1Merger::LabelMerge","Merging Z axis in numeric mode");
1023 }
1024
1025 // check if histogram has duplicate labels
1026 if (!fNoCheck && hist->GetEntries() > 0) CheckForDuplicateLabels(hist);
1027
1028 // loop on bins of the histogram and do the merge
1029 if (gDebug) {
1030 // print bins original histogram
1031 std::cout << "Bins of original histograms\n";
1032 for (int ix = 1; ix <= fH0->GetXaxis()->GetNbins(); ++ix) {
1033 for (int iy = 1; iy <= fH0->GetYaxis()->GetNbins(); ++iy) {
1034 for (int iz = 1; iz <= fH0->GetZaxis()->GetNbins(); ++iz) {
1035 int i = fH0->GetBin(ix,iy,iz);
1036 std::cout << "bin" << ix << "," << iy << "," << iz
1037 << " : " << fH0->RetrieveBinContent(i) /* << " , " << fH0->fBinEntries.fArray[i] */ << std::endl;
1038 }
1039 }
1040 }
1041 }
1042 for (Int_t ibin = 0; ibin < hist->fNcells; ibin++) {
1043
1044 // if bin is empty we can skip it
1045 if (IsBinEmpty(hist,ibin)) continue;
1046
1047 Int_t binx,biny,binz;
1048 hist->GetBinXYZ(ibin, binx, biny, binz);
1049
1050 // here only in the case of bins with labels
1051 const char * labelX = 0;
1052 const char * labelY = 0;
1053 const char * labelZ = 0;
1054 labelX=hist->GetXaxis()->GetBinLabel(binx);
1055 if (fH0->fDimension > 1) labelY = hist->GetYaxis()->GetBinLabel(biny);
1056 if (fH0->fDimension > 2) labelZ = hist->GetYaxis()->GetBinLabel(binz);
1057 // do we need to support case when there are bins with labels and bins without them ??
1058 // this case should have been detected before when examining the histograms
1059
1060
1061 Int_t ix = -1;
1062 Int_t iy = (fH0->fDimension > 1) ? -1 : 0;
1063 Int_t iz = (fH0->fDimension > 2) ? -1 : 0;
1064
1065 // special case for underflow/overflows which have normally empty labels
1066 if (binx == 0 && TString(labelX) == "" ) ix = 0;
1067 if (binx == hist->fXaxis.GetNbins() +1 && TString(labelX) == "" ) ix = fH0->fXaxis.GetNbins() +1;
1068 if (fH0->fDimension > 1 ) {
1069 if (biny == 0 && TString(labelY) == "" ) iy = 0;
1070 if (biny == hist->fYaxis.GetNbins() +1 && TString(labelY) == "" ) iy = fH0->fYaxis.GetNbins() +1;
1071 }
1072 if (fH0->fDimension > 2 ) {
1073 if (binz == 0 && TString(labelZ) == "" ) iz = 0;
1074 if (binz == hist->fZaxis.GetNbins() +1 && TString(labelZ) == "" ) iz = fH0->fZaxis.GetNbins() +1;
1075 }
1076
1077
1078
1079 // find corresponding case (in case bin is not overflow)
1080 // and see if for that axis we need to merge using labels or bin numbers
1081 if (ix == -1) {
1082 if (mergeLabelsX) {
1083 // std::cout << "find bin for label " << labelX << " " << fH0->GetBinContent(1,1,1) << " nbins "
1084 // << fH0->GetXaxis()->GetNbins() << std::endl;
1085 ix = fH0->fXaxis.FindBin(labelX);
1086 // std::cout << "bin for label " << ix << " " << fH0->GetBinContent(1,1,1) << " nbins "
1087 // << fH0->GetXaxis()->GetNbins() << std::endl;
1088 }
1089 else
1090 ix = FindFixBinNumber(binx, hist->fXaxis, fH0->fXaxis);
1091 }
1092
1093 if (iy == -1 && fH0->fDimension> 1 ) { // check on dim should not be needed
1094 if (mergeLabelsY)
1095 iy= fH0->fYaxis.FindBin(labelY);
1096 else
1097 iy = FindFixBinNumber(biny, hist->fYaxis, fH0->fYaxis);
1098 }
1099 if (iz == -1 && fH0->fDimension> 2) {
1100 if (mergeLabelsZ)
1101 iz= fH0->fZaxis.FindBin(labelZ);
1102 else
1103 iz = FindFixBinNumber(binz, hist->fZaxis, fH0->fZaxis);
1104 }
1105
1106 if (gDebug)
1107 Info("TH1Merge::LabelMerge","Merge bin [%d,%d,%d] with label [%s,%s,%s] into bin [%d,%d,%d]",
1108 binx,biny,binz,labelX,labelY,labelZ,ix,iy,iz);
1109
1110
1111 Int_t ib = fH0->GetBin(ix,iy,iz);
1112 if (ib < 0 || ib >= fH0->fNcells) {
1113 Fatal("TH1Merger::LabelMerge","Fatal error merging histogram %s - bin number is %d and array size is %d",
1114 fH0->GetName(), ib,fH0->fNcells);
1115 }
1116
1117 MergeBin(hist, ibin, ib);
1118 }
1119 }
1120 //copy merged stats
1121 fH0->PutStats(totstats);
1123
1124 return kTRUE;
1125}
1126
1127/// helper function for merging
1128
1130 Double_t cu = hist->RetrieveBinContent(ibin);
1131 Double_t e1sq = (hist->fSumw2.fN) ? hist->GetBinErrorSqUnchecked(ibin) : cu;
1132 return cu == 0 && e1sq == 0;
1133}
1134
1135// merge input bin (ibin) of histograms hist ibin into current bin cbin of this histogram
1136void TH1Merger::MergeBin(const TH1 *hist, Int_t ibin, Int_t cbin)
1137{
1138 if (!fIsProfileMerge) {
1139 Double_t cu = hist->RetrieveBinContent(ibin);
1140 fH0->AddBinContent(cbin, cu);
1141 if (fH0->fSumw2.fN) {
1142 Double_t e1sq = (hist->fSumw2.fN) ? hist->GetBinErrorSqUnchecked(ibin) : cu;
1143 fH0->fSumw2.fArray[cbin] += e1sq;
1144 }
1145 } else {
1146 if (fIsProfile1D)
1147 MergeProfileBin(static_cast<const TProfile *> (hist), ibin, cbin);
1148 else if (fIsProfile2D)
1149 MergeProfileBin(static_cast<const TProfile2D *> (hist), ibin, cbin);
1150 else if (fIsProfile3D)
1151 MergeProfileBin(static_cast<const TProfile3D *> (hist), ibin, cbin);
1152 }
1153 return;
1154}
1155
1156// merge profile input bin (ibin) of histograms hist ibin into current bin cbin of this histogram
1157template<class TProfileType>
1158void TH1Merger::MergeProfileBin(const TProfileType *h, Int_t hbin, Int_t pbin)
1159{
1160 TProfileType *p = static_cast<TProfileType *>(fH0);
1161 p->fArray[pbin] += h->fArray[hbin];
1162 p->fSumw2.fArray[pbin] += h->fSumw2.fArray[hbin];
1163 p->fBinEntries.fArray[pbin] += h->fBinEntries.fArray[hbin];
1164 if (p->fBinSumw2.fN) {
1165 if (h->fBinSumw2.fN)
1166 p->fBinSumw2.fArray[pbin] += h->fBinSumw2.fArray[hbin];
1167 else
1168 p->fBinSumw2.fArray[pbin] += h->fArray[hbin];
1169 }
1170 if (gDebug)
1171 Info("TH1Merge::MergeProfileBin", "Merge bin %d of profile %s with content %f in bin %d - result is %f", hbin,
1172 h->GetName(), h->fArray[hbin], pbin, p->fArray[pbin]);
1173}
#define h(i)
Definition: RSha256.hxx:106
int Int_t
Definition: RtypesCore.h:45
unsigned int UInt_t
Definition: RtypesCore.h:46
const Bool_t kFALSE
Definition: RtypesCore.h:101
bool Bool_t
Definition: RtypesCore.h:63
double Double_t
Definition: RtypesCore.h:59
const Bool_t kTRUE
Definition: RtypesCore.h:100
#define R__ASSERT(e)
Definition: TError.h:118
void Info(const char *location, const char *msgfmt,...)
Use this function for informational messages.
Definition: TError.cxx:220
void Error(const char *location, const char *msgfmt,...)
Use this function in case an error occurred.
Definition: TError.cxx:187
void Warning(const char *location, const char *msgfmt,...)
Use this function in warning situations.
Definition: TError.cxx:231
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
int type
Definition: TGX11.cxx:121
#define PRINTRANGE(a, b, bn)
Definition: TH1Merger.cxx:15
float xmin
Definition: THbookFile.cxx:95
int nentries
Definition: THbookFile.cxx:91
float xmax
Definition: THbookFile.cxx:95
@ kMustCleanup
Definition: TObject.h:355
Int_t gDebug
Definition: TROOT.cxx:592
Double_t * fArray
Definition: TArrayD.h:30
void Set(Int_t n)
Set size of this array to n doubles.
Definition: TArrayD.cxx:106
const Double_t * GetArray() const
Definition: TArrayD.h:43
Int_t fN
Definition: TArray.h:38
Int_t GetSize() const
Definition: TArray.h:47
Class to manage histogram axis.
Definition: TAxis.h:30
Bool_t CanExtend() const
Definition: TAxis.h:82
const TArrayD * GetXbins() const
Definition: TAxis.h:130
void SetCanExtend(Bool_t canExtend)
Definition: TAxis.h:86
Double_t GetXmax() const
Definition: TAxis.h:134
virtual Int_t FindBin(Double_t x)
Find bin number corresponding to abscissa x.
Definition: TAxis.cxx:293
virtual void Set(Int_t nbins, Double_t xmin, Double_t xmax)
Initialize axis with fix bins.
Definition: TAxis.cxx:731
Int_t GetLast() const
Return last bin on the axis i.e.
Definition: TAxis.cxx:469
Double_t GetXmin() const
Definition: TAxis.h:133
Int_t GetNbins() const
Definition: TAxis.h:121
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
Int_t GetFirst() const
Return first bin on the axis i.e.
Definition: TAxis.cxx:458
THashList * GetLabels() const
Definition: TAxis.h:117
virtual Int_t GetEntries() const
Definition: TCollection.h:179
virtual Int_t GetSize() const
Return the capacity of the collection, i.e.
Definition: TCollection.h:184
Bool_t AutoP2BufferMerge()
Definition: TH1Merger.cxx:620
static Bool_t AxesHaveLimits(const TH1 *h)
Definition: TH1Merger.cxx:19
Bool_t AutoP2Merge()
Definition: TH1Merger.cxx:663
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:946
Bool_t AutoP2BuildAxes(TH1 *)
Determine final boundaries and number of bins for histograms created in power-of-2 autobin mode.
Definition: TH1Merger.cxx:77
Bool_t fIsProfileMerge
Definition: TH1Merger.h:134
Bool_t DifferentAxesMerge()
Merged histogram when axis can be different.
Definition: TH1Merger.cxx:833
Bool_t SameAxesMerge()
Definition: TH1Merger.cxx:787
TList fInputList
copy of fH0 - managed by this class
Definition: TH1Merger.h:140
Bool_t fNoLabelMerge
Definition: TH1Merger.h:132
static Int_t FindFixBinNumber(Int_t ibin, const TAxis &inAxis, const TAxis &outAxis)
Definition: TH1Merger.h:35
TH1 * fH0
Definition: TH1Merger.h:138
Bool_t fIsProfile3D
Definition: TH1Merger.h:137
TAxis fNewZAxis
Definition: TH1Merger.h:143
Bool_t fIsProfile1D
Definition: TH1Merger.h:135
void CopyBuffer(TH1 *hsrc, TH1 *hdes)
Definition: TH1Merger.cxx:586
Bool_t BufferMerge()
Definition: TH1Merger.cxx:761
static Bool_t IsBinEmpty(const TH1 *hist, Int_t bin)
helper function for merging
Definition: TH1Merger.cxx:1129
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
static Bool_t HasDuplicateLabels(const THashList *labels)
Find a duplicate labels in an axis label list.
Definition: TH1Merger.cxx:919
void MergeBin(const TH1 *hist, Int_t inbin, Int_t outbin)
Definition: TH1Merger.cxx:1136
Bool_t operator()()
Function performing the actual merge.
Definition: TH1Merger.cxx:27
Bool_t fIsProfile2D
Definition: TH1Merger.h:136
@ kAllNoLimits
Definition: TH1Merger.h:26
@ kNotCompatible
Definition: TH1Merger.h:24
@ kAutoP2NeedLimits
Definition: TH1Merger.h:30
@ kAllLabel
Definition: TH1Merger.h:28
@ kHasNewLimits
Definition: TH1Merger.h:27
@ kAutoP2HaveLimits
Definition: TH1Merger.h:29
@ kAllSameAxes
Definition: TH1Merger.h:25
void DefineNewAxes()
Function to define new histogram axis when merging It is call only in case of merging with different ...
Definition: TH1Merger.cxx:520
Bool_t fNoCheck
Definition: TH1Merger.h:133
TH1 * fHClone
histogram on which the list is merged
Definition: TH1Merger.h:139
UInt_t fNewAxisFlag
Definition: TH1Merger.h:144
Bool_t LabelMerge()
Merge histograms with labels.
Definition: TH1Merger.cxx:976
TAxis fNewXAxis
Definition: TH1Merger.h:141
void MergeProfileBin(const TProfileType *p, Int_t ibin, Int_t outbin)
Definition: TH1Merger.cxx:1158
TAxis fNewYAxis
Definition: TH1Merger.h:142
TH1 is the base class of all histogram classes in ROOT.
Definition: TH1.h:58
virtual void SetDirectory(TDirectory *dir)
By default, when a histogram is created, it is added to the list of histogram objects in the current ...
Definition: TH1.cxx:8780
Double_t * fBuffer
[fBufferSize] entry buffer
Definition: TH1.h:107
virtual Double_t GetBinCenter(Int_t bin) const
Return bin center for 1D histogram.
Definition: TH1.cxx:8984
TAxis * GetZaxis()
Definition: TH1.h:322
@ kXaxis
Definition: TH1.h:72
@ kNoAxis
NOTE: Must always be 0 !!!
Definition: TH1.h:71
@ kZaxis
Definition: TH1.h:74
@ kYaxis
Definition: TH1.h:73
Int_t fNcells
Number of bins(1D), cells (2D) +U/Overflows.
Definition: TH1.h:88
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:7721
virtual void AddBinContent(Int_t bin)
Increment bin content by 1.
Definition: TH1.cxx:1258
virtual Int_t GetDimension() const
Definition: TH1.h:282
@ kAutoBinPTwo
Use Power(2)-based algorithm for autobinning.
Definition: TH1.h:173
virtual void Reset(Option_t *option="")
Reset this histogram: contents, errors, etc.
Definition: TH1.cxx:7071
TAxis * GetXaxis()
Get the behaviour adopted by the object about the statoverflows. See EStatOverflows for more informat...
Definition: TH1.h:320
static Bool_t RecomputeAxisLimits(TAxis &destAxis, const TAxis &anAxis)
Finds new limits for the axis for the Merge function.
Definition: TH1.cxx:5841
virtual void PutStats(Double_t *stats)
Replace current statistics with the values in array stats.
Definition: TH1.cxx:7772
TObject * Clone(const char *newname=0) const
Make a complete copy of the underlying object.
Definition: TH1.cxx:2741
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:4894
static Bool_t SameLimitsAndNBins(const TAxis &axis1, const TAxis &axis2)
Same limits and bins.
Definition: TH1.cxx:5831
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:9283
Int_t fDimension
! Histogram dimension (1, 2 or 3 dim)
Definition: TH1.h:109
virtual void SetBinsLength(Int_t=-1)
Definition: TH1.h:375
virtual Int_t Fill(Double_t x)
Increment bin with abscissa X by 1.
Definition: TH1.cxx:3351
TAxis * GetYaxis()
Definition: TH1.h:321
virtual Double_t GetBinErrorSqUnchecked(Int_t bin) const
Definition: TH1.h:443
virtual Double_t GetEntries() const
Return the current number of entries.
Definition: TH1.cxx:4387
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:6611
virtual void Copy(TObject &hnew) const
Copy this histogram structure to newth1.
Definition: TH1.cxx:2664
Bool_t IsEmpty() const
Check if a histogram is empty (this is a protected method used mainly by TH1Merger )
Definition: TH1.cxx:5097
@ kNstat
Size of statistics data (up to TProfile3D)
Definition: TH1.h:183
TAxis fZaxis
Z axis descriptor.
Definition: TH1.h:91
TAxis fXaxis
X axis descriptor.
Definition: TH1.h:89
TArrayD fSumw2
Array of sum of squares of weights.
Definition: TH1.h:103
virtual Int_t GetSumw2N() const
Definition: TH1.h:314
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:3681
TAxis fYaxis
Y axis descriptor.
Definition: TH1.h:90
virtual void SetBins(Int_t nx, Double_t xmin, Double_t xmax)
Redefine x axis parameters.
Definition: TH1.cxx:8610
virtual void Sumw2(Bool_t flag=kTRUE)
Create structure to store sum of squares of weights.
Definition: TH1.cxx:8863
virtual void SetEntries(Double_t n)
Definition: TH1.h:385
virtual Int_t BufferEmpty(Int_t action=0)
Fill histogram with all entries in the buffer.
Definition: TH1.cxx:1403
Service class for 2-D histogram classes.
Definition: TH2.h:30
The 3-D histogram classes derived from the 1-D histogram classes.
Definition: TH3.h:31
THashList implements a hybrid collection class consisting of a hash table and a list to store TObject...
Definition: THashList.h:34
const TList * GetListForObject(const char *name) const
Return the THashTable's list (bucket) in which obj can be found based on its hash; see THashTable::Ge...
Definition: THashList.cxx:283
void Reset()
Definition: TCollection.h:254
virtual void Add(TObject *obj)
Definition: TList.h:87
virtual TObject * Remove(TObject *obj)
Remove object from the list.
Definition: TList.cxx:822
virtual void AddFirst(TObject *obj)
Add object at the beginning of the list.
Definition: TList.cxx:100
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:47
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition: TObject.h:187
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition: TObject.cxx:130
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition: TObject.cxx:696
void ResetBit(UInt_t f)
Definition: TObject.h:186
Profile2D histograms are used to display the mean value of Z and its error for each cell in X,...
Definition: TProfile2D.h:27
Profile3D histograms are used to display the mean value of T and its RMS for each cell in X,...
Definition: TProfile3D.h:27
Profile Histogram.
Definition: TProfile.h:32
Basic string class.
Definition: TString.h:136
void swap(RDirectoryEntry &e1, RDirectoryEntry &e2) noexcept
static constexpr double s
Short_t Abs(Short_t d)
Definition: TMathBase.h:120
REAL epsilon
Definition: triangle.c:618