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
17 
18 #include <cmath>
19 #include <iostream>
20 #include <memory>
21 #include <utility>
22 #include <vector>
23 
24 namespace Acts {
25 
41 class BinningData {
42  public:
46  float min;
47  float max;
48  float step;
49  bool zdim;
50 
52  std::unique_ptr<const BinningData> subBinningData;
55 
61  BinningData(BinningValue bValue, float bMin, float bMax)
62  : type(equidistant),
63  option(open),
64  binvalue(bValue),
65  min(bMin),
66  max(bMax),
67  step((bMax - bMin)),
68  zdim(true),
69  subBinningData(nullptr),
71  m_bins(1),
72  m_boundaries({{min, max}}),
73  m_totalBins(1),
74  m_totalBoundaries(std::vector<float>()),
76 
88  BinningData(BinningOption bOption, BinningValue bValue, size_t bBins,
89  float bMin, float bMax,
90  std::unique_ptr<const BinningData> sBinData = nullptr,
91  bool sBinAdditive = false)
92  : type(equidistant),
93  option(bOption),
94  binvalue(bValue),
95  min(bMin),
96  max(bMax),
97  step((bMax - bMin) / bBins),
98  zdim(bBins == 1 ? true : false),
99  subBinningData(std::move(sBinData)),
100  subBinningAdditive(sBinAdditive),
101  m_bins(bBins),
102  m_boundaries(std::vector<float>()),
103  m_totalBins(bBins),
104  m_totalBoundaries(std::vector<float>()),
105  m_functionPtr(nullptr) {
106  // set to equidistant search
108  // fill the boundary vector for fast access to center & boundaries
109  m_boundaries.reserve(m_bins + 1);
110  for (size_t ib = 0; ib < m_bins + 1; ++ib) {
111  m_boundaries.push_back(min + ib * step);
112  }
113  // the binning data has sub structure - multiplicative or additive
115  }
116 
124  const std::vector<float>& bBoundaries,
125  std::unique_ptr<const BinningData> sBinData = nullptr)
126  : type(arbitrary),
127  option(bOption),
128  binvalue(bValue),
129  min(0.),
130  max(0.),
131  step(0.),
132  zdim(bBoundaries.size() == 2 ? true : false),
133  subBinningData(std::move(sBinData)),
135  m_bins(bBoundaries.size() - 1),
136  m_boundaries(bBoundaries),
137  m_totalBins(bBoundaries.size() - 1),
138  m_totalBoundaries(bBoundaries),
139  m_functionPtr(nullptr) {
140  // assert a no-size case
141  throw_assert(m_boundaries.size() > 1, "Must have more than one boundary");
142  min = m_boundaries[0];
143  max = m_boundaries[m_boundaries.size() - 1];
144  // set to equidistant search
145  m_functionPtr =
147  // the binning data has sub structure - multiplicative
149  }
150 
154  BinningData(const BinningData& bdata)
155  : type(bdata.type),
156  option(bdata.option),
157  binvalue(bdata.binvalue),
158  min(bdata.min),
159  max(bdata.max),
160  step(bdata.step),
161  zdim(bdata.zdim),
162  subBinningData(nullptr),
164  m_bins(bdata.m_bins),
165  m_boundaries(bdata.m_boundaries),
166  m_totalBins(bdata.m_totalBins),
168  m_functionPtr(nullptr) {
169  // get the binning data
171  bdata.subBinningData
172  ? std::make_unique<const BinningData>(*bdata.subBinningData)
173  : nullptr;
174  // set the pointer depending on the type
175  // set the correct function pointer
176  if (type == equidistant) {
178  } else {
179  m_functionPtr =
181  }
182  }
183 
188  if (this != &bdata) {
189  type = bdata.type;
190  option = bdata.option;
191  binvalue = bdata.binvalue;
192  min = bdata.min;
193  max = bdata.max;
194  step = bdata.step;
195  zdim = bdata.zdim;
198  bdata.subBinningData
199  ? std::make_unique<const BinningData>(*bdata.subBinningData)
200  : nullptr;
201  m_bins = bdata.m_bins;
202  m_boundaries = bdata.m_boundaries;
203  m_totalBins = bdata.m_totalBins;
205  // set the correct function pointer
206  if (type == equidistant) {
208  } else {
211  }
212  }
213  return (*this);
214  }
215 
217  ~BinningData() = default;
218 
220  size_t bins() const { return m_totalBins; }
221 
226  bool decrement(size_t& bin) const {
227  size_t sbin = bin;
228  bin = bin > 0 ? bin - 1 : (option == open ? bin : m_bins - 1);
229  return (sbin != bin);
230  }
231 
236  bool increment(size_t& bin) const {
237  size_t sbin = bin;
238  bin = bin + 1 < m_bins ? bin + 1 : (option == open ? bin : 0);
239  return (sbin != bin);
240  }
241 
244  const std::vector<float>& boundaries() const {
245  if (subBinningData) {
246  return m_totalBoundaries;
247  }
248  return m_boundaries;
249  }
250 
256  float value(const Vector2D& lposition) const {
257  // ordered after occurence
258  if (binvalue == binR || binvalue == binRPhi || binvalue == binX ||
259  binvalue == binH) {
260  return lposition[0];
261  }
262  if (binvalue == binPhi) {
263  return lposition[1];
264  }
265  return lposition[1];
266  }
267 
273  float value(const Vector3D& position) const {
274  using VectorHelpers::eta;
275  using VectorHelpers::perp;
276  using VectorHelpers::phi;
277  // ordered after occurence
278  if (binvalue == binR || binvalue == binH) {
279  return (perp(position));
280  }
281  if (binvalue == binRPhi) {
282  return (perp(position) * phi(position));
283  }
284  if (binvalue == binEta) {
285  return (eta(position));
286  }
287  if (binvalue < 3) {
288  return (position[binvalue]);
289  }
290  // phi gauging
291  return phi(position);
292  }
293 
299  float center(size_t bin) const {
300  const std::vector<float>& bvals = boundaries();
301  // take the center between bin boundaries
302  float value = bin < bvals.size() ? 0.5 * (bvals[bin] + bvals[bin + 1]) : 0.;
303  return value;
304  }
305 
311  bool inside(const Vector3D& position) const {
312  // closed one is always inside
313  if (option == closed) {
314  return true;
315  }
316  // all other options
317  // @todo remove hard-coded tolerance parameters
318  float val = value(position);
319  return (val > min - 0.001 && val < max + 0.001);
320  }
321 
327  bool inside(const Vector2D& lposition) const {
328  // closed one is always inside
329  if (option == closed) {
330  return true;
331  }
332  // all other options
333  // @todo remove hard-coded tolerance parameters
334  float val = value(lposition);
335  return (val > min - 0.001 && val < max + 0.001);
336  }
337 
343  size_t searchLocal(const Vector2D& lposition) const {
344  if (zdim) {
345  return 0;
346  }
347  return search(value(lposition));
348  }
349 
355  size_t searchGlobal(const Vector3D& position) const {
356  if (zdim) {
357  return 0;
358  }
359  return search(value(position));
360  }
361 
367  size_t search(float value) const {
368  if (zdim) {
369  return 0;
370  }
371  assert(m_functionPtr != nullptr);
372  return (!subBinningData) ? (*m_functionPtr)(value, *this)
373  : searchWithSubStructure(value);
374  }
375 
382  size_t searchWithSubStructure(float value) const {
383  // find the masterbin with the correct function pointer
384  size_t masterbin = (*m_functionPtr)(value, *this);
385  // additive sub binning -
386  if (subBinningAdditive) {
387  // no gauging done, for additive sub structure
388  return masterbin + subBinningData->search(value);
389  }
390  // gauge the value to the subBinData
391  float gvalue =
392  value - masterbin * (subBinningData->max - subBinningData->min);
393  // now go / additive or multiplicative
394  size_t subbin = subBinningData->search(gvalue);
395  // now return
396  return masterbin * subBinningData->bins() + subbin;
397  }
398 
406  int nextDirection(const Vector3D& position, const Vector3D& dir) const {
407  if (zdim) {
408  return 0;
409  }
410  float val = value(position);
411  Vector3D probe = position + dir.normalized();
412  float nextval = value(probe);
413  return (nextval > val) ? 1 : -1;
414  }
415 
423  float centerValue(size_t bin) const {
424  if (zdim) {
425  return 0.5 * (min + max);
426  }
427  float bmin = m_boundaries[bin];
428  float bmax = bin < m_boundaries.size() ? m_boundaries[bin + 1] : max;
429  return 0.5 * (bmin + bmax);
430  }
431 
437  std::vector<size_t> neighbourRange(size_t bin) const {
438  size_t low = bin;
439  size_t high = bin;
440  // decrement and increment
441  bool dsucc = decrement(low);
442  bool isucc = increment(high);
443  // both worked -> triple range
444  if (dsucc && isucc) {
445  return {low, bin, high};
446  }
447  // one worked -> double range
448  if (dsucc || isucc) {
449  return {low, high};
450  }
451  // none worked -> single bin
452  return {bin};
453  }
454 
455  private:
456  size_t m_bins;
457  std::vector<float> m_boundaries;
458  size_t m_totalBins;
459  std::vector<float> m_totalBoundaries;
460 
461  size_t (*m_functionPtr)(float, const BinningData&);
462 
465  // sub structure is only checked when sBinData is defined
466  if (subBinningData) {
467  m_totalBoundaries.clear();
468  // (A) additive sub structure
469  if (subBinningAdditive) {
470  // one bin is replaced by the sub bins
471  m_totalBins = m_bins + subBinningData->bins() - 1;
472  // the tricky one - exchange one bin by many others
473  m_totalBoundaries.reserve(m_totalBins + 1);
474  // get the sub bin boundaries
475  const std::vector<float>& subBinBoundaries =
476  subBinningData->boundaries();
477  float sBinMin = subBinBoundaries[0];
478  // get the min value of the sub bin boundaries
479  std::vector<float>::const_iterator mbvalue = m_boundaries.begin();
480  for (; mbvalue != m_boundaries.end(); ++mbvalue) {
481  // should define numerically stable
482  if (std::abs((*mbvalue) - sBinMin) < 10e-10) {
483  // copy the sub bin boundaries into the vector
484  m_totalBoundaries.insert(m_totalBoundaries.begin(),
485  subBinBoundaries.begin(),
486  subBinBoundaries.end());
487  ++mbvalue;
488  } else {
489  m_totalBoundaries.push_back(*mbvalue);
490  }
491  }
492  } else { // (B) multiplicative sub structure
493  // every bin is just repaced by the sub binning structure
494  m_totalBins = m_bins * subBinningData->bins();
495  m_totalBoundaries.reserve(m_totalBins + 1);
496  // get the sub bin boundaries if there are any
497  const std::vector<float>& subBinBoundaries =
498  subBinningData->boundaries();
499  // create the boundary vector
500  m_totalBoundaries.push_back(min);
501  for (size_t ib = 0; ib < m_bins; ++ib) {
502  float offset = ib * step;
503  for (size_t isb = 1; isb < subBinBoundaries.size(); ++isb) {
504  m_totalBoundaries.push_back(offset + subBinBoundaries[isb]);
505  }
506  }
507  }
508  // sort the total boundary vector
509  std::sort(m_totalBoundaries.begin(), m_totalBoundaries.end());
510  }
511  }
512 
513  // Equidistant search
514  // - fastest method
516  const BinningData& bData) {
517  // vanilla
518 
519  int bin = ((value - bData.min) / bData.step);
520  // special treatment of the 0 bin for closed
521  if (bData.option == closed) {
522  if (value < bData.min) {
523  return (bData.m_bins - 1);
524  }
525  if (value > bData.max) {
526  return 0;
527  }
528  }
529  // if outside boundary : return boundary for open, opposite bin for closed
530  bin = bin < 0 ? ((bData.option == open) ? 0 : (bData.m_bins - 1)) : bin;
531  return size_t((bin <= int(bData.m_bins - 1))
532  ? bin
533  : ((bData.option == open) ? (bData.m_bins - 1) : 0));
534  }
535 
536  // Linear search in arbitrary vector
537  // - superior in O(10) searches
538  static size_t searchInVectorWithBoundary(float value,
539  const BinningData& bData) {
540  // lower boundary
541  if (value <= bData.m_boundaries[0]) {
542  return (bData.option == closed) ? (bData.m_bins - 1) : 0;
543  }
544  // higher boundary
545  if (value >= bData.max) {
546  return (bData.option == closed) ? 0 : (bData.m_bins - 1);
547  }
548  // search
549  auto vIter = bData.m_boundaries.begin();
550  size_t bin = 0;
551  for (; vIter != bData.m_boundaries.end(); ++vIter, ++bin) {
552  if ((*vIter) > value) {
553  break;
554  }
555  }
556  return (bin - 1);
557  }
558 
559  // A binary search with in an arbitrary vector
560  // - faster than vector search for O(50) objects
561  static size_t binarySearchWithBoundary(float value,
562  const BinningData& bData) {
563  // Binary search in an array of n values to locate value
564  if (value <= bData.m_boundaries[0]) {
565  return (bData.option == closed) ? (bData.m_bins - 1) : 0;
566  }
567  size_t nabove, nbelow, middle;
568  // overflow
569  nabove = bData.m_boundaries.size();
570  if (value >= bData.max) {
571  return (bData.option == closed) ? 0 : nabove - 2;
572  }
573  // binary search
574  nbelow = 0;
575  while (nabove - nbelow > 1) {
576  middle = (nabove + nbelow) / 2;
577  if (value == bData.m_boundaries[middle - 1]) {
578  return middle - 1;
579  }
580  if (value < bData.m_boundaries[middle - 1]) {
581  nabove = middle;
582  } else {
583  nbelow = middle;
584  }
585  }
586  return nbelow - 1;
587  }
588 };
589 } // namespace Acts