Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
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);
121 if (re > std::numeric_limits<Double_t>::epsilon()) {
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 }
181 if (re > std::numeric_limits<Double_t>::epsilon()) {
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 }
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) {
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
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 }
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())
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
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
1135void 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
1156template<class TProfileType>
1157void 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}
#define h(i)
Definition RSha256.hxx:106
int Int_t
Definition RtypesCore.h:45
const Bool_t kFALSE
Definition RtypesCore.h:92
double Double_t
Definition RtypesCore.h:59
const Bool_t kTRUE
Definition RtypesCore.h:91
#define R__ASSERT(e)
Definition TError.h:120
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
int nentries
float xmax
@ kMustCleanup
Definition TObject.h:355
Int_t gDebug
Definition TROOT.cxx:590
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
virtual Int_t GetSize() const
Return the capacity of the collection, i.e.
Bool_t AutoP2BufferMerge()
static Bool_t AxesHaveLimits(const TH1 *h)
Definition TH1Merger.cxx:19
Bool_t AutoP2Merge()
static Int_t CheckForDuplicateLabels(const TH1 *hist)
Check if histogram has duplicate labels Return an integer with bit set correponding on the axis that ...
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.
Bool_t SameAxesMerge()
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)
Bool_t BufferMerge()
static Bool_t IsBinEmpty(const TH1 *hist, Int_t bin)
helper function for merging
EMergerType ExamineHistograms()
Examine the list of histograms to find out which type of Merge we need to do Pass the input list cont...
static Bool_t HasDuplicateLabels(const THashList *labels)
Find a duplicate labels in an axis label list.
void MergeBin(const TH1 *hist, Int_t inbin, Int_t outbin)
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
@ 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 ...
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.
TAxis fNewXAxis
Definition TH1Merger.h:141
void MergeProfileBin(const TProfileType *p, Int_t ibin, Int_t outbin)
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 an histogram is created, it is added to the list of histogram objects in the current ...
Definition TH1.cxx:8777
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:8981
TAxis * GetZaxis()
Definition TH1.h:322
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:7726
virtual void AddBinContent(Int_t bin)
Increment bin content by 1.
Definition TH1.cxx:1257
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:7069
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:5839
virtual void PutStats(Double_t *stats)
Replace current statistics with the values in array stats.
Definition TH1.cxx:7777
TObject * Clone(const char *newname=0) const
Make a complete copy of the underlying object.
Definition TH1.cxx:2740
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
static Bool_t SameLimitsAndNBins(const TAxis &axis1, const TAxis &axis2)
Same limits and bins.
Definition TH1.cxx:5829
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
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:3350
TAxis * GetYaxis()
Definition TH1.h:321
virtual Double_t GetBinErrorSqUnchecked(Int_t bin) const
Definition TH1.h:443
@ kNstat
Definition TH1.h:183
virtual Double_t GetEntries() const
Return the current number of entries.
Definition TH1.cxx:4386
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
virtual void Copy(TObject &hnew) const
Copy this histogram structure to newth1.
Definition TH1.cxx:2663
Bool_t IsEmpty() const
Check if an histogram is empty (this a protected method used mainly by TH1Merger )
Definition TH1.cxx:5096
@ 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
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:3680
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:8607
virtual void Sumw2(Bool_t flag=kTRUE)
Create structure to store sum of squares of weights.
Definition TH1.cxx:8860
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:1402
Service class for 2-Dim 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...
void Reset()
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
Short_t Abs(Short_t d)
Definition TMathBase.h:120