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(), \
19 Bool_t TH1Merger::AxesHaveLimits(
const TH1 * h) {
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();
27 Bool_t TH1Merger::operator() () {
30 EMergerType type = ExamineHistograms();
32 if (gDebug) Info(
"Merge",
"Histogram Merge type is %d and new axis flag is %d",(
int) type,(
int) fNewAxisFlag);
34 if (type == kNotCompatible)
return kFALSE;
36 if (type == kAllSameAxes)
37 return SameAxesMerge();
39 if (type == kAllLabel)
42 if (type == kAllNoLimits)
45 if (type == kAutoP2HaveLimits || (type == kAutoP2NeedLimits && AutoP2BufferMerge()))
49 if (type == kHasNewLimits) {
53 Bool_t ret = BufferMerge();
55 if (ret)
return kTRUE;
57 return DifferentAxesMerge();
59 Error(
"TH1Merger",
"Unknown type of Merge for histogram %s",fH0->GetName());
77 Bool_t TH1Merger::AutoP2BuildAxes(TH1 *h)
81 Error(
"AutoP2BuildAxes",
"undefined histogram: %p", h);
86 if (!h->TestBit(TH1::kAutoBinPTwo)) {
87 Error(
"AutoP2BuildAxes",
"not in autobin-power-of-2 mode!");
92 TAxis *a0 = &fNewXAxis, *a1 = h->GetXaxis();
95 Bool_t canextend = (h->GetBinContent(0) > 0 || h->GetBinContent(a1->GetNbins() + 1) > 0) ? kFALSE : kTRUE;
98 if (a0->GetFirst() == a0->GetLast()) {
99 a0->Set(a1->GetNbins(), a1->GetXmin(), a1->GetXmax());
101 a0->SetCanExtend(canextend);
106 Double_t bwmax = (a0->GetXmax() - a0->GetXmin()) / a0->GetNbins();
107 Double_t bwmin = (a1->GetXmax() - a1->GetXmin()) / a1->GetNbins();
110 std::swap(bwmax, bwmin);
114 PRINTRANGE(a0, a1, h->GetName());
115 Error(
"AutoP2BuildAxes",
"minimal bin width negative or null: %f", bwmin);
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);
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");
137 xmax = a1->GetXmax();
138 xmin = a0->GetXmin();
139 domax = b0 ? kTRUE : kFALSE;
141 if (a0->GetXmax() >= a1->GetXmax()) {
142 xmax = a1->GetXmax();
143 xmin = a1->GetXmin();
144 domax = !b0 ? kTRUE : kFALSE;
146 xmax = a0->GetXmax();
147 xmin = a1->GetXmin();
148 domax = !b0 ? kTRUE : kFALSE;
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");
158 xmax = a0->GetXmax();
159 xmin = a1->GetXmin();
160 domax = !b0 ? kTRUE : kFALSE;
162 if (a1->GetXmax() >= a0->GetXmax()) {
163 xmax = a0->GetXmax();
164 xmin = a0->GetXmin();
165 domax = b0 ? kTRUE : kFALSE;
167 xmax = a1->GetXmax();
168 xmin = a0->GetXmin();
169 domax = b0 ? kTRUE : kFALSE;
173 Double_t range = xmax - xmin;
175 re = std::modf(range / bwmax, &rt);
177 PRINTRANGE(a0, a1, h->GetName());
178 Error(
"MergeCompatibleHistograms",
"range smaller than bin width: %f %f %f", range, bwmax, rt);
181 if (re > std::numeric_limits<Double_t>::epsilon()) {
189 Int_t nb = (Int_t)rt;
192 a0->Set(nb, xmin, xmax);
195 if (!a0->CanExtend())
196 a0->SetCanExtend(canextend);
216 TH1Merger::EMergerType TH1Merger::ExamineHistograms() {
220 Bool_t initialLimitsFound = kFALSE;
221 Bool_t allHaveLabels = kTRUE;
222 Bool_t allHaveLimits = kTRUE;
223 Bool_t allSameLimits = kTRUE;
224 Bool_t sameLimitsX = kTRUE;
225 Bool_t sameLimitsY = kTRUE;
226 Bool_t sameLimitsZ = kTRUE;
227 Bool_t foundLabelHist = kFALSE;
228 Bool_t haveWeights = kFALSE;
230 Bool_t isAutoP2 = kFALSE;
236 TIter next(&fInputList);
239 int dimension = fH0->GetDimension();
241 isAutoP2 = fH0->TestBit(TH1::kAutoBinPTwo) ? kTRUE : kFALSE;
245 if (fNoLabelMerge) allHaveLabels = kFALSE;
253 if (h->GetDimension() != dimension) {
254 Error(
"Merge",
"Cannot merge histogram - dimensions are different\n "
255 "%s has dim=%d and %s has dim=%d",fH0->GetName(),dimension,h->GetName(),h->GetDimension());
256 return kNotCompatible;
261 haveWeights |= h->GetSumw2N() != 0;
265 Bool_t hasLimits = TH1Merger::AxesHaveLimits(h);
266 allHaveLimits = allHaveLimits && hasLimits;
267 allSameLimits &= allHaveLimits;
269 if (isAutoP2 && !h->TestBit(TH1::kAutoBinPTwo)) {
270 Error(
"Merge",
"Cannot merge histogram - some are in autobin-power-of-2 mode, but not %s!", h->GetName());
271 return kNotCompatible;
273 if (!isAutoP2 && h->TestBit(TH1::kAutoBinPTwo)) {
274 Error(
"Merge",
"Cannot merge histogram - %s is in autobin-power-of-2 mode, but not the previous ones",
276 return kNotCompatible;
297 if (!initialLimitsFound) {
298 initialLimitsFound = kTRUE;
299 if (h->GetXaxis()->GetXbins()->GetSize() != 0)
300 fNewXAxis.Set(h->GetXaxis()->GetNbins(), h->GetXaxis()->GetXbins()->GetArray());
302 fNewXAxis.Set(h->GetXaxis()->GetNbins(), h->GetXaxis()->GetXmin(), h->GetXaxis()->GetXmax());
304 if (h->GetYaxis()->GetXbins()->GetSize() != 0)
305 fNewYAxis.Set(h->GetYaxis()->GetNbins(), h->GetYaxis()->GetXbins()->GetArray());
307 fNewYAxis.Set(h->GetYaxis()->GetNbins(), h->GetYaxis()->GetXmin(), h->GetYaxis()->GetXmax());
310 if (h->GetZaxis()->GetXbins()->GetSize() != 0)
311 fNewZAxis.Set(h->GetZaxis()->GetNbins(), h->GetZaxis()->GetXbins()->GetArray());
313 fNewZAxis.Set(h->GetZaxis()->GetNbins(), h->GetZaxis()->GetXmin(), h->GetZaxis()->GetXmax());
319 if (!TH1::SameLimitsAndNBins(fNewXAxis, *(h->GetXaxis())) ) {
320 sameLimitsX = kFALSE;
324 if (!TH1::RecomputeAxisLimits(fNewXAxis, *(h->GetXaxis()))) {
325 Error(
"Merge",
"Cannot merge histograms - limits are inconsistent:\n "
326 "first: %s (%d, %f, %f), second: %s (%d, %f, %f)", fH0->GetName(),
327 fNewXAxis.GetNbins(), fNewXAxis.GetXmin(), fNewXAxis.GetXmax(),
328 h->GetName(),h->GetXaxis()->GetNbins(), h->GetXaxis()->GetXmin(),
329 h->GetXaxis()->GetXmax());
330 return kNotCompatible;
334 if (dimension > 1 && !TH1::SameLimitsAndNBins(fNewYAxis, *(h->GetYaxis()))) {
335 sameLimitsY = kFALSE;
339 if (!TH1::RecomputeAxisLimits(fNewYAxis, *(h->GetYaxis()))) {
340 Error(
"Merge",
"Cannot merge histograms - limits are inconsistent:\n "
341 "first: %s (%d, %f, %f), second: %s (%d, %f, %f)", fH0->GetName(),
342 fNewYAxis.GetNbins(), fNewYAxis.GetXmin(), fNewYAxis.GetXmax(),
343 h->GetName(), h->GetYaxis()->GetNbins(), h->GetYaxis()->GetXmin(),
344 h->GetYaxis()->GetXmax());
345 return kNotCompatible;
348 if(dimension > 2 && !fH0->SameLimitsAndNBins(fNewZAxis, *(h->GetZaxis()))) {
349 sameLimitsZ = kFALSE;
350 if (!TH1::RecomputeAxisLimits(fNewZAxis, *(h->GetZaxis()))) {
351 Error(
"Merge",
"Cannot merge histograms - limits are inconsistent:\n "
352 "first: %s (%d, %f, %f), second: %s (%d, %f, %f)", fH0->GetName(),
353 fNewZAxis.GetNbins(), fNewZAxis.GetXmin(), fNewZAxis.GetXmax(),
354 h->GetName(),h->GetZaxis()->GetNbins(), h->GetZaxis()->GetXmin(),
355 h->GetZaxis()->GetXmax());
356 return kNotCompatible;
359 allSameLimits = sameLimitsX && sameLimitsY && sameLimitsZ;
364 Bool_t histoIsEmpty = h->IsEmpty();
369 if (allHaveLabels && !histoIsEmpty) {
370 THashList* hlabels=h->GetXaxis()->GetLabels();
371 Bool_t haveOneLabel = (hlabels !=
nullptr);
373 if (foundLabelHist && allHaveLabels && !haveOneLabel) {
374 Warning(
"Merge",
"Not all histograms have labels. I will ignore labels,"
375 " falling back to bin numbering mode.");
378 allHaveLabels &= (haveOneLabel);
380 if (haveOneLabel) foundLabelHist = kTRUE;
382 if (foundLabelHist && gDebug)
383 Info(
"TH1Merger::ExamineHistogram",
"Histogram %s has labels",h->GetName() );
387 if (allHaveLabels && !fH0->CanExtendAllAxes()) {
390 if ( fH0->IsEmpty() ) {
392 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());
393 UInt_t bitMaskX = fH0->GetXaxis()->CanBeAlphanumeric() & TH1::kXaxis;
394 UInt_t bitMaskY = (fH0->GetYaxis()->CanBeAlphanumeric() << 1 ) & TH1::kYaxis;
395 UInt_t bitMaskZ = (fH0->GetZaxis()->CanBeAlphanumeric() << 2 ) & TH1::kZaxis;
396 fH0->SetCanExtend(bitMaskX | bitMaskY | bitMaskZ );
398 if (!fH0->CanExtendAllAxes()) {
400 Info(
"TH1Merger::ExamineHistogram",
"Histogram %s to be merged has label but axis cannot be extended - using bin numeric mode to merge. Call TH1::SetExtendAllAxes() if want to merge using label mode",fH0->GetName());
401 allHaveLabels = kFALSE;
408 if (allHaveLabels && !h->CanExtendAllAxes()) {
410 Int_t non_zero_bins = 0;
411 Int_t nbins = h->GetXaxis()->GetNbins();
412 if (nbins > hlabels->GetEntries() ) {
413 for (Int_t i = 1; i <= nbins; i++) {
414 if (h->RetrieveBinContent(i) != 0 || (fH0->fSumw2.fN && h->GetBinError(i) != 0) ) {
418 if (non_zero_bins > hlabels->GetEntries() ) {
419 Warning(
"TH1Merger::ExamineHistograms",
"Histogram %s contains non-empty bins without labels - falling back to bin numbering mode",h->GetName() );
420 allHaveLabels = kFALSE;
426 Info(
"TH1Merger::ExamineHistogram",
"Examine histogram %s - labels %d - same limits %d - axis found %d",h->GetName(),allHaveLabels,allSameLimits,initialLimitsFound );
428 }
while ( ( h = dynamic_cast<TH1*> ( next() ) ) != NULL );
430 if (!h && (*next) ) {
431 Error(
"Merge",
"Attempt to merge object of class: %s to a %s",
432 (*next)->ClassName(),fH0->ClassName());
433 return kNotCompatible;
437 if (haveWeights && fH0->GetSumw2N() == 0)
443 return kAutoP2HaveLimits;
444 return kAutoP2NeedLimits;
448 if (allHaveLabels)
return kAllLabel;
449 if (allSameLimits)
return kAllSameAxes;
450 if (!initialLimitsFound) {
451 R__ASSERT(!allHaveLimits);
457 if (!sameLimitsX) fNewAxisFlag |= TH1::kXaxis;
458 if (!sameLimitsY) fNewAxisFlag |= TH1::kYaxis;
459 if (!sameLimitsZ) fNewAxisFlag |= TH1::kZaxis;
463 if (fH0->GetXaxis()->GetXmin() >= fH0->GetXaxis()->GetXmax()) fNewAxisFlag |= TH1::kXaxis;
464 if (dimension > 1 && fH0->GetYaxis()->GetXmin() >= fH0->GetYaxis()->GetXmax()) fNewAxisFlag |= TH1::kYaxis;
465 if (dimension > 2 && fH0->GetZaxis()->GetXmin() >= fH0->GetZaxis()->GetXmax()) fNewAxisFlag |= TH1::kZaxis;
468 return kHasNewLimits;
478 void TH1Merger::DefineNewAxes() {
482 if (!fH0->IsEmpty() ) {
483 Bool_t mustCleanup = fH0->TestBit(kMustCleanup);
484 if (mustCleanup) fH0->ResetBit(kMustCleanup);
485 fHClone = (TH1*)fH0->IsA()->New();
486 fHClone->SetDirectory(0);
488 if (mustCleanup) fH0->SetBit(kMustCleanup);
492 fInputList.AddFirst(fHClone);
496 bool newLimitsX = (fNewAxisFlag & TH1::kXaxis);
497 bool newLimitsY = (fNewAxisFlag & TH1::kYaxis);
498 bool newLimitsZ = (fNewAxisFlag & TH1::kZaxis);
500 fH0->fXaxis.SetRange(0,0);
501 if (fNewXAxis.GetXbins()->GetSize() != 0)
502 fH0->fXaxis.Set(fNewXAxis.GetNbins(),fNewXAxis.GetXbins()->GetArray());
504 fH0->fXaxis.Set(fNewXAxis.GetNbins(),fNewXAxis.GetXmin(), fNewXAxis.GetXmax());
507 fH0->fYaxis.SetRange(0,0);
508 if (fNewYAxis.GetXbins()->GetSize() != 0)
509 fH0->fYaxis.Set(fNewYAxis.GetNbins(),fNewYAxis.GetXbins()->GetArray());
511 fH0->fYaxis.Set(fNewYAxis.GetNbins(),fNewYAxis.GetXmin(), fNewYAxis.GetXmax());
514 fH0->fZaxis.SetRange(0,0);
515 if (fNewZAxis.GetXbins()->GetSize() != 0)
516 fH0->fZaxis.Set(fNewZAxis.GetNbins(),fNewZAxis.GetXbins()->GetArray());
518 fH0->fZaxis.Set(fNewZAxis.GetNbins(),fNewZAxis.GetXmin(), fNewZAxis.GetXmax());
522 fH0->fNcells = fH0->fXaxis.GetNbins()+2;
523 if (fH0->fDimension > 1) fH0->fNcells *= fH0->fYaxis.GetNbins()+2;
524 if (fH0->fDimension > 2) fH0->fNcells *= fH0->fZaxis.GetNbins()+2;
525 fH0->SetBinsLength(fH0->fNcells);
526 if (fH0->fSumw2.fN) fH0->fSumw2.Set(fH0->fNcells);
528 if (fH0->fDimension < 3) fH0->fZaxis.Set(1,0,1);
529 if (fH0->fDimension < 2) fH0->fYaxis.Set(1,0,1);
532 if (newLimitsX) Info(
"DefineNewAxis",
"A new X axis has been defined Nbins=%d , [%f,%f]", fH0->fXaxis.GetNbins(),
533 fH0->fXaxis.GetXmin(), fH0->fXaxis.GetXmax() );
534 if (newLimitsY) Info(
"DefineNewAxis",
"A new Y axis has been defined Nbins=%d , [%f,%f]", fH0->fYaxis.GetNbins(),
535 fH0->fYaxis.GetXmin(), fH0->fYaxis.GetXmax() );
536 if (newLimitsZ) Info(
"DefineNewAxis",
"A new Z axis has been defined Nbins=%d , [%f,%f]", fH0->fZaxis.GetNbins(),
537 fH0->fZaxis.GetXmin(), fH0->fZaxis.GetXmax() );
544 void TH1Merger::CopyBuffer(TH1 *hsrc, TH1 *hdes)
548 if (!hsrc || !hsrc->fBuffer || !hdes ) {
549 void *p1 = hsrc ? hsrc->fBuffer : 0;
552 Warning(
"TH1Merger::CopyMerge",
"invalid inputs: %p, %p, %p, -> do nothing", hsrc, hdes, p1);
557 Int_t nbentries = (Int_t)hsrc->fBuffer[0];
558 if (hdes->fDimension == 1) {
559 for (Int_t i = 0; i < nbentries; i++)
560 hdes->Fill(hsrc->fBuffer[2 * i + 2], hsrc->fBuffer[2 * i + 1]);
562 if (hdes->fDimension == 2) {
563 auto h2 =
dynamic_cast<TH2 *
>(hdes);
565 for (Int_t i = 0; i < nbentries; i++)
566 h2->Fill(hsrc->fBuffer[3 * i + 2], hsrc->fBuffer[3 * i + 3], hsrc->fBuffer[3 * i + 1]);
568 if (hdes->fDimension == 3) {
569 auto h3 =
dynamic_cast<TH3 *
>(hdes);
571 for (Int_t i = 0; i < nbentries; i++)
572 h3->Fill(hsrc->fBuffer[4 * i + 2], hsrc->fBuffer[4 * i + 3], hsrc->fBuffer[4 * i + 4],
573 hsrc->fBuffer[4 * i + 1]);
577 Bool_t TH1Merger::AutoP2BufferMerge()
580 TH1 *href = 0, *hist = 0;
581 TIter nextref(&fInputList);
582 if (TH1Merger::AxesHaveLimits(fH0)) {
585 while ((hist = (TH1 *)nextref()) && !href) {
586 if (TH1Merger::AxesHaveLimits(hist))
590 Bool_t resetfH0 = kFALSE;
601 TIter next(&fInputList);
602 while ((hist = (TH1 *)next())) {
603 if (!TH1Merger::AxesHaveLimits(hist) && hist->fBuffer) {
605 Info(
"AutoP2BufferMerge",
"merging buffer of %s into %s", hist->GetName(), href->GetName());
606 CopyBuffer(hist, href);
607 fInputList.Remove(hist);
612 href->BufferEmpty(1);
620 Bool_t TH1Merger::AutoP2Merge()
623 Double_t stats[TH1::kNstat], totstats[TH1::kNstat];
624 for (Int_t i = 0; i < TH1::kNstat; i++) {
625 totstats[i] = stats[i] = 0;
628 TIter next(&fInputList);
631 Double_t xmin = 0., xmax = 0.;
632 if (!(fH0->IsEmpty())) {
635 while ((hist = (TH1 *)next())) {
636 if (!hist->IsEmpty())
643 Info(
"TH1Merger::AutoP2Merge",
"all histograms look empty!");
648 if (!AutoP2BuildAxes(hist)) {
649 Error(
"TH1Merger::AutoP2Merge",
"cannot create axes from %s", hist->GetName());
653 while ((h = (TH1 *)next())) {
654 if (!AutoP2BuildAxes(h)) {
655 Error(
"TH1Merger::AutoP2Merge",
"cannot merge histogram %s: not merge compatible", h->GetName());
659 xmin = fNewXAxis.GetXmin();
660 xmax = fNewXAxis.GetXmax();
661 Int_t nbins = fNewXAxis.GetNbins();
664 fH0->GetStats(totstats);
667 fInputList.Add(fH0->Clone());
672 fH0->SetBins(nbins, xmin, xmax);
675 Double_t nentries = 0.;
676 while ((hist = (TH1 *)next())) {
681 Info(
"TH1Merger::AutoP2Merge",
"merging histogram %s into %s (entries: %f)", hist->GetName(), fH0->GetName(),
689 hist->GetStats(stats);
690 for (Int_t i = 0; i < TH1::kNstat; i++)
691 totstats[i] += stats[i];
692 nentries += hist->GetEntries();
696 for (Int_t ibin = 0; ibin < hist->fNcells; ibin++) {
698 Double_t cu = hist->RetrieveBinContent(ibin);
699 Double_t e1sq = TMath::Abs(cu);
701 e1sq = hist->GetBinErrorSqUnchecked(ibin);
703 Double_t xu = hist->GetBinCenter(ibin);
704 Int_t jbin = fH0->FindBin(xu);
706 fH0->AddBinContent(jbin, cu);
708 fH0->fSumw2.fArray[jbin] += e1sq;
712 fH0->PutStats(totstats);
713 fH0->SetEntries(nentries);
718 Bool_t TH1Merger::BufferMerge()
721 TIter next(&fInputList);
722 while (TH1* hist = (TH1*)next()) {
724 if ( !TH1Merger::AxesHaveLimits(hist) && hist->fBuffer ) {
727 Info(
"TH1Merger::BufferMerge",
"Merging histogram %s into %s",hist->GetName(), fH0->GetName() );
728 CopyBuffer(hist, fH0);
729 fInputList.Remove(hist);
733 if (fInputList.GetSize() == 0) {
739 if (fH0->fBuffer) fH0->BufferEmpty(1);
744 Bool_t TH1Merger::SameAxesMerge() {
747 Double_t stats[TH1::kNstat], totstats[TH1::kNstat];
748 for (Int_t i=0;i<TH1::kNstat;i++) {
749 totstats[i] = stats[i] = 0;
751 fH0->GetStats(totstats);
752 Double_t nentries = fH0->GetEntries();
754 TIter next(&fInputList);
755 while (TH1* hist=(TH1*)next()) {
760 Info(
"TH1Merger::SameAxesMerge",
"Merging histogram %s into %s",hist->GetName(), fH0->GetName() );
763 if (hist->IsEmpty())
continue;
766 hist->GetStats(stats);
767 for (Int_t i=0; i<TH1::kNstat; i++)
768 totstats[i] += stats[i];
769 nentries += hist->GetEntries();
773 for (Int_t ibin = 0; ibin < hist->fNcells; ibin++) {
775 Double_t cu = hist->RetrieveBinContent(ibin);
776 Double_t e1sq = TMath::Abs(cu);
777 if (fH0->fSumw2.fN) e1sq= hist->GetBinErrorSqUnchecked(ibin);
779 fH0->AddBinContent(ibin,cu);
780 if (fH0->fSumw2.fN) fH0->fSumw2.fArray[ibin] += e1sq;
785 fH0->PutStats(totstats);
786 fH0->SetEntries(nentries);
797 Bool_t TH1Merger::DifferentAxesMerge() {
799 Double_t stats[TH1::kNstat], totstats[TH1::kNstat];
800 for (Int_t i=0;i<TH1::kNstat;i++) {totstats[i] = stats[i] = 0;}
801 fH0->GetStats(totstats);
802 Double_t nentries = fH0->GetEntries();
804 TIter next(&fInputList);
805 while (TH1* hist=(TH1*)next()) {
808 Info(
"TH1Merger::DifferentAxesMerge",
"Merging histogram %s into %s",hist->GetName(), fH0->GetName() );
811 if (hist->IsEmpty())
continue;
814 hist->GetStats(stats);
815 for (Int_t i=0;i<TH1::kNstat;i++)
816 totstats[i] += stats[i];
817 nentries += hist->GetEntries();
820 for (Int_t ibin = 0; ibin < hist->fNcells; ibin++) {
822 Double_t cu = hist->RetrieveBinContent(ibin);
823 Double_t e1sq = TMath::Abs(cu);
824 if (fH0->fSumw2.fN) e1sq= hist->GetBinErrorSqUnchecked(ibin);
827 if (cu == 0 && e1sq == 0)
continue;
829 Int_t binx,biny,binz;
830 hist->GetBinXYZ(ibin, binx, biny, binz);
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());
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());
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());
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));
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);
873 fH0->AddBinContent(ib,cu);
874 if (fH0->fSumw2.fN) fH0->fSumw2.fArray[ib] += e1sq;
878 fH0->PutStats(totstats);
879 fH0->SetEntries(nentries);
887 Bool_t TH1Merger::HasDuplicateLabels(
const THashList * labels) {
889 if (!labels)
return kFALSE;
891 for (
const auto * obj: *labels) {
892 auto objList = labels->GetListForObject(obj);
894 if (objList->GetSize() > 1 ) {
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;
914 Int_t TH1Merger::CheckForDuplicateLabels(
const TH1 * hist) {
916 R__ASSERT(hist !=
nullptr);
918 auto labelsX = hist->GetXaxis()->GetLabels();
919 auto labelsY = hist->GetYaxis()->GetLabels();
920 auto labelsZ = hist->GetZaxis()->GetLabels();
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());
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());
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());
944 Bool_t TH1Merger::LabelMerge() {
946 Double_t stats[TH1::kNstat], totstats[TH1::kNstat];
947 for (Int_t i=0;i<TH1::kNstat;i++) {totstats[i] = stats[i] = 0;}
948 fH0->GetStats(totstats);
949 Double_t nentries = fH0->GetEntries();
952 if (!fNoCheck && nentries > 0) CheckForDuplicateLabels(fH0);
954 TIter next(&fInputList);
955 while (TH1* hist=(TH1*)next()) {
958 Info(
"TH1Merger::LabelMerge",
"Merging histogram %s into %s",hist->GetName(), fH0->GetName() );
961 if (hist->IsEmpty())
continue;
964 hist->GetStats(stats);
965 for (Int_t i=0;i<TH1::kNstat;i++)
966 totstats[i] += stats[i];
967 nentries += hist->GetEntries();
969 auto labelsX = hist->GetXaxis()->GetLabels();
970 auto labelsY = hist->GetYaxis()->GetLabels();
971 auto labelsZ = hist->GetZaxis()->GetLabels();
972 R__ASSERT(!( labelsX ==
nullptr && labelsY ==
nullptr && labelsZ ==
nullptr));
975 if (!fNoCheck && hist->GetEntries() > 0) CheckForDuplicateLabels(hist);
978 for (Int_t ibin = 0; ibin < hist->fNcells; ibin++) {
980 Double_t cu = hist->RetrieveBinContent(ibin);
982 if (fH0->fSumw2.fN) e1sq= hist->GetBinErrorSqUnchecked(ibin);
985 if (cu == 0 && e1sq == 0)
continue;
987 Int_t binx,biny,binz;
988 hist->GetBinXYZ(ibin, binx, biny, binz);
991 const char * labelX = 0;
992 const char * labelY = 0;
993 const char * labelZ = 0;
994 labelX=hist->GetXaxis()->GetBinLabel(binx);
995 if (fH0->fDimension > 1) labelY = hist->GetYaxis()->GetBinLabel(biny);
996 if (fH0->fDimension > 2) labelZ = hist->GetYaxis()->GetBinLabel(binz);
1002 Int_t iy = (fH0->fDimension > 1) ? -1 : 0;
1003 Int_t iz = (fH0->fDimension > 2) ? -1 : 0;
1006 if (binx == 0 && TString(labelX) ==
"" ) ix = 0;
1007 if (binx == hist->fXaxis.GetNbins() +1 && TString(labelX) ==
"" ) ix = fH0->fXaxis.GetNbins() +1;
1008 if (fH0->fDimension > 1 ) {
1009 if (biny == 0 && TString(labelY) ==
"" ) iy = 0;
1010 if (biny == hist->fYaxis.GetNbins() +1 && TString(labelY) ==
"" ) iy = fH0->fYaxis.GetNbins() +1;
1012 if (fH0->fDimension > 2 ) {
1013 if (binz == 0 && TString(labelZ) ==
"" ) iz = 0;
1014 if (binz == hist->fZaxis.GetNbins() +1 && TString(labelZ) ==
"" ) iz = fH0->fZaxis.GetNbins() +1;
1022 ix = fH0->fXaxis.FindBin(labelX);
1024 ix = FindFixBinNumber(binx, hist->fXaxis, fH0->fXaxis);
1027 if (iy == -1 && fH0->fDimension> 1 ) {
1029 iy= fH0->fYaxis.FindBin(labelY);
1031 iy = FindFixBinNumber(biny, hist->fYaxis, fH0->fYaxis);
1033 if (iz == -1 && fH0->fDimension> 2) {
1035 iz= fH0->fZaxis.FindBin(labelZ);
1037 iz = FindFixBinNumber(binz, hist->fZaxis, fH0->fZaxis);
1041 Info(
"TH1Merge::LabelMerge",
"Merge bin [%d,%d,%d] with label [%s,%s,%s] into bin [%d,%d,%d]",
1042 binx,biny,binz,labelX,labelY,labelZ,ix,iy,iz);
1044 Int_t ib = fH0->GetBin(ix,iy,iz);
1045 if (ib < 0 || ib >= fH0->fNcells) {
1046 Fatal(
"TH1Merger::LabelMerge",
"Fatal error merging histogram %s - bin number is %d and array size is %d",
1047 fH0->GetName(), ib,fH0->fNcells);
1050 fH0->AddBinContent(ib,cu);
1051 if (fH0->fSumw2.fN) fH0->fSumw2.fArray[ib] += e1sq;
1055 fH0->PutStats(totstats);
1056 fH0->SetEntries(nentries);