All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Binner.h
Go to the documentation of this file.
1 /**
2  * @file Binner.h
3  * @brief Helper object to describing a binned axis.
4  * @author Gianluca Petrillo (petrillo@slac.stanford.edu)
5  * @date October 13, 2020
6  *
7  * This library is header only.
8  */
9 
10 #ifndef ICARUSALG_GALLERY_DETECTORACTIVITYRATEPLOTS_BINNER_H
11 #define ICARUSALG_GALLERY_DETECTORACTIVITYRATEPLOTS_BINNER_H
12 
13 
14 // C/C++ standard libraries
15 #include <ostream>
16 #include <algorithm> // std::clamp()
17 #include <utility> // std::declval()
18 #include <cmath> // std::ceil(), std::floor()
19 #include <cassert>
20 
21 
22 // -----------------------------------------------------------------------------
23 namespace util {
24  template <typename T> class Binner;
25  template <typename T>
26  std::ostream& operator<< (std::ostream&, Binner<T> const&);
27 } // namespace util
28 
29 /**
30  * @brief Helper class binning values in a range.
31  * @tparam T type of data on the axis
32  *
33  * This object provides binning and indexing of a range of values from
34  * `lower()` to `upper()`.
35  * The range is divided in `nBins()` bins all of the same size `step()`.
36  *
37  * The type of the values is `T`; the type of `step()` may be `T` or something
38  * else, automatically detected.
39  *
40  * Example of usage:
41  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
42  * util::Binner<float> const bins(-1.0f, +1.0f, 0.1f);
43  *
44  * std::cout << "Binning: " << bins << std::endl; // print binning on screen
45  *
46  * // print the bin index for some known values
47  * std::cout << "\nBin indices (no range constraint):";
48  * for (float const value: { -1.5f, -1.0f, -0.5f, 0.0f, +0.5f, +1.0f, +1.5f })
49  * std::cout << " - bin index for " << value << ": " << bins(value) << std::endl;
50  * std::cout << std::flush;
51  *
52  * // print the bin index for some known values
53  * std::cout << "\nBin relative indices (no range constraint):";
54  * for (float const value: { -1.5f, -1.0f, -0.5f, 0.0f, +0.5f, +1.0f, +1.5f })
55  * std::cout << "\n - " << value << " => [" << bins.relative(value) << "]";
56  * std::cout << std::flush;
57  *
58  * // print the capped bin index for some known values
59  * std::cout << "\nBin indices (capped):";
60  * for (float const value: { -1.5f, -1.0f, -0.5f, 0.0f, +0.5f, +1.0f, +1.5f }) {
61  * std::cout << "\n - " << value << " => [" << bins.cappedBin(value) << "]";
62  * std::cout << std::flush;
63  *
64  *
65  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
66  *
67  * Note that the upper bound of each bin does _not_ belong to that bin, but
68  * rather to the next one (and, differently from ROOT, this also holds for
69  * the last bin, i.e. the `upper()` value).
70  *
71  */
72 template <typename T>
73 class util::Binner {
74  public:
75  using Data_t = T; ///< Type of values on the binning axis.
76 
77  /// Type of difference between binning axis values.
78  using Step_t = decltype(std::declval<Data_t>() - std::declval<Data_t>());
79 
80 
81  /**
82  * @brief Constructor: covers the range from `lower` to `upper` or above.
83  * @param lower lower bound of the binning range (used exact)
84  * @param upper upper bound of the binning range (see description)
85  * @param step bin width (used exact)
86  *
87  * The binning range is defined to include an integral number of bins all
88  * with width `step`, starting exactly at `lower` value.
89  * The bins are enough that the last one includes or touches the `upper`
90  * value. In other words the number of bins is set by the formula
91  * @f$ \lceil (upper - lower) / step \rceil @f$, and the actual `upper()`
92  * value is computed accordingly, to accommodate that many bins.
93  */
95 
96 
97  // -- BEGIN -- Access --------------------------------------------------------
98  /// @name Access
99  /// @{
100  /// Returns the lower limit of the range.
101  Data_t lower() const { return fLower; }
102 
103  /// Returns the upper limit of the range.
104  Data_t upper() const { return fUpper; }
105 
106  /// Returns the step size.
107  Step_t step() const { return fStep; }
108 
109  /// Returns the number of bins in the range.
110  unsigned int nBins() const { return fNBins; }
111  /// @}
112  // -- END -- Access ----------------------------------------------------------
113 
114 
115  // -- BEGIN -- Bin index queries ---------------------------------------------
116  /**
117  * @name Bin index queries
118  *
119  * Type of supported queries:
120  * * whether a value is within the range: `contains()`
121  * * bin "index" for a value:
122  * * fractional value (`relative()`): a value in the middle of the bin
123  * will have a index with fractional part `0.5`;
124  * * integral value, with different treatment for overflows:
125  * * `bin()` (also `operator()`): no range check at all, index can be
126  * any integral value
127  * * `cappedBin()`: if the bin index is smaller, or larger, than the
128  * specified minimum and maximum bin numbers, the returned value is
129  * clamped to those minimum and maximum bin numbers;
130  * * `cappedBin()`: the bin index is between `0` and `nBins() - 1`,
131  * where bin `0` also includes all values smaller than `lower()`
132  * and bin `nBins() - 1` includes all values larger or equal to
133  * `upper()`
134  * * `cappedBinWithOverflows()`: the bin index is between `-1` and
135  * `nBins()`, where bin `-1` includes all values smaller than
136  * `lower()` and bin `nBins()` includes all values larger or equal
137  * to `upper()`
138  */
139  /// @{
140 
141  // @{
142  /// Returns `value` relative to the range (lower = 0, upper = 1).
143  double relative(Data_t value) const { return (value - fLower) / fStep; }
144  // @}
145 
146  // @{
147  /// Returns bin number for `value` (unbound).
148  int bin(Data_t value) const
149  { return static_cast<int>(std::floor(relative(value))); }
150  int operator() (Data_t value) const { return bin(value); }
151  // @}
152 
153  // @{
154  /// Returns a bin number for `value` clamped between `min` and `max` included.
155  int cappedBin(Data_t value, int min, int max) const
156  { return std::clamp(bin(value), min, max); }
157  // @}
158 
159  // @{
160  /// Returns a valid bin index, capping if `value` is out of range.
161  int cappedBin(Data_t value) const { return cappedBin(value, 0, nBins() - 1); }
162  // @}
163 
164  // @{
165  /// Returns a valid bin index or `-1` for underflow or `nBins()` for overflow.
167  { return cappedBin(value, -1, nBins()); }
168  // @}
169 
170  /// @}
171  // -- END -- Bin index queries -----------------------------------------------
172 
173 
174  // -- BEGIN -- Range queries -------------------------------------------------
175  /// @name Range queries
176  /// @{
177 
178  /// Returns if `value` is in the range.
179  bool contains(Data_t value) const
180  { return (value >= fLower) && (value < fUpper); }
181 
182  /// Returns the lower edge of the bin with the specified index `iBin`.
183  Data_t lowerEdge(int iBin) const { return fLower + fStep * iBin; }
184 
185  /// Returns the upper edge of the bin with the specified index `iBin`.
186  Data_t upperEdge(int iBin) const { return lowerEdge(iBin + 1); }
187 
188  /// Returns the center of the bin with the specified index `iBin`.
189  Data_t binCenter(int iBin) const { return lowerEdge(iBin) + fStep / 2; }
190 
191  /// @}
192  // -- END -- Range queries ---------------------------------------------------
193 
194 
195  private:
196  Data_t fLower; ///< Lower bound of the covered range.
197  Step_t fStep; ///< Width of the bins.
198  unsigned int fNBins; ///< Number of bins in the range.
199  Data_t fUpper; ///< Upper bound of the covered range.
200 
201 }; // util::Binner<>
202 
203 
204 // -----------------------------------------------------------------------------
205 // --- template implementation
206 // -----------------------------------------------------------------------------
207 template <typename T>
209  : fLower(lower)
210  , fStep(step)
211  , fNBins(static_cast<unsigned int>(std::ceil((upper - lower) / step)))
212  , fUpper(lowerEdge(fNBins))
213  { assert(lower <= upper); }
214 
215 
216 // -----------------------------------------------------------------------------
217 template <typename T>
218 std::ostream& util::operator<< (std::ostream& out, Binner<T> const& binner) {
219 
220  out << "[ " << binner.lower() << " -- " << binner.upper() << " ] ("
221  << binner.nBins() << "x " << binner.step() << ")";
222  return out;
223 
224 } // operator<< (Binner<>)
225 
226 
227 // -----------------------------------------------------------------------------
228 
229 #endif // ICARUSALG_GALLERY_DETECTORACTIVITYRATEPLOTS_BINNER_H
int cappedBin(Data_t value, int min, int max) const
Returns a bin number for value clamped between min and max included.
Definition: Binner.h:155
int cappedBin(Data_t value) const
Returns a valid bin index, capping if value is out of range.
Definition: Binner.h:161
double std(const std::vector< short > &wf, const double ped_mean, size_t start, size_t nsample)
Definition: UtilFunc.cxx:42
Helper class binning values in a range.
Definition: Binner.h:24
bool contains(Data_t value) const
Returns if value is in the range.
Definition: Binner.h:179
simulation_time Data_t
Type of values on the binning axis.
Definition: Binner.h:75
int cappedBinWithOverflows(Data_t value) const
Returns a valid bin index or -1 for underflow or nBins() for overflow.
Definition: Binner.h:166
Data_t binCenter(int iBin) const
Returns the center of the bin with the specified index iBin.
Definition: Binner.h:189
int bin(Data_t value) const
Returns bin number for value (unbound).
Definition: Binner.h:148
Step_t fStep
Width of the bins.
Definition: Binner.h:197
Data_t lowerEdge(int iBin) const
Returns the lower edge of the bin with the specified index iBin.
Definition: Binner.h:183
Binner(Data_t lower, Data_t upper, Step_t step)
Constructor: covers the range from lower to upper or above.
Definition: Binner.h:208
double relative(Data_t value) const
Returns value relative to the range (lower = 0, upper = 1).
Definition: Binner.h:143
Data_t fUpper
Upper bound of the covered range.
Definition: Binner.h:199
Data_t fLower
Lower bound of the covered range.
Definition: Binner.h:196
unsigned int fNBins
Number of bins in the range.
Definition: Binner.h:198
Data_t upperEdge(int iBin) const
Returns the upper edge of the bin with the specified index iBin.
Definition: Binner.h:186
Data_t upper() const
Returns the upper limit of the range.
Definition: Binner.h:104
Step_t step() const
Returns the step size.
Definition: Binner.h:107
Data_t lower() const
Definition: Binner.h:101
temporary value
int operator()(Data_t value) const
Definition: Binner.h:150
decltype(std::declval< Data_t >()-std::declval< Data_t >()) Step_t
Type of difference between binning axis values.
Definition: Binner.h:78
unsigned int nBins() const
Returns the number of bins in the range.
Definition: Binner.h:110