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