Logo ROOT   master
Reference Guide
RAxis.cxx
Go to the documentation of this file.
1 /// \file RAxis.cxx
2 /// \ingroup Hist ROOT7
3 /// \author Axel Naumann <axel@cern.ch>
4 /// \date 2015-08-06
5 /// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
6 /// is welcome!
7 
8 /*************************************************************************
9  * Copyright (C) 1995-2015, Rene Brun and Fons Rademakers. *
10  * All rights reserved. *
11  * *
12  * For the licensing terms see $ROOTSYS/LICENSE. *
13  * For the list of contributors see $ROOTSYS/README/CREDITS. *
14  *************************************************************************/
15 
16 #include "ROOT/RAxis.hxx"
17 
18 #include <cmath>
19 #include <limits>
20 
22 
24  // Bin borders must match
25  if (!HasSameBinBordersAs(other))
26  return false;
27 
28  // Bin labels must match
29  auto lbl_ptr = dynamic_cast<const RAxisLabels*>(this);
30  auto other_lbl_ptr = dynamic_cast<const RAxisLabels*>(&other);
31  if (bool(lbl_ptr) != bool(other_lbl_ptr)) {
32  return false;
33  } else if (lbl_ptr) {
34  auto lbl_cmp = lbl_ptr->CompareBinLabels(*other_lbl_ptr);
35  return (lbl_cmp == RAxisLabels::kLabelsCmpSame);
36  } else {
37  return true;
38  }
39 }
40 
42 {
43  // fracBinIdx is the fractional bin index of x in this axis. It's (close to)
44  // an integer if it's an axis border.
45  double fracBinIdx = GetFirstBin() + FindBinRaw(x);
46 
47  // fracBinIdx might be 12.99999999. It's a bin border if the deviation from
48  // an regular bin border is "fairly small".
49  int binIdx = std::round(fracBinIdx);
50  double binOffset = fracBinIdx - binIdx;
51  if (std::fabs(binOffset) > 10 * std::numeric_limits<double>::epsilon())
53 
54  // If the bin index is below the first bin (i.e. x is the lower edge of the
55  // underflow bin) then it's out of range.
56  if (binIdx < GetFirstBin())
58  // If x is the lower edge of the overflow bin then that's still okay - but if
59  // even the bin before binIdx is an overflow it's out of range.
60  if (binIdx > GetLastBin() + 1)
62 
63  return binIdx;
64 }
65 
67  // This is an optimized override for the equidistant-equidistant case,
68  // fall back to the default implementation if we're not in that case.
69  auto other_eq_ptr = dynamic_cast<const RAxisEquidistant*>(&other);
70  if (!other_eq_ptr)
71  return RAxisBase::HasSameBinBordersAs(other);
72  const RAxisEquidistant& other_eq = *other_eq_ptr;
73 
74  // Can directly compare equidistant/growable axis properties in this case
75  return fInvBinWidth == other_eq.fInvBinWidth &&
76  fLow == other_eq.fLow &&
77  fNBinsNoOver == other_eq.fNBinsNoOver &&
78  CanGrow() == other_eq.CanGrow();
79 }
80 
82 {
83  // Check in which bin `x` resides
84  double fracBinIdx = FindBinRaw(x);
85  const int binIdx = fracBinIdx;
86 
87  // Are we close to the lower and upper bin boundaries, if any?
88  constexpr double tol = 10 * std::numeric_limits<double>::epsilon();
89  if (binIdx >= GetFirstBin()) {
90  const double lowBound = GetBinFrom(binIdx);
91  if (std::fabs(x - lowBound) < tol * std::fabs(lowBound))
92  return binIdx;
93  }
94  if (binIdx <= GetLastBin()) {
95  const double upBound = GetBinTo(binIdx);
96  if (std::fabs(x - upBound) < tol * std::fabs(upBound))
97  return binIdx + 1;
98  }
99 
100  // If not, report failure
101  return RAxisBase::kInvalidBin;
102 }
103 
105  // This is an optimized override for the irregular-irregular case,
106  // fall back to the default implementation if we're not in that case.
107  auto other_irr_ptr = dynamic_cast<const RAxisIrregular*>(&other);
108  if (!other_irr_ptr)
109  return RAxisBase::HasSameBinBordersAs(other);
110  const RAxisIrregular& other_irr = *other_irr_ptr;
111 
112  // Only need to compare bin borders in this specialized case
113  return fBinBorders == other_irr.fBinBorders;
114 }
115 
117  const RAxisEquidistant &source) noexcept
118 {
119  // First, let's get the common "all parameters are equal" case out of the way
120  if (source.HasSameBinningAs(target))
122 
123  // Do the source min/max boundaries correspond to target bin boundaries?
124  int idxTargetLow = target.GetBinIndexForLowEdge(source.GetMinimum());
125  int idxTargetHigh = target.GetBinIndexForLowEdge(source.GetMaximum());
126  if (idxTargetLow < 0 || idxTargetHigh < 0)
127  // If not, the source is incompatible with the target since the first or
128  // last source bin does not map into a target axis bin.
130 
131  // If so, and if the bin width is the same, then since we've eliminated the
132  // care where min/max/width are equal, source must be a subset of target.
133  if (source.GetInverseBinWidth() == target.GetInverseBinWidth())
135 
136  // Now we are left with the case
137  // source: 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6
138  // target: ...0.0, 0.3, 0.6...
139  // The question is: is the ratio of the bin width identical to the ratio of
140  // the number of bin?
141  if (std::fabs(target.GetInverseBinWidth() * source.GetNBinsNoOver() -
142  source.GetInverseBinWidth() * (idxTargetHigh - idxTargetLow)) > 1E-6 * target.GetInverseBinWidth())
144 
145  // source is a fine-grained version of target.
147 }
148 
149 // TODO: the other CanMap() overloads
An axis with non-equidistant bins (also known as "variable binning").
Definition: RAxis.hxx:591
virtual bool HasSameBinBordersAs(const RAxisBase &other) const
Check if two axis have the same bin borders.
Definition: RAxis.hxx:98
static constexpr const int kInvalidBin
Special bin index returned to signify that no bin matches a request.
Definition: RAxis.hxx:226
bool HasSameBinBordersAs(const RAxisBase &other) const override
See RAxisBase::HasSameBinBordersAs.
Definition: RAxis.cxx:104
int GetBinIndexForLowEdge(double x) const noexcept final override
If the coordinate x is within 10 ULPs of a bin low edge coordinate, return the bin for which this is ...
Definition: RAxis.cxx:81
bool HasSameBinningAs(const RAxisBase &other) const
Check if two axes use the same binning convention, i.e.
Definition: RAxis.cxx:23
bool CanGrow() const noexcept override
This axis cannot grow.
Definition: RAxis.hxx:458
double fLow
The lower limit of the axis.
Definition: RAxis.hxx:386
The bins of the source axis have finer granularity, but the bin borders are compatible.
Double_t x[n]
Definition: legend1.C:17
Both axes have the same labels, mapping to the same bins.
Definition: RAxis.hxx:800
VecExpr< UnaryOp< Fabs< T >, VecExpr< A, T, D >, T >, T, D > fabs(const VecExpr< A, T, D > &rhs)
virtual ~RAxisBase()
Virtual destructor needed in this inheritance-based design.
Definition: RAxis.cxx:21
std::vector< double > fBinBorders
Bin borders, one more than the number of regular bins.
Definition: RAxis.hxx:594
REAL epsilon
Definition: triangle.c:617
constexpr Double_t E()
Base of natural log: .
Definition: TMath.h:97
bool HasSameBinBordersAs(const RAxisBase &other) const override
See RAxisBase::HasSameBinBordersAs.
Definition: RAxis.cxx:66
unsigned int fNBinsNoOver
Number of bins excluding under- and overflow.
Definition: RAxis.hxx:388
A RAxisGrow that has a label assigned to each bin and a bin width of 1.
Definition: RAxis.hxx:738
The source is a subset of bins of the target axis.
double fInvBinWidth
The inverse of the bin width.
Definition: RAxis.hxx:387
EAxisCompatibility CanMap(const RAxisEquidistant &target, const RAxisEquidistant &source) noexcept
Whether (and how) the source axis can be merged into the target axis.
Definition: RAxis.cxx:116
Histogram axis base class.
Definition: RAxis.hxx:44
int GetBinIndexForLowEdge(double x) const noexcept final override
If the coordinate x is within 10 ULPs of a bin low edge coordinate, return the bin for which this is ...
Definition: RAxis.cxx:41
Source and target axes are identical.
LabelsCmpFlags CompareBinLabels(const RAxisLabels &other) const noexcept
Compare the labels of this axis with those of another axis.
Definition: RAxis.hxx:813
The source axis and target axis have different binning.
Axis with equidistant bin borders.
Definition: RAxis.hxx:384