ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SurfaceArrayCreator.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file SurfaceArrayCreator.cpp
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 // SurfaceArrayCreator.cpp, Acts project
12 
14 #include <algorithm>
15 #include <cmath>
16 #include <stdexcept>
24 #include "Acts/Utilities/Units.hpp"
26 
29 
30 std::unique_ptr<Acts::SurfaceArray>
32  const GeometryContext& gctx,
33  std::vector<std::shared_ptr<const Surface>> surfaces, size_t binsPhi,
34  size_t binsZ, std::optional<ProtoLayer> protoLayerOpt,
35  const std::shared_ptr<const Transform3D>& transformOpt) const {
36  std::vector<const Surface*> surfacesRaw = unpack_shared_vector(surfaces);
37  // check if we have proto layer, else build it
38  ProtoLayer protoLayer =
39  protoLayerOpt ? *protoLayerOpt : ProtoLayer(gctx, surfacesRaw);
40 
41  ACTS_VERBOSE("Creating a SurfaceArray on a cylinder");
42  ACTS_VERBOSE(" -- with " << surfaces.size() << " surfaces.")
43  ACTS_VERBOSE(" -- with phi x z = " << binsPhi << " x " << binsZ << " = "
44  << binsPhi * binsZ << " bins.");
45 
47  transformOpt != nullptr ? *transformOpt : Transform3D::Identity();
48 
49  ProtoAxis pAxisPhi = createEquidistantAxis(gctx, surfacesRaw, binPhi,
50  protoLayer, transform, binsPhi);
51  ProtoAxis pAxisZ = createEquidistantAxis(gctx, surfacesRaw, binZ, protoLayer,
52  transform, binsZ);
53 
54  double R = protoLayer.maxR - protoLayer.minR;
55 
56  Transform3D itransform = transform.inverse();
57  // transform lambda captures the transform matrix
58  auto globalToLocal = [transform](const Vector3D& pos) {
59  Vector3D loc = transform * pos;
60  return Vector2D(phi(loc), loc.z());
61  };
62  auto localToGlobal = [itransform, R](const Vector2D& loc) {
63  return itransform *
64  Vector3D(R * std::cos(loc[0]), R * std::sin(loc[0]), loc[1]);
65  };
66 
67  std::unique_ptr<SurfaceArray::ISurfaceGridLookup> sl =
68  makeSurfaceGridLookup2D<detail::AxisBoundaryType::Closed,
69  detail::AxisBoundaryType::Bound>(
70  globalToLocal, localToGlobal, pAxisPhi, pAxisZ);
71 
72  sl->fill(gctx, surfacesRaw);
73  completeBinning(gctx, *sl, surfacesRaw);
74 
75  return std::make_unique<SurfaceArray>(
76  std::move(sl), std::move(surfaces),
77  std::make_shared<const Transform3D>(transform));
78 }
79 
80 std::unique_ptr<Acts::SurfaceArray>
82  const GeometryContext& gctx,
83  std::vector<std::shared_ptr<const Surface>> surfaces, BinningType bTypePhi,
84  BinningType bTypeZ, std::optional<ProtoLayer> protoLayerOpt,
85  const std::shared_ptr<const Transform3D>& transformOpt) const {
86  std::vector<const Surface*> surfacesRaw = unpack_shared_vector(surfaces);
87  // check if we have proto layer, else build it
88  ProtoLayer protoLayer =
89  protoLayerOpt ? *protoLayerOpt : ProtoLayer(gctx, surfacesRaw);
90 
91  double R = 0.5 * (protoLayer.maxR - protoLayer.minR);
93  transformOpt != nullptr ? *transformOpt : Transform3D::Identity();
94 
95  ProtoAxis pAxisPhi;
96  ProtoAxis pAxisZ;
97 
98  if (bTypePhi == equidistant) {
99  pAxisPhi = createEquidistantAxis(gctx, surfacesRaw, binPhi, protoLayer,
100  transform, 0);
101  } else {
102  pAxisPhi =
103  createVariableAxis(gctx, surfacesRaw, binPhi, protoLayer, transform);
104  }
105 
106  if (bTypeZ == equidistant) {
107  pAxisZ =
108  createEquidistantAxis(gctx, surfacesRaw, binZ, protoLayer, transform);
109  } else {
110  pAxisZ = createVariableAxis(gctx, surfacesRaw, binZ, protoLayer, transform);
111  }
112 
113  Transform3D itransform = transform.inverse();
114  auto globalToLocal = [transform](const Vector3D& pos) {
115  Vector3D loc = transform * pos;
116  return Vector2D(phi(loc), loc.z());
117  };
118  auto localToGlobal = [itransform, R](const Vector2D& loc) {
119  return itransform *
120  Vector3D(R * std::cos(loc[0]), R * std::sin(loc[0]), loc[1]);
121  };
122 
123  std::unique_ptr<SurfaceArray::ISurfaceGridLookup> sl =
124  makeSurfaceGridLookup2D<detail::AxisBoundaryType::Closed,
125  detail::AxisBoundaryType::Bound>(
126  globalToLocal, localToGlobal, pAxisPhi, pAxisZ);
127 
128  sl->fill(gctx, surfacesRaw);
129  completeBinning(gctx, *sl, surfacesRaw);
130 
131  // get the number of bins
132  auto axes = sl->getAxes();
133  size_t bins0 = axes.at(0)->getNBins();
134  size_t bins1 = axes.at(1)->getNBins();
135 
136  ACTS_VERBOSE("Creating a SurfaceArray on a cylinder");
137  ACTS_VERBOSE(" -- with " << surfaces.size() << " surfaces.")
138  ACTS_VERBOSE(" -- with phi x z = " << bins0 << " x " << bins1 << " = "
139  << bins0 * bins1 << " bins.");
140 
141  return std::make_unique<SurfaceArray>(
142  std::move(sl), std::move(surfaces),
143  std::make_shared<const Transform3D>(transform));
144 }
145 
146 std::unique_ptr<Acts::SurfaceArray>
148  const GeometryContext& gctx,
149  std::vector<std::shared_ptr<const Surface>> surfaces, size_t binsR,
150  size_t binsPhi, std::optional<ProtoLayer> protoLayerOpt,
151  const std::shared_ptr<const Transform3D>& transformOpt) const {
152  std::vector<const Surface*> surfacesRaw = unpack_shared_vector(surfaces);
153  // check if we have proto layer, else build it
154  ProtoLayer protoLayer =
155  protoLayerOpt ? *protoLayerOpt : ProtoLayer(gctx, surfacesRaw);
156 
157  ACTS_VERBOSE("Creating a SurfaceArray on a disc");
158 
160  transformOpt != nullptr ? *transformOpt : Transform3D::Identity();
161 
162  ProtoAxis pAxisR = createEquidistantAxis(gctx, surfacesRaw, binR, protoLayer,
163  transform, binsR);
164  ProtoAxis pAxisPhi = createEquidistantAxis(gctx, surfacesRaw, binPhi,
165  protoLayer, transform, binsPhi);
166 
167  double Z = 0.5 * (protoLayer.minZ + protoLayer.maxZ);
168  ACTS_VERBOSE("- z-position of disk estimated as " << Z);
169 
170  Transform3D itransform = transform.inverse();
171  // transform lambda captures the transform matrix
172  auto globalToLocal = [transform](const Vector3D& pos) {
173  Vector3D loc = transform * pos;
174  return Vector2D(perp(loc), phi(loc));
175  };
176  auto localToGlobal = [itransform, Z](const Vector2D& loc) {
177  return itransform *
178  Vector3D(loc[0] * std::cos(loc[1]), loc[0] * std::sin(loc[1]), Z);
179  };
180 
181  std::unique_ptr<SurfaceArray::ISurfaceGridLookup> sl =
182  makeSurfaceGridLookup2D<detail::AxisBoundaryType::Bound,
183  detail::AxisBoundaryType::Closed>(
184  globalToLocal, localToGlobal, pAxisR, pAxisPhi);
185 
186  // get the number of bins
187  auto axes = sl->getAxes();
188  size_t bins0 = axes.at(0)->getNBins();
189  size_t bins1 = axes.at(1)->getNBins();
190 
191  ACTS_VERBOSE(" -- with " << surfaces.size() << " surfaces.")
192  ACTS_VERBOSE(" -- with r x phi = " << bins0 << " x " << bins1 << " = "
193  << bins0 * bins1 << " bins.");
194  sl->fill(gctx, surfacesRaw);
195  completeBinning(gctx, *sl, surfacesRaw);
196 
197  return std::make_unique<SurfaceArray>(
198  std::move(sl), std::move(surfaces),
199  std::make_shared<const Transform3D>(transform));
200 }
201 
202 std::unique_ptr<Acts::SurfaceArray>
204  const GeometryContext& gctx,
205  std::vector<std::shared_ptr<const Surface>> surfaces, BinningType bTypeR,
206  BinningType bTypePhi, std::optional<ProtoLayer> protoLayerOpt,
207  const std::shared_ptr<const Transform3D>& transformOpt) const {
208  std::vector<const Surface*> surfacesRaw = unpack_shared_vector(surfaces);
209  // check if we have proto layer, else build it
210  ProtoLayer protoLayer =
211  protoLayerOpt ? *protoLayerOpt : ProtoLayer(gctx, surfacesRaw);
212 
213  ACTS_VERBOSE("Creating a SurfaceArray on a disc");
214 
216  transformOpt != nullptr ? *transformOpt : Transform3D::Identity();
217 
218  ProtoAxis pAxisPhi;
219  ProtoAxis pAxisR;
220 
221  if (bTypeR == equidistant) {
222  pAxisR =
223  createEquidistantAxis(gctx, surfacesRaw, binR, protoLayer, transform);
224  } else {
225  pAxisR = createVariableAxis(gctx, surfacesRaw, binR, protoLayer, transform);
226  }
227 
228  // if we have more than one R ring, we need to figure out
229  // the number of phi bins.
230  if (pAxisR.nBins > 1) {
231  // more than one R-Ring, we need to adjust
232  // this FORCES equidistant binning
233  std::vector<std::vector<const Surface*>> phiModules(pAxisR.nBins);
234  for (const auto& srf : surfacesRaw) {
235  Vector3D bpos = srf->binningPosition(gctx, binR);
236  size_t bin = pAxisR.getBin(perp(bpos));
237  phiModules.at(bin).push_back(srf);
238  }
239 
240  std::vector<size_t> nPhiModules;
241  auto matcher = m_cfg.surfaceMatcher;
242  auto equal = [&gctx, &matcher](const Surface* a, const Surface* b) {
243  return matcher(gctx, binPhi, a, b);
244  };
245 
247  phiModules.begin(), phiModules.end(), std::back_inserter(nPhiModules),
248  [&equal, this](std::vector<const Surface*> surfaces_) -> size_t {
249  return this->findKeySurfaces(surfaces_, equal).size();
250  });
251 
252  // @FIXME: Problem: phi binning runs rotation to optimize
253  // for bin edges. This FAILS after this modification, since
254  // the bin count is the one from the lowest module-count bin,
255  // but the rotation is done considering all bins.
256  // This might be resolved through bin completion, but not sure.
257  // @TODO: check in extrapolation
258  size_t nBinsPhi =
259  (*std::min_element(nPhiModules.begin(), nPhiModules.end()));
260  pAxisPhi = createEquidistantAxis(gctx, surfacesRaw, binPhi, protoLayer,
261  transform, nBinsPhi);
262 
263  } else {
264  // use regular determination
265  if (bTypePhi == equidistant) {
266  pAxisPhi = createEquidistantAxis(gctx, surfacesRaw, binPhi, protoLayer,
267  transform, 0);
268  } else {
269  pAxisPhi =
270  createVariableAxis(gctx, surfacesRaw, binPhi, protoLayer, transform);
271  }
272  }
273 
274  double Z = 0.5 * (protoLayer.minZ + protoLayer.maxZ);
275  ACTS_VERBOSE("- z-position of disk estimated as " << Z);
276 
277  Transform3D itransform = transform.inverse();
278  // transform lambda captures the transform matrix
279  auto globalToLocal = [transform](const Vector3D& pos) {
280  Vector3D loc = transform * pos;
281  return Vector2D(perp(loc), phi(loc));
282  };
283  auto localToGlobal = [itransform, Z](const Vector2D& loc) {
284  return itransform *
285  Vector3D(loc[0] * std::cos(loc[1]), loc[0] * std::sin(loc[1]), Z);
286  };
287 
288  std::unique_ptr<SurfaceArray::ISurfaceGridLookup> sl =
289  makeSurfaceGridLookup2D<detail::AxisBoundaryType::Bound,
290  detail::AxisBoundaryType::Closed>(
291  globalToLocal, localToGlobal, pAxisR, pAxisPhi);
292 
293  // get the number of bins
294  auto axes = sl->getAxes();
295  size_t bins0 = axes.at(0)->getNBins();
296  size_t bins1 = axes.at(1)->getNBins();
297 
298  ACTS_VERBOSE(" -- with " << surfaces.size() << " surfaces.")
299  ACTS_VERBOSE(" -- with r x phi = " << bins0 << " x " << bins1 << " = "
300  << bins0 * bins1 << " bins.");
301 
302  sl->fill(gctx, surfacesRaw);
303  completeBinning(gctx, *sl, surfacesRaw);
304 
305  return std::make_unique<SurfaceArray>(
306  std::move(sl), std::move(surfaces),
307  std::make_shared<const Transform3D>(transform));
308 }
309 
311 std::unique_ptr<Acts::SurfaceArray>
313  const GeometryContext& gctx,
314  std::vector<std::shared_ptr<const Surface>> surfaces, size_t bins1,
315  size_t bins2, BinningValue bValue, std::optional<ProtoLayer> protoLayerOpt,
316  const std::shared_ptr<const Transform3D>& transformOpt) const {
317  std::vector<const Surface*> surfacesRaw = unpack_shared_vector(surfaces);
318  // check if we have proto layer, else build it
319  ProtoLayer protoLayer =
320  protoLayerOpt ? *protoLayerOpt : ProtoLayer(gctx, surfacesRaw);
321 
322  ACTS_VERBOSE("Creating a SurfaceArray on a plance");
323  ACTS_VERBOSE(" -- with " << surfaces.size() << " surfaces.")
324  ACTS_VERBOSE(" -- with " << bins1 << " x " << bins2 << " = " << bins1 * bins2
325  << " bins.");
326  // Transformation
328  transformOpt != nullptr ? *transformOpt : Transform3D::Identity();
329 
330  Transform3D itransform = transform.inverse();
331  // transform lambda captures the transform matrix
332  auto globalToLocal = [transform](const Vector3D& pos) {
333  Vector3D loc = transform * pos;
334  return Vector2D(loc.x(), loc.y());
335  };
336  auto localToGlobal = [itransform](const Vector2D& loc) {
337  return itransform * Vector3D(loc.x(), loc.y(), 0.);
338  };
339  // Build the grid
340  std::unique_ptr<SurfaceArray::ISurfaceGridLookup> sl;
341 
342  // Axis along the binning
343  switch (bValue) {
344  case BinningValue::binX: {
345  ProtoAxis pAxis1 = createEquidistantAxis(gctx, surfacesRaw, binY,
346  protoLayer, transform, bins1);
347  ProtoAxis pAxis2 = createEquidistantAxis(gctx, surfacesRaw, binZ,
348  protoLayer, transform, bins2);
349  sl = makeSurfaceGridLookup2D<detail::AxisBoundaryType::Bound,
350  detail::AxisBoundaryType::Bound>(
351  globalToLocal, localToGlobal, pAxis1, pAxis2);
352  break;
353  }
354  case BinningValue::binY: {
355  ProtoAxis pAxis1 = createEquidistantAxis(gctx, surfacesRaw, binX,
356  protoLayer, transform, bins1);
357  ProtoAxis pAxis2 = createEquidistantAxis(gctx, surfacesRaw, binZ,
358  protoLayer, transform, bins2);
359  sl = makeSurfaceGridLookup2D<detail::AxisBoundaryType::Bound,
360  detail::AxisBoundaryType::Bound>(
361  globalToLocal, localToGlobal, pAxis1, pAxis2);
362  break;
363  }
364  case BinningValue::binZ: {
365  ProtoAxis pAxis1 = createEquidistantAxis(gctx, surfacesRaw, binX,
366  protoLayer, transform, bins1);
367  ProtoAxis pAxis2 = createEquidistantAxis(gctx, surfacesRaw, binY,
368  protoLayer, transform, bins2);
369  sl = makeSurfaceGridLookup2D<detail::AxisBoundaryType::Bound,
370  detail::AxisBoundaryType::Bound>(
371  globalToLocal, localToGlobal, pAxis1, pAxis2);
372  break;
373  }
374  default: {
375  throw std::invalid_argument(
376  "Acts::SurfaceArrayCreator::"
377  "surfaceArrayOnPlane: Invalid binning "
378  "direction");
379  }
380  }
381 
382  sl->fill(gctx, surfacesRaw);
383  completeBinning(gctx, *sl, surfacesRaw);
384 
385  return std::make_unique<SurfaceArray>(
386  std::move(sl), std::move(surfaces),
387  std::make_shared<const Transform3D>(transform));
389 }
390 
391 std::vector<const Acts::Surface*> Acts::SurfaceArrayCreator::findKeySurfaces(
392  const std::vector<const Surface*>& surfaces,
393  const std::function<bool(const Surface*, const Surface*)>& equal) const {
394  std::vector<const Surface*> keys;
395  for (const auto& srfA : surfaces) {
396  bool exists = false;
397  for (const auto& srfB : keys) {
398  if (equal(srfA, srfB)) {
399  exists = true;
400  break;
401  }
402  }
403  if (!exists) {
404  keys.push_back(srfA);
405  }
406  }
407 
408  return keys;
409 }
410 
412  const GeometryContext& gctx, const std::vector<const Surface*>& surfaces,
413  BinningValue bValue) const {
414  auto matcher = m_cfg.surfaceMatcher;
415  auto equal = [&gctx, &bValue, &matcher](const Surface* a, const Surface* b) {
416  return matcher(gctx, bValue, a, b);
417  };
418  std::vector<const Surface*> keys = findKeySurfaces(surfaces, equal);
419 
420  return keys.size();
421 }
422 
425  const GeometryContext& gctx, const std::vector<const Surface*>& surfaces,
426  BinningValue bValue, ProtoLayer protoLayer, Transform3D& transform) const {
427  if (surfaces.empty()) {
428  throw std::logic_error(
429  "No surfaces handed over for creating arbitrary bin utility!");
430  }
431  // BinningOption is open for z and r, in case of phi binning reset later
432  // the vector with the binning Values (boundaries for each bin)
433 
434  // bind matcher with binning type
435  auto matcher = m_cfg.surfaceMatcher;
436  // find the key surfaces
437  auto equal = [&gctx, &bValue, &matcher](const Surface* a, const Surface* b) {
438  return matcher(gctx, bValue, a, b);
439  };
440  std::vector<const Acts::Surface*> keys = findKeySurfaces(surfaces, equal);
441 
442  std::vector<double> bValues;
443  if (bValue == Acts::binPhi) {
444  std::stable_sort(keys.begin(), keys.end(),
445  [&gctx](const Acts::Surface* a, const Acts::Surface* b) {
446  return (phi(a->binningPosition(gctx, binPhi)) <
447  phi(b->binningPosition(gctx, binPhi)));
448  });
449 
450  double maxPhi = 0.5 * (phi(keys.at(0)->binningPosition(gctx, binPhi)) +
451  phi(keys.at(1)->binningPosition(gctx, binPhi)));
452 
453  // create rotation, so that maxPhi is +pi
454  double angle = -(M_PI + maxPhi);
455  transform = (transform)*AngleAxis3D(angle, Vector3D::UnitZ());
456 
457  // iterate over all key surfaces, and use their mean position as bValues,
458  // but
459  // rotate using transform from before
460  double previous = phi(keys.at(0)->binningPosition(gctx, binPhi));
461  // go through key surfaces
462  for (size_t i = 1; i < keys.size(); i++) {
463  const Surface* surface = keys.at(i);
464  // create central binning values which is the mean of the center
465  // positions in the binning direction of the current and previous
466  // surface
467  double edge =
468  0.5 * (previous + phi(surface->binningPosition(gctx, binPhi))) +
469  angle;
470  bValues.push_back(edge);
471  previous = phi(surface->binningPosition(gctx, binPhi));
472  }
473 
474  // get the bounds of the last surfaces
475  const Acts::Surface* backSurface = keys.back();
476  const Acts::PlanarBounds* backBounds =
477  dynamic_cast<const Acts::PlanarBounds*>(&(backSurface->bounds()));
478  if (backBounds == nullptr)
479  ACTS_ERROR(
480  "Given SurfaceBounds are not planar - not implemented for "
481  "other bounds yet! ");
482  // get the global vertices
483  std::vector<Acts::Vector3D> backVertices =
484  makeGlobalVertices(gctx, *backSurface, backBounds->vertices());
485  double maxBValue = phi(
486  *std::max_element(backVertices.begin(), backVertices.end(),
487  [](const Acts::Vector3D& a, const Acts::Vector3D& b) {
488  return phi(a) < phi(b);
489  }));
490 
491  bValues.push_back(maxBValue);
492 
493  bValues.push_back(M_PI);
494 
495  } else if (bValue == Acts::binZ) {
496  std::stable_sort(keys.begin(), keys.end(),
497  [&gctx](const Acts::Surface* a, const Acts::Surface* b) {
498  return (a->binningPosition(gctx, binZ).z() <
499  b->binningPosition(gctx, binZ).z());
500  });
501 
502  bValues.push_back(protoLayer.minZ);
503  bValues.push_back(protoLayer.maxZ);
504 
505  // the z-center position of the previous surface
506  double previous = keys.front()->binningPosition(gctx, binZ).z();
507  // go through key surfaces
508  for (auto surface = keys.begin() + 1; surface != keys.end(); surface++) {
509  // create central binning values which is the mean of the center
510  // positions in the binning direction of the current and previous
511  // surface
512  bValues.push_back(
513  0.5 * (previous + (*surface)->binningPosition(gctx, binZ).z()));
514  previous = (*surface)->binningPosition(gctx, binZ).z();
515  }
516  } else { // binR
517  std::stable_sort(keys.begin(), keys.end(),
518  [&gctx](const Acts::Surface* a, const Acts::Surface* b) {
519  return (perp(a->binningPosition(gctx, binR)) <
520  perp(b->binningPosition(gctx, binR)));
521  });
522 
523  bValues.push_back(protoLayer.minR);
524  bValues.push_back(protoLayer.maxR);
525 
526  // the r-center position of the previous surface
527  double previous = perp(keys.front()->binningPosition(gctx, binR));
528 
529  // go through key surfaces
530  for (auto surface = keys.begin() + 1; surface != keys.end(); surface++) {
531  // create central binning values which is the mean of the center
532  // positions in the binning direction of the current and previous
533  // surface
534  bValues.push_back(
535  0.5 * (previous + perp((*surface)->binningPosition(gctx, binR))));
536  previous = perp((*surface)->binningPosition(gctx, binR));
537  }
538  }
539  std::sort(bValues.begin(), bValues.end());
540  ACTS_VERBOSE("Create variable binning Axis for binned SurfaceArray");
541  ACTS_VERBOSE(" BinningValue: " << bValue);
542  ACTS_VERBOSE(
543  " (binX = 0, binY = 1, binZ = 2, binR = 3, binPhi = 4, "
544  "binRPhi = 5, binH = 6, binEta = 7)");
545  ACTS_VERBOSE(" Number of bins: " << (bValues.size() - 1));
546  ACTS_VERBOSE(" (Min/Max) = (" << bValues.front() << "/"
547  << bValues.back() << ")");
548 
549  ProtoAxis pAxis;
550  pAxis.bType = arbitrary;
551  pAxis.bValue = bValue;
552  pAxis.binEdges = bValues;
553  pAxis.nBins = bValues.size() - 1;
554 
555  return pAxis;
556 }
557 
560  const GeometryContext& gctx, const std::vector<const Surface*>& surfaces,
561  BinningValue bValue, ProtoLayer protoLayer, Transform3D& transform,
562  size_t nBins) const {
563  if (surfaces.empty()) {
564  throw std::logic_error(
565  "No surfaces handed over for creating equidistant axis!");
566  }
567  // check the binning type first
568 
569  double minimum = 0.;
570  double maximum = 0.;
571 
572  // binning option is open for z and r, in case of phi binning reset later
573  // Acts::BinningOption bOption = Acts::open;
574 
575  // the key surfaces - placed in different bins in the given binning
576  // direction
577  std::vector<const Acts::Surface*> keys;
578 
579  size_t binNumber;
580  if (nBins == 0) {
581  // determine bin count
582  binNumber = determineBinCount(gctx, surfaces, bValue);
583  } else {
584  // use bin count
585  binNumber = nBins;
586  }
587 
588  // bind matcher & context with binning type
589  auto matcher = m_cfg.surfaceMatcher;
590 
591  // now check the binning value
592  switch (bValue) {
593  case Acts::binPhi: {
594  if (m_cfg.doPhiBinningOptimization) {
595  // Phi binning
596  // set the binning option for phi
597  // sort first in phi
598  const Acts::Surface* maxElem = *std::max_element(
599  surfaces.begin(), surfaces.end(),
600  [&gctx](const Acts::Surface* a, const Acts::Surface* b) {
601  return phi(a->binningPosition(gctx, binR)) <
602  phi(b->binningPosition(gctx, binR));
603  });
604 
605  // get the key surfaces at the different phi positions
606  auto equal = [&gctx, &bValue, &matcher](const Surface* a,
607  const Surface* b) {
608  return matcher(gctx, bValue, a, b);
609  };
610  keys = findKeySurfaces(surfaces, equal);
611 
612  // multiple surfaces, we bin from -pi to pi closed
613  if (keys.size() > 1) {
614  // bOption = Acts::closed;
615 
616  minimum = -M_PI;
617  maximum = M_PI;
618 
619  // double step = 2 * M_PI / keys.size();
620  double step = 2 * M_PI / binNumber;
621  // rotate to max phi module plus one half step
622  // this should make sure that phi wrapping at +- pi
623  // never falls on a module center
624  double max = phi(maxElem->binningPosition(gctx, binR));
625  double angle = M_PI - (max + 0.5 * step);
626 
627  // replace given transform ref
628  transform = (transform)*AngleAxis3D(angle, Vector3D::UnitZ());
629 
630  } else {
631  minimum = protoLayer.minPhi;
632  maximum = protoLayer.maxPhi;
633 
634  // we do not need a transform in this case
635  }
636  } else {
637  minimum = -M_PI;
638  maximum = M_PI;
639  }
640  break;
641  }
642  case Acts::binR: {
643  // R binning
644 
645  // just use maximum and minimum of all surfaces
646  // we do not need key surfaces here
647  maximum = protoLayer.maxR;
648  minimum = protoLayer.minR;
649  break;
650  }
651  case Acts::binX: {
652  // X binning
653 
654  // just use maximum and minimum of all surfaces
655  // we do not need key surfaces here
656  maximum = protoLayer.maxX;
657  minimum = protoLayer.minX;
658  break;
659  }
660  case Acts::binY: {
661  // Y binning
662 
663  // just use maximum and minimum of all surfaces
664  // we do not need key surfaces here
665  maximum = protoLayer.maxY;
666  minimum = protoLayer.minY;
667  break;
668  }
669  case Acts::binZ: {
670  // Z binning
671 
672  // just use maximum and minimum of all surfaces
673  // we do not need key surfaces here
674  maximum = protoLayer.maxZ;
675  minimum = protoLayer.minZ;
676  break;
677  }
678  default: {
679  throw std::invalid_argument(
680  "Acts::SurfaceArrayCreator::"
681  "createEquidistantAxis: Invalid binning "
682  "direction");
683  }
684  }
685  // assign the bin size
686  ACTS_VERBOSE("Create equidistant binning Axis for binned SurfaceArray");
687  ACTS_VERBOSE(" BinningValue: " << bValue);
688  ACTS_VERBOSE(
689  " (binX = 0, binY = 1, binZ = 2, binR = 3, binPhi = 4, "
690  "binRPhi = 5, binH = 6, binEta = 7)");
691  ACTS_VERBOSE(" Number of bins: " << binNumber);
692  ACTS_VERBOSE(" (Min/Max) = (" << minimum << "/" << maximum << ")");
693 
694  ProtoAxis pAxis;
695  pAxis.max = maximum;
696  pAxis.min = minimum;
697  pAxis.bType = equidistant;
698  pAxis.bValue = bValue;
699  pAxis.nBins = binNumber;
700 
701  return pAxis;
702 }
703 
705  const GeometryContext& gctx, const Acts::Surface& surface,
706  const std::vector<Acts::Vector2D>& locVertices) const {
707  std::vector<Acts::Vector3D> globVertices;
708  for (auto& vertex : locVertices) {
709  Acts::Vector3D globVertex(0., 0., 0.);
710  surface.localToGlobal(gctx, vertex, Acts::Vector3D(), globVertex);
711  globVertices.push_back(globVertex);
712  }
713  return globVertices;
714 }