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(), \
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();
55 if (ret)
return kTRUE;
59 Error(
"TH1Merger",
"Unknown type of Merge for histogram %s",
fH0->
GetName());
81 Error(
"AutoP2BuildAxes",
"undefined histogram: %p",
h);
87 Error(
"AutoP2BuildAxes",
"not in autobin-power-of-2 mode!");
95 Bool_t canextend = (
h->GetBinContent(0) > 0 ||
h->GetBinContent(a1->GetNbins() + 1) > 0) ?
kFALSE :
kTRUE;
99 a0->
Set(a1->GetNbins(), a1->GetXmin(), a1->GetXmax());
107 Double_t bwmin = (a1->GetXmax() - a1->GetXmin()) / a1->GetNbins();
115 Error(
"AutoP2BuildAxes",
"minimal bin width negative or null: %f", bwmin);
120 Double_t re = std::modf(bwmax / bwmin, &rt);
123 Error(
"AutoP2BuildAxes",
"bin widths not in integer ratio: %f", re);
130 if (a0->
GetXmin() < a1->GetXmin()) {
131 if (a0->
GetXmax() < a1->GetXmin()) {
134 Error(
"AutoP2BuildAxes",
"ranges are disconnected and under/overflows: cannot merge");
137 xmax = a1->GetXmax();
141 if (a0->
GetXmax() >= a1->GetXmax()) {
142 xmax = a1->GetXmax();
143 xmin = a1->GetXmin();
147 xmin = a1->GetXmin();
152 if (a1->GetXmax() < a0->
GetXmin()) {
155 Error(
"AutoP2BuildAxes",
"ranges are disconnected and under/overflows: cannot merge");
159 xmin = a1->GetXmin();
162 if (a1->GetXmax() >= a0->
GetXmax()) {
167 xmax = a1->GetXmax();
175 re = std::modf(range / bwmax, &rt);
178 Error(
"MergeCompatibleHistograms",
"range smaller than bin width: %f %f %f", range, bwmax, rt);
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());
261 haveWeights |=
h->GetSumw2N() != 0;
266 allHaveLimits = allHaveLimits && hasLimits;
267 allSameLimits &= allHaveLimits;
270 Error(
"Merge",
"Cannot merge histogram - some are in autobin-power-of-2 mode, but not %s!",
h->GetName());
274 Error(
"Merge",
"Cannot merge histogram - %s is in autobin-power-of-2 mode, but not the previous ones",
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());
325 Error(
"Merge",
"Cannot merge histograms - limits are inconsistent:\n "
326 "first: %s (%d, %f, %f), second: %s (%d, %f, %f)",
fH0->
GetName(),
328 h->GetName(),
h->GetXaxis()->GetNbins(),
h->GetXaxis()->GetXmin(),
329 h->GetXaxis()->GetXmax());
340 Error(
"Merge",
"Cannot merge histograms - limits are inconsistent:\n "
341 "first: %s (%d, %f, %f), second: %s (%d, %f, %f)",
fH0->
GetName(),
343 h->GetName(),
h->GetYaxis()->GetNbins(),
h->GetYaxis()->GetXmin(),
344 h->GetYaxis()->GetXmax());
351 Error(
"Merge",
"Cannot merge histograms - limits are inconsistent:\n "
352 "first: %s (%d, %f, %f), second: %s (%d, %f, %f)",
fH0->
GetName(),
354 h->GetName(),
h->GetZaxis()->GetNbins(),
h->GetZaxis()->GetXmin(),
355 h->GetZaxis()->GetXmax());
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() );
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());
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());
408 if (allHaveLabels && !
h->CanExtendAllAxes()) {
410 Int_t non_zero_bins = 0;
411 Int_t nbins =
h->GetXaxis()->GetNbins();
413 for (
Int_t i = 1; i <= nbins; i++) {
414 if (
h->RetrieveBinContent(i) != 0 || (
fH0->
fSumw2.
fN &&
h->GetBinError(i) != 0) ) {
419 Warning(
"TH1Merger::ExamineHistograms",
"Histogram %s contains non-empty bins without labels - falling back to bin numbering mode",
h->GetName() );
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",
450 if (!initialLimitsFound) {
532 if (newLimitsX)
Info(
"DefineNewAxis",
"A new X axis has been defined Nbins=%d , [%f,%f]",
fH0->
fXaxis.
GetNbins(),
534 if (newLimitsY)
Info(
"DefineNewAxis",
"A new Y axis has been defined Nbins=%d , [%f,%f]",
fH0->
fYaxis.
GetNbins(),
536 if (newLimitsZ)
Info(
"DefineNewAxis",
"A new Z axis has been defined Nbins=%d , [%f,%f]",
fH0->
fZaxis.
GetNbins(),
548 if (!hsrc || !hsrc->
fBuffer || !hdes ) {
552 Warning(
"TH1Merger::CopyMerge",
"invalid inputs: %p, %p, %p, -> do nothing", hsrc, hdes,
p1);
559 for (
Int_t i = 0; i < nbentries; i++)
563 auto h2 =
dynamic_cast<TH2 *
>(hdes);
565 for (
Int_t i = 0; i < nbentries; i++)
569 auto h3 =
dynamic_cast<TH3 *
>(hdes);
571 for (
Int_t i = 0; i < nbentries; i++)
580 TH1 *href = 0, *hist = 0;
585 while ((hist = (
TH1 *)nextref()) && !href) {
602 while ((hist = (
TH1 *)next())) {
605 Info(
"AutoP2BufferMerge",
"merging buffer of %s into %s", hist->GetName(), href->
GetName());
625 totstats[i] = stats[i] = 0;
635 while ((hist = (
TH1 *)next())) {
643 Info(
"TH1Merger::AutoP2Merge",
"all histograms look empty!");
649 Error(
"TH1Merger::AutoP2Merge",
"cannot create axes from %s", hist->
GetName());
653 while ((
h = (
TH1 *)next())) {
655 Error(
"TH1Merger::AutoP2Merge",
"cannot merge histogram %s: not merge compatible",
h->GetName());
676 while ((hist = (
TH1 *)next())) {
681 Info(
"TH1Merger::AutoP2Merge",
"merging histogram %s into %s (entries: %f)", hist->
GetName(),
fH0->
GetName(),
691 totstats[i] += stats[i];
722 while (
TH1* hist = (
TH1*)next()) {
727 Info(
"TH1Merger::BufferMerge",
"Merging histogram %s into %s",hist->GetName(),
fH0->
GetName() );
749 totstats[i] = stats[i] = 0;
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);
768 totstats[i] += stats[i];
773 for (
Int_t ibin = 0; ibin < hist->fNcells; ibin++) {
775 Double_t cu = hist->RetrieveBinContent(ibin);
777 if (
fH0->
fSumw2.
fN) e1sq= hist->GetBinErrorSqUnchecked(ibin);
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);
816 totstats[i] += stats[i];
820 for (
Int_t ibin = 0; ibin < hist->fNcells; ibin++) {
822 Double_t cu = hist->RetrieveBinContent(ibin);
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) {
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) {
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) {
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());
869 Fatal(
"TH1Merger::LabelMerge",
"Fatal error merging histogram %s - bin number is %d and array size is %d",
889 if (!labels)
return kFALSE;
891 for (
const auto * obj: *labels) {
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;
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());
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());
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());
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);
966 totstats[i] += stats[i];
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));
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);
1006 if (binx == 0 &&
TString(labelX) ==
"" ) ix = 0;
1009 if (biny == 0 &&
TString(labelY) ==
"" ) iy = 0;
1013 if (binz == 0 &&
TString(labelZ) ==
"" ) iz = 0;
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);
1046 Fatal(
"TH1Merger::LabelMerge",
"Fatal error merging histogram %s - bin number is %d and array size is %d",
static double p1(double t, double a, double b)
void Info(const char *location, const char *msgfmt,...)
void Error(const char *location, const char *msgfmt,...)
void Warning(const char *location, const char *msgfmt,...)
void Fatal(const char *location, const char *msgfmt,...)
#define PRINTRANGE(a, b, bn)
void Set(Int_t n)
Set size of this array to n doubles.
const Double_t * GetArray() const
Class to manage histogram axis.
const TArrayD * GetXbins() const
void SetCanExtend(Bool_t canExtend)
virtual Int_t FindBin(Double_t x)
Find bin number corresponding to abscissa x.
virtual void Set(Int_t nbins, Double_t xmin, Double_t xmax)
Initialize axis with fix bins.
Int_t GetLast() const
Return last bin on the axis i.e.
Bool_t CanBeAlphanumeric()
virtual void SetRange(Int_t first=0, Int_t last=0)
Set the viewing range for the axis from bin first to last.
Int_t GetFirst() const
Return first bin on the axis i.e.
THashList * GetLabels() const
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)
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.
Bool_t DifferentAxesMerge()
Merged histogram when axis can be different.
TList fInputList
copy of fH0 - managed by this class
static Int_t FindFixBinNumber(Int_t ibin, const TAxis &inAxis, const TAxis &outAxis)
void CopyBuffer(TH1 *hsrc, TH1 *hdes)
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.
Bool_t operator()()
Function performing the actual merge.
void DefineNewAxes()
Function to define new histogram axis when merging It is call only in case of merging with different ...
TH1 * fHClone
histogram on which the list is merged
Bool_t LabelMerge()
Merge histograms with labels.
virtual void SetDirectory(TDirectory *dir)
By default when an histogram is created, it is added to the list of histogram objects in the current ...
Double_t * fBuffer
[fBufferSize] entry buffer
virtual Double_t GetBinCenter(Int_t bin) const
Return bin center for 1D histogram.
Int_t fNcells
number of bins(1D), cells (2D) +U/Overflows
virtual void GetStats(Double_t *stats) const
fill the array stats from the contents of this histogram The array stats must be correctly dimensione...
virtual void AddBinContent(Int_t bin)
Increment bin content by 1.
virtual Int_t GetDimension() const
@ kAutoBinPTwo
Use Power(2)-based algorithm for autobinning.
virtual Bool_t CanExtendAllAxes() const
Returns true if all axes are extendable.
virtual void Reset(Option_t *option="")
Reset this histogram: contents, errors, etc.
TAxis * GetXaxis()
Get the behaviour adopted by the object about the statoverflows. See EStatOverflows for more informat...
static Bool_t RecomputeAxisLimits(TAxis &destAxis, const TAxis &anAxis)
Finds new limits for the axis for the Merge function.
virtual void PutStats(Double_t *stats)
Replace current statistics with the values in array stats.
TObject * Clone(const char *newname=0) const
Make a complete copy of the underlying object.
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.
static Bool_t SameLimitsAndNBins(const TAxis &axis1, const TAxis &axis2)
Same limits and bins.
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...
Int_t fDimension
!Histogram dimension (1, 2 or 3 dim)
virtual void SetBinsLength(Int_t=-1)
virtual Int_t Fill(Double_t x)
Increment bin with abscissa X by 1.
virtual Double_t GetBinErrorSqUnchecked(Int_t bin) const
virtual Double_t GetEntries() const
Return the current number of entries.
virtual UInt_t SetCanExtend(UInt_t extendBitMask)
Make the histogram axes extendable / not extendable according to the bit mask returns the previous bi...
virtual void Copy(TObject &hnew) const
Copy this histogram structure to newth1.
Bool_t IsEmpty() const
Check if an histogram is empty (this a protected method used mainly by TH1Merger )
TAxis fZaxis
Z axis descriptor.
TAxis fXaxis
X axis descriptor.
TArrayD fSumw2
Array of sum of squares of weights.
virtual Int_t GetSumw2N() const
virtual Int_t FindBin(Double_t x, Double_t y=0, Double_t z=0)
Return Global bin number corresponding to x,y,z.
TAxis fYaxis
Y axis descriptor.
virtual void SetBins(Int_t nx, Double_t xmin, Double_t xmax)
Redefine x axis parameters.
virtual void Sumw2(Bool_t flag=kTRUE)
Create structure to store sum of squares of weights.
virtual void SetEntries(Double_t n)
virtual Int_t BufferEmpty(Int_t action=0)
Fill histogram with all entries in the buffer.
Service class for 2-Dim histogram classes.
The 3-D histogram classes derived from the 1-D histogram classes.
THashList implements a hybrid collection class consisting of a hash table and a list to store TObject...
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...
virtual void Add(TObject *obj)
virtual TObject * Remove(TObject *obj)
Remove object from the list.
virtual void AddFirst(TObject *obj)
Add object at the beginning of the list.
virtual const char * GetName() const
Returns name of object.
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
virtual const char * ClassName() const
Returns name of class to which the object belongs.
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
static constexpr double s
void swap(nlohmann::json &j1, nlohmann::json &j2) noexcept(is_nothrow_move_constructible< nlohmann::json >::value and is_nothrow_move_assignable< nlohmann::json >::value)
exchanges the values of two JSON objects