ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
BinningData.hpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file BinningData.hpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2016-2018 CERN for the benefit of the Acts project
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 
10 // BinUtility.h, Acts project
12 #pragma once
13 #include <cmath>
14 #include <iostream>
15 #include <memory>
16 #include <utility>
17 #include <vector>
22 
23 namespace Acts {
24 
40 class BinningData {
41  public:
45  float min;
46  float max;
47  float step;
48  bool zdim;
49 
51  std::unique_ptr<const BinningData> subBinningData;
54 
60  BinningData(BinningValue bValue, float bMin, float bMax)
61  : type(equidistant),
62  option(open),
63  binvalue(bValue),
64  min(bMin),
65  max(bMax),
66  step((bMax - bMin)),
67  zdim(true),
68  subBinningData(nullptr),
70  m_bins(1),
71  m_boundaries({{min, max}}),
72  m_totalBins(1),
73  m_totalBoundaries(std::vector<float>()),
75 
87  BinningData(BinningOption bOption, BinningValue bValue, size_t bBins,
88  float bMin, float bMax,
89  std::unique_ptr<const BinningData> sBinData = nullptr,
90  bool sBinAdditive = false)
91  : type(equidistant),
92  option(bOption),
93  binvalue(bValue),
94  min(bMin),
95  max(bMax),
96  step((bMax - bMin) / bBins),
97  zdim(bBins == 1 ? true : false),
98  subBinningData(std::move(sBinData)),
99  subBinningAdditive(sBinAdditive),
100  m_bins(bBins),
101  m_boundaries(std::vector<float>()),
102  m_totalBins(bBins),
103  m_totalBoundaries(std::vector<float>()),
104  m_functionPtr(nullptr) {
105  // set to equidistant search
107  // fill the boundary vector for fast access to center & boundaries
108  m_boundaries.reserve(m_bins + 1);
109  for (size_t ib = 0; ib < m_bins + 1; ++ib) {
110  m_boundaries.push_back(min + ib * step);
111  }
112  // the binning data has sub structure - multiplicative or additive
114  }
115 
123  const std::vector<float>& bBoundaries,
124  std::unique_ptr<const BinningData> sBinData = nullptr)
125  : type(arbitrary),
126  option(bOption),
127  binvalue(bValue),
128  min(0.),
129  max(0.),
130  step(0.),
131  zdim(bBoundaries.size() == 2 ? true : false),
132  subBinningData(std::move(sBinData)),
134  m_bins(bBoundaries.size() - 1),
135  m_boundaries(bBoundaries),
136  m_totalBins(bBoundaries.size() - 1),
137  m_totalBoundaries(bBoundaries),
138  m_functionPtr(nullptr) {
139  // assert a no-size case
140  throw_assert(m_boundaries.size() > 1, "Must have more than one boundary");
141  min = m_boundaries[0];
142  max = m_boundaries[m_boundaries.size() - 1];
143  // set to equidistant search
144  m_functionPtr =
146  // the binning data has sub structure - multiplicative
148  }
149 
153  BinningData(const BinningData& bdata)
154  : type(bdata.type),
155  option(bdata.option),
156  binvalue(bdata.binvalue),
157  min(bdata.min),
158  max(bdata.max),
159  step(bdata.step),
160  zdim(bdata.zdim),
161  subBinningData(nullptr),
163  m_bins(bdata.m_bins),
164  m_boundaries(bdata.m_boundaries),
165  m_totalBins(bdata.m_totalBins),
167  m_functionPtr(nullptr) {
168  // get the binning data
170  bdata.subBinningData
171  ? std::make_unique<const BinningData>(*bdata.subBinningData)
172  : nullptr;
173  // set the pointer depending on the type
174  // set the correct function pointer
175  if (type == equidistant) {
177  } else {
178  m_functionPtr =
180  }
181  }
182 
187  if (this != &bdata) {
188  type = bdata.type;
189  option = bdata.option;
190  binvalue = bdata.binvalue;
191  min = bdata.min;
192  max = bdata.max;
193  step = bdata.step;
194  zdim = bdata.zdim;
197  bdata.subBinningData
198  ? std::make_unique<const BinningData>(*bdata.subBinningData)
199  : nullptr;
200  m_bins = bdata.m_bins;
201  m_boundaries = bdata.m_boundaries;
202  m_totalBins = bdata.m_totalBins;
204  // set the correct function pointer
205  if (type == equidistant) {
207  } else {
210  }
211  }
212  return (*this);
213  }
214 
216  ~BinningData() = default;
217 
219  size_t bins() const { return m_totalBins; }
220 
225  bool decrement(size_t& bin) const {
226  size_t sbin = bin;
227  bin = bin > 0 ? bin - 1 : (option == open ? bin : m_bins - 1);
228  return (sbin != bin);
229  }
230 
235  bool increment(size_t& bin) const {
236  size_t sbin = bin;
237  bin = bin + 1 < m_bins ? bin + 1 : (option == open ? bin : 0);
238  return (sbin != bin);
239  }
240 
243  const std::vector<float>& boundaries() const {
244  if (subBinningData) {
245  return m_totalBoundaries;
246  }
247  return m_boundaries;
248  }
249 
255  float value(const Vector2D& lposition) const {
256  // ordered after occurence
257  if (binvalue == binR || binvalue == binRPhi || binvalue == binX ||
258  binvalue == binH) {
259  return lposition[0];
260  }
261  if (binvalue == binPhi) {
262  return lposition[1];
263  }
264  return lposition[1];
265  }
266 
272  float value(const Vector3D& position) const {
273  using VectorHelpers::eta;
274  using VectorHelpers::perp;
275  using VectorHelpers::phi;
276  // ordered after occurence
277  if (binvalue == binR || binvalue == binH) {
278  return (perp(position));
279  }
280  if (binvalue == binRPhi) {
281  return (perp(position) * phi(position));
282  }
283  if (binvalue == binEta) {
284  return (eta(position));
285  }
286  if (binvalue < 3) {
287  return (position[binvalue]);
288  }
289  // phi gauging
290  return phi(position);
291  }
292 
298  float center(size_t bin) const {
299  const std::vector<float>& bvals = boundaries();
300  // take the center between bin boundaries
301  float value = bin < bvals.size() ? 0.5 * (bvals[bin] + bvals[bin + 1]) : 0.;
302  return value;
303  }
304 
310  bool inside(const Vector3D& position) const {
311  // closed one is always inside
312  if (option == closed) {
313  return true;
314  }
315  // all other options
316  // @todo remove hard-coded tolerance parameters
317  float val = value(position);
318  return (val > min - 0.001 && val < max + 0.001);
319  }
320 
326  bool inside(const Vector2D& lposition) const {
327  // closed one is always inside
328  if (option == closed) {
329  return true;
330  }
331  // all other options
332  // @todo remove hard-coded tolerance parameters
333  float val = value(lposition);
334  return (val > min - 0.001 && val < max + 0.001);
335  }
336 
342  size_t searchLocal(const Vector2D& lposition) const {
343  if (zdim) {
344  return 0;
345  }
346  return search(value(lposition));
347  }
348 
354  size_t searchGlobal(const Vector3D& position) const {
355  if (zdim) {
356  return 0;
357  }
358  return search(value(position));
359  }
360 
366  size_t search(float value) const {
367  if (zdim) {
368  return 0;
369  }
370  assert(m_functionPtr != nullptr);
371  return (!subBinningData) ? (*m_functionPtr)(value, *this)
372  : searchWithSubStructure(value);
373  }
374 
381  size_t searchWithSubStructure(float value) const {
382  // find the masterbin with the correct function pointer
383  size_t masterbin = (*m_functionPtr)(value, *this);
384  // additive sub binning -
385  if (subBinningAdditive) {
386  // no gauging done, for additive sub structure
387  return masterbin + subBinningData->search(value);
388  }
389  // gauge the value to the subBinData
390  float gvalue =
391  value - masterbin * (subBinningData->max - subBinningData->min);
392  // now go / additive or multiplicative
393  size_t subbin = subBinningData->search(gvalue);
394  // now return
395  return masterbin * subBinningData->bins() + subbin;
396  }
397 
405  int nextDirection(const Vector3D& position, const Vector3D& dir) const {
406  if (zdim) {
407  return 0;
408  }
409  float val = value(position);
410  Vector3D probe = position + dir.normalized();
411  float nextval = value(probe);
412  return (nextval > val) ? 1 : -1;
413  }
414 
422  float centerValue(size_t bin) const {
423  if (zdim) {
424  return 0.5 * (min + max);
425  }
426  float bmin = m_boundaries[bin];
427  float bmax = bin < m_boundaries.size() ? m_boundaries[bin + 1] : max;
428  return 0.5 * (bmin + bmax);
429  }
430 
436  std::vector<size_t> neighbourRange(size_t bin) const {
437  size_t low = bin;
438  size_t high = bin;
439  // decrement and increment
440  bool dsucc = decrement(low);
441  bool isucc = increment(high);
442  // both worked -> triple range
443  if (dsucc && isucc) {
444  return {low, bin, high};
445  }
446  // one worked -> double range
447  if (dsucc || isucc) {
448  return {low, high};
449  }
450  // none worked -> single bin
451  return {bin};
452  }
453 
454  private:
455  size_t m_bins;
456  std::vector<float> m_boundaries;
457  size_t m_totalBins;
458  std::vector<float> m_totalBoundaries;
459 
460  size_t (*m_functionPtr)(float, const BinningData&);
461 
464  // sub structure is only checked when sBinData is defined
465  if (subBinningData) {
466  m_totalBoundaries.clear();
467  // (A) additive sub structure
468  if (subBinningAdditive) {
469  // one bin is replaced by the sub bins
470  m_totalBins = m_bins + subBinningData->bins() - 1;
471  // the tricky one - exchange one bin by many others
472  m_totalBoundaries.reserve(m_totalBins + 1);
473  // get the sub bin boundaries
474  const std::vector<float>& subBinBoundaries =
475  subBinningData->boundaries();
476  float sBinMin = subBinBoundaries[0];
477  // get the min value of the sub bin boundaries
478  std::vector<float>::const_iterator mbvalue = m_boundaries.begin();
479  for (; mbvalue != m_boundaries.end(); ++mbvalue) {
480  // should define numerically stable
481  if (std::abs((*mbvalue) - sBinMin) < 10e-10) {
482  // copy the sub bin boundaries into the vector
483  m_totalBoundaries.insert(m_totalBoundaries.begin(),
484  subBinBoundaries.begin(),
485  subBinBoundaries.end());
486  ++mbvalue;
487  } else {
488  m_totalBoundaries.push_back(*mbvalue);
489  }
490  }
491  } else { // (B) multiplicative sub structure
492  // every bin is just repaced by the sub binning structure
493  m_totalBins = m_bins * subBinningData->bins();
494  m_totalBoundaries.reserve(m_totalBins + 1);
495  // get the sub bin boundaries if there are any
496  const std::vector<float>& subBinBoundaries =
497  subBinningData->boundaries();
498  // create the boundary vector
499  m_totalBoundaries.push_back(min);
500  for (size_t ib = 0; ib < m_bins; ++ib) {
501  float offset = ib * step;
502  for (size_t isb = 1; isb < subBinBoundaries.size(); ++isb) {
503  m_totalBoundaries.push_back(offset + subBinBoundaries[isb]);
504  }
505  }
506  }
507  // sort the total boundary vector
508  std::sort(m_totalBoundaries.begin(), m_totalBoundaries.end());
509  }
510  }
511 
512  // Equidistant search
513  // - fastest method
515  const BinningData& bData) {
516  // vanilla
517 
518  int bin = ((value - bData.min) / bData.step);
519  // special treatment of the 0 bin for closed
520  if (bData.option == closed) {
521  if (value < bData.min) {
522  return (bData.m_bins - 1);
523  }
524  if (value > bData.max) {
525  return 0;
526  }
527  }
528  // if outside boundary : return boundary for open, opposite bin for closed
529  bin = bin < 0 ? ((bData.option == open) ? 0 : (bData.m_bins - 1)) : bin;
530  return size_t((bin <= int(bData.m_bins - 1))
531  ? bin
532  : ((bData.option == open) ? (bData.m_bins - 1) : 0));
533  }
534 
535  // Linear search in arbitrary vector
536  // - superior in O(10) searches
537  static size_t searchInVectorWithBoundary(float value,
538  const BinningData& bData) {
539  // lower boundary
540  if (value <= bData.m_boundaries[0]) {
541  return (bData.option == closed) ? (bData.m_bins - 1) : 0;
542  }
543  // higher boundary
544  if (value >= bData.max) {
545  return (bData.option == closed) ? 0 : (bData.m_bins - 1);
546  }
547  // search
548  auto vIter = bData.m_boundaries.begin();
549  size_t bin = 0;
550  for (; vIter != bData.m_boundaries.end(); ++vIter, ++bin) {
551  if ((*vIter) > value) {
552  break;
553  }
554  }
555  return (bin - 1);
556  }
557 
558  // A binary search with in an arbitrary vector
559  // - faster than vector search for O(50) objects
560  static size_t binarySearchWithBoundary(float value,
561  const BinningData& bData) {
562  // Binary search in an array of n values to locate value
563  if (value <= bData.m_boundaries[0]) {
564  return (bData.option == closed) ? (bData.m_bins - 1) : 0;
565  }
566  size_t nabove, nbelow, middle;
567  // overflow
568  nabove = bData.m_boundaries.size();
569  if (value >= bData.max) {
570  return (bData.option == closed) ? 0 : nabove - 2;
571  }
572  // binary search
573  nbelow = 0;
574  while (nabove - nbelow > 1) {
575  middle = (nabove + nbelow) / 2;
576  if (value == bData.m_boundaries[middle - 1]) {
577  return middle - 1;
578  }
579  if (value < bData.m_boundaries[middle - 1]) {
580  nabove = middle;
581  } else {
582  nbelow = middle;
583  }
584  }
585  return nbelow - 1;
586  }
587 };
588 } // namespace Acts