Analysis Software
Documentation for sPHENIX simulation 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 
9 #pragma once
10 
15 
16 #include <algorithm>
17 #include <cmath>
18 #include <memory>
19 #include <sstream>
20 #include <string>
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),
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  // set to equidistant search
106  // fill the boundary vector for fast access to center & boundaries
107  m_boundaries.reserve(m_bins + 1);
108  for (size_t ib = 0; ib < m_bins + 1; ++ib) {
109  m_boundaries.push_back(min + ib * step);
110  }
111  // the binning data has sub structure - multiplicative or additive
113  }
114 
122  const std::vector<float>& bBoundaries,
123  std::unique_ptr<const BinningData> sBinData = nullptr)
124  : type(arbitrary),
125  option(bOption),
126  binvalue(bValue),
127  zdim(bBoundaries.size() == 2 ? true : false),
128  subBinningData(std::move(sBinData)),
130  m_bins(bBoundaries.size() - 1),
131  m_boundaries(bBoundaries),
132  m_totalBins(bBoundaries.size() - 1),
133  m_totalBoundaries(bBoundaries) {
134  // assert a no-size case
135  throw_assert(m_boundaries.size() > 1, "Must have more than one boundary");
136  min = m_boundaries[0];
137  max = m_boundaries[m_boundaries.size() - 1];
138  // set to equidistant search
140  // the binning data has sub structure - multiplicative
142  }
143 
147  BinningData(const BinningData& bdata)
148  : type(bdata.type),
149  option(bdata.option),
150  binvalue(bdata.binvalue),
151  min(bdata.min),
152  max(bdata.max),
153  step(bdata.step),
154  zdim(bdata.zdim),
155  subBinningData(nullptr),
157  m_bins(bdata.m_bins),
158  m_boundaries(bdata.m_boundaries),
159  m_totalBins(bdata.m_totalBins),
161  // get the binning data
163  bdata.subBinningData
164  ? std::make_unique<const BinningData>(*bdata.subBinningData)
165  : nullptr;
166  // set the pointer depending on the type
167  // set the correct function pointer
168  if (type == equidistant) {
170  } else {
172  }
173  }
174 
179  if (this != &bdata) {
180  type = bdata.type;
181  option = bdata.option;
182  binvalue = bdata.binvalue;
183  min = bdata.min;
184  max = bdata.max;
185  step = bdata.step;
186  zdim = bdata.zdim;
189  bdata.subBinningData
190  ? std::make_unique<const BinningData>(*bdata.subBinningData)
191  : nullptr;
192  m_bins = bdata.m_bins;
193  m_boundaries = bdata.m_boundaries;
194  m_totalBins = bdata.m_totalBins;
196  // set the correct function pointer
197  if (type == equidistant) {
199  } else {
201  }
202  }
203  return (*this);
204  }
205 
206  BinningData() = default;
207  ~BinningData() = default;
208 
214  bool operator==(const BinningData& bData) const {
215  return (type == bData.type and option == bData.option and
216  binvalue == bData.binvalue and min == bData.min and
217  max == bData.max and step == bData.step and zdim == bData.zdim and
218  ((subBinningData == nullptr and bData.subBinningData == nullptr) or
219  (subBinningData != nullptr and bData.subBinningData != nullptr and
220  (*subBinningData == *bData.subBinningData))) and
222  }
223 
225  size_t bins() const { return m_totalBins; }
226 
229  const std::vector<float>& boundaries() const {
230  if (subBinningData) {
231  return m_totalBoundaries;
232  }
233  return m_boundaries;
234  }
235 
241  float value(const Vector2& lposition) const {
242  // ordered after occurrence
243  if (binvalue == binR || binvalue == binRPhi || binvalue == binX ||
244  binvalue == binH) {
245  return lposition[0];
246  }
247  if (binvalue == binPhi) {
248  return lposition[1];
249  }
250  return lposition[1];
251  }
252 
258  float value(const Vector3& position) const {
259  using VectorHelpers::eta;
260  using VectorHelpers::perp;
261  using VectorHelpers::phi;
262  // ordered after occurrence
263  if (binvalue == binR || binvalue == binH) {
264  return (perp(position));
265  }
266  if (binvalue == binRPhi) {
267  return (perp(position) * phi(position));
268  }
269  if (binvalue == binEta) {
270  return (eta(position));
271  }
272  if (binvalue < 3) {
273  return (position[binvalue]);
274  }
275  // phi gauging
276  return phi(position);
277  }
278 
284  float center(size_t bin) const {
285  const std::vector<float>& bvals = boundaries();
286  // take the center between bin boundaries
287  float value =
288  bin < (bvals.size() - 1) ? 0.5 * (bvals[bin] + bvals[bin + 1]) : 0.;
289  return value;
290  }
291 
297  float width(size_t bin) const {
298  const std::vector<float>& bvals = boundaries();
299  // take the center between bin boundaries
300  float value = bin < (bvals.size() - 1) ? bvals[bin + 1] - bvals[bin] : 0.;
301  return value;
302  }
303 
309  bool inside(const Vector3& position) const {
310  // closed one is always inside
311  if (option == closed) {
312  return true;
313  }
314  // all other options
315  // @todo remove hard-coded tolerance parameters
316  float val = value(position);
317  return (val > min - 0.001 && val < max + 0.001);
318  }
319 
325  bool inside(const Vector2& lposition) const {
326  // closed one is always inside
327  if (option == closed) {
328  return true;
329  }
330  // all other options
331  // @todo remove hard-coded tolerance parameters
332  float val = value(lposition);
333  return (val > min - 0.001 && val < max + 0.001);
334  }
335 
341  size_t searchLocal(const Vector2& lposition) const {
342  if (zdim) {
343  return 0;
344  }
345  return search(value(lposition));
346  }
347 
353  size_t searchGlobal(const Vector3& position) const {
354  if (zdim) {
355  return 0;
356  }
357  return search(value(position));
358  }
359 
365  size_t search(float value) const {
366  if (zdim) {
367  return 0;
368  }
369  assert(m_functionPtr != nullptr);
370  return (!subBinningData) ? (*m_functionPtr)(value, *this)
371  : searchWithSubStructure(value);
372  }
373 
380  size_t searchWithSubStructure(float value) const {
381  // find the masterbin with the correct function pointer
382  size_t masterbin = (*m_functionPtr)(value, *this);
383  // additive sub binning -
384  if (subBinningAdditive) {
385  // no gauging done, for additive sub structure
386  return masterbin + subBinningData->search(value);
387  }
388  // gauge the value to the subBinData
389  float gvalue =
390  value - masterbin * (subBinningData->max - subBinningData->min);
391  // now go / additive or multiplicative
392  size_t subbin = subBinningData->search(gvalue);
393  // now return
394  return masterbin * subBinningData->bins() + subbin;
395  }
396 
404  int nextDirection(const Vector3& position, const Vector3& dir) const {
405  if (zdim) {
406  return 0;
407  }
408  float val = value(position);
409  Vector3 probe = position + dir.normalized();
410  float nextval = value(probe);
411  return (nextval > val) ? 1 : -1;
412  }
413 
421  float centerValue(size_t bin) const {
422  if (zdim) {
423  return 0.5 * (min + max);
424  }
425  float bmin = m_boundaries[bin];
426  float bmax = bin < m_boundaries.size() ? m_boundaries[bin + 1] : max;
427  return 0.5 * (bmin + bmax);
428  }
429 
430  private:
431  size_t m_bins{};
432  std::vector<float> m_boundaries;
433  size_t m_totalBins{};
434  std::vector<float> m_totalBoundaries;
435 
436  size_t (*m_functionPtr)(float, const BinningData&){};
437 
440  // sub structure is only checked when sBinData is defined
441  if (subBinningData) {
442  m_totalBoundaries.clear();
443  // (A) additive sub structure
444  if (subBinningAdditive) {
445  // one bin is replaced by the sub bins
446  m_totalBins = m_bins + subBinningData->bins() - 1;
447  // the tricky one - exchange one bin by many others
448  m_totalBoundaries.reserve(m_totalBins + 1);
449  // get the sub bin boundaries
450  const std::vector<float>& subBinBoundaries =
451  subBinningData->boundaries();
452  float sBinMin = subBinBoundaries[0];
453  // get the min value of the sub bin boundaries
454  std::vector<float>::const_iterator mbvalue = m_boundaries.begin();
455  for (; mbvalue != m_boundaries.end(); ++mbvalue) {
456  // should define numerically stable
457  if (std::abs((*mbvalue) - sBinMin) < 10e-10) {
458  // copy the sub bin boundaries into the vector
459  m_totalBoundaries.insert(m_totalBoundaries.begin(),
460  subBinBoundaries.begin(),
461  subBinBoundaries.end());
462  ++mbvalue;
463  } else {
464  m_totalBoundaries.push_back(*mbvalue);
465  }
466  }
467  } else { // (B) multiplicative sub structure
468  // every bin is just replaced by the sub binning structure
469  m_totalBins = m_bins * subBinningData->bins();
470  m_totalBoundaries.reserve(m_totalBins + 1);
471  // get the sub bin boundaries if there are any
472  const std::vector<float>& subBinBoundaries =
473  subBinningData->boundaries();
474  // create the boundary vector
475  m_totalBoundaries.push_back(min);
476  for (size_t ib = 0; ib < m_bins; ++ib) {
477  float offset = ib * step;
478  for (size_t isb = 1; isb < subBinBoundaries.size(); ++isb) {
479  m_totalBoundaries.push_back(offset + subBinBoundaries[isb]);
480  }
481  }
482  }
483  // sort the total boundary vector
485  }
486  }
487 
488  // Equidistant search
489  // - fastest method
491  const BinningData& bData) {
492  // vanilla
493 
494  int bin = static_cast<int>((value - bData.min) / bData.step);
495  // special treatment of the 0 bin for closed
496  if (bData.option == closed) {
497  if (value < bData.min) {
498  return (bData.m_bins - 1);
499  }
500  if (value > bData.max) {
501  return 0;
502  }
503  }
504  // if outside boundary : return boundary for open, opposite bin for closed
505  bin = bin < 0 ? ((bData.option == open) ? 0 : (bData.m_bins - 1)) : bin;
506  return size_t((bin <= int(bData.m_bins - 1))
507  ? bin
508  : ((bData.option == open) ? (bData.m_bins - 1) : 0));
509  }
510 
511  // Search in arbitrary boundary
512  static size_t searchInVectorWithBoundary(float value,
513  const BinningData& bData) {
514  // lower boundary
515  if (value <= bData.m_boundaries[0]) {
516  return (bData.option == closed) ? (bData.m_bins - 1) : 0;
517  }
518  // higher boundary
519  if (value >= bData.max) {
520  return (bData.option == closed) ? 0 : (bData.m_bins - 1);
521  }
522 
523  auto lb = std::lower_bound(bData.m_boundaries.begin(),
524  bData.m_boundaries.end(), value);
525  return static_cast<size_t>(std::distance(bData.m_boundaries.begin(), lb) -
526  1);
527  }
528 
529  public:
533  std::string toString(const std::string& indent) const {
534  std::stringstream sl;
535  sl << indent << "BinngingData object:" << '\n';
536  sl << indent << " - type : " << size_t(type) << '\n';
537  sl << indent << " - option : " << size_t(option) << '\n';
538  sl << indent << " - value : " << size_t(binvalue) << '\n';
539  sl << indent << " - bins : " << bins() << '\n';
540  sl << indent << " - min/max : " << min << " / " << max << '\n';
541  if (type == equidistant) {
542  sl << indent << " - step : " << step << '\n';
543  }
544  sl << indent << " - boundaries : | ";
545  for (const auto& b : boundaries()) {
546  sl << b << " | ";
547  }
548  sl << '\n';
549  return sl.str();
550  }
551 };
552 } // namespace Acts