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