File indexing completed on 2025-08-05 08:09:37
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "Acts/Geometry/SurfaceArrayCreator.hpp"
0010
0011 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/Surfaces/PlanarBounds.hpp"
0013 #include "Acts/Surfaces/Surface.hpp"
0014 #include "Acts/Surfaces/SurfaceArray.hpp"
0015 #include "Acts/Surfaces/SurfaceBounds.hpp"
0016 #include "Acts/Utilities/BinningType.hpp"
0017 #include "Acts/Utilities/Grid.hpp"
0018 #include "Acts/Utilities/Helpers.hpp"
0019 #include "Acts/Utilities/IAxis.hpp"
0020 #include "Acts/Utilities/detail/grid_helper.hpp"
0021
0022 #include <algorithm>
0023 #include <cmath>
0024 #include <stdexcept>
0025
0026 using Acts::VectorHelpers::perp;
0027 using Acts::VectorHelpers::phi;
0028
0029 std::unique_ptr<Acts::SurfaceArray>
0030 Acts::SurfaceArrayCreator::surfaceArrayOnCylinder(
0031 const GeometryContext& gctx,
0032 std::vector<std::shared_ptr<const Surface>> surfaces, std::size_t binsPhi,
0033 std::size_t binsZ, std::optional<ProtoLayer> protoLayerOpt,
0034 const Transform3& transform) const {
0035 std::vector<const Surface*> surfacesRaw = unpack_shared_vector(surfaces);
0036
0037 ProtoLayer protoLayer =
0038 protoLayerOpt ? *protoLayerOpt : ProtoLayer(gctx, surfacesRaw);
0039
0040 ACTS_VERBOSE("Creating a SurfaceArray on a cylinder");
0041 ACTS_VERBOSE(" -- with " << surfaces.size() << " surfaces.")
0042 ACTS_VERBOSE(" -- with phi x z = " << binsPhi << " x " << binsZ << " = "
0043 << binsPhi * binsZ << " bins.");
0044
0045 Transform3 ftransform = transform;
0046 ProtoAxis pAxisPhi = createEquidistantAxis(gctx, surfacesRaw, binPhi,
0047 protoLayer, ftransform, binsPhi);
0048 ProtoAxis pAxisZ = createEquidistantAxis(gctx, surfacesRaw, binZ, protoLayer,
0049 ftransform, binsZ);
0050
0051 double R = protoLayer.medium(binR, true);
0052
0053 Transform3 itransform = ftransform.inverse();
0054
0055 auto globalToLocal = [ftransform](const Vector3& pos) {
0056 Vector3 loc = ftransform * pos;
0057 return Vector2(phi(loc), loc.z());
0058 };
0059 auto localToGlobal = [itransform, R](const Vector2& loc) {
0060 return itransform *
0061 Vector3(R * std::cos(loc[0]), R * std::sin(loc[0]), loc[1]);
0062 };
0063
0064 std::unique_ptr<SurfaceArray::ISurfaceGridLookup> sl =
0065 makeSurfaceGridLookup2D<detail::AxisBoundaryType::Closed,
0066 detail::AxisBoundaryType::Bound>(
0067 globalToLocal, localToGlobal, pAxisPhi, pAxisZ);
0068
0069 sl->fill(gctx, surfacesRaw);
0070 completeBinning(gctx, *sl, surfacesRaw);
0071
0072 return std::make_unique<SurfaceArray>(std::move(sl), std::move(surfaces),
0073 ftransform);
0074 }
0075
0076 std::unique_ptr<Acts::SurfaceArray>
0077 Acts::SurfaceArrayCreator::surfaceArrayOnCylinder(
0078 const GeometryContext& gctx,
0079 std::vector<std::shared_ptr<const Surface>> surfaces, BinningType bTypePhi,
0080 BinningType bTypeZ, std::optional<ProtoLayer> protoLayerOpt,
0081 const Transform3& transform) const {
0082 std::vector<const Surface*> surfacesRaw = unpack_shared_vector(surfaces);
0083
0084 ProtoLayer protoLayer =
0085 protoLayerOpt ? *protoLayerOpt : ProtoLayer(gctx, surfacesRaw);
0086
0087 double R = protoLayer.medium(binR, true);
0088
0089 ProtoAxis pAxisPhi;
0090 ProtoAxis pAxisZ;
0091
0092 Transform3 ftransform = transform;
0093
0094 if (bTypePhi == equidistant) {
0095 pAxisPhi = createEquidistantAxis(gctx, surfacesRaw, binPhi, protoLayer,
0096 ftransform, 0);
0097 } else {
0098 pAxisPhi =
0099 createVariableAxis(gctx, surfacesRaw, binPhi, protoLayer, ftransform);
0100 }
0101
0102 if (bTypeZ == equidistant) {
0103 pAxisZ =
0104 createEquidistantAxis(gctx, surfacesRaw, binZ, protoLayer, ftransform);
0105 } else {
0106 pAxisZ =
0107 createVariableAxis(gctx, surfacesRaw, binZ, protoLayer, ftransform);
0108 }
0109
0110 Transform3 itransform = ftransform.inverse();
0111 auto globalToLocal = [ftransform](const Vector3& pos) {
0112 Vector3 loc = ftransform * pos;
0113 return Vector2(phi(loc), loc.z());
0114 };
0115 auto localToGlobal = [itransform, R](const Vector2& loc) {
0116 return itransform *
0117 Vector3(R * std::cos(loc[0]), R * std::sin(loc[0]), loc[1]);
0118 };
0119
0120 std::unique_ptr<SurfaceArray::ISurfaceGridLookup> sl =
0121 makeSurfaceGridLookup2D<detail::AxisBoundaryType::Closed,
0122 detail::AxisBoundaryType::Bound>(
0123 globalToLocal, localToGlobal, pAxisPhi, pAxisZ);
0124
0125 sl->fill(gctx, surfacesRaw);
0126 completeBinning(gctx, *sl, surfacesRaw);
0127
0128
0129 auto axes = sl->getAxes();
0130 std::size_t bins0 = axes.at(0)->getNBins();
0131 std::size_t bins1 = axes.at(1)->getNBins();
0132
0133 ACTS_VERBOSE("Creating a SurfaceArray on a cylinder");
0134 ACTS_VERBOSE(" -- with " << surfaces.size() << " surfaces.")
0135 ACTS_VERBOSE(" -- with phi x z = " << bins0 << " x " << bins1 << " = "
0136 << bins0 * bins1 << " bins.");
0137
0138 return std::make_unique<SurfaceArray>(std::move(sl), std::move(surfaces),
0139 ftransform);
0140 }
0141
0142 std::unique_ptr<Acts::SurfaceArray>
0143 Acts::SurfaceArrayCreator::surfaceArrayOnDisc(
0144 const GeometryContext& gctx,
0145 std::vector<std::shared_ptr<const Surface>> surfaces, std::size_t binsR,
0146 std::size_t binsPhi, std::optional<ProtoLayer> protoLayerOpt,
0147 const Transform3& transform) const {
0148 std::vector<const Surface*> surfacesRaw = unpack_shared_vector(surfaces);
0149
0150 ProtoLayer protoLayer =
0151 protoLayerOpt ? *protoLayerOpt : ProtoLayer(gctx, surfacesRaw);
0152
0153 ACTS_VERBOSE("Creating a SurfaceArray on a disc");
0154
0155 Transform3 ftransform = transform;
0156 ProtoAxis pAxisR = createEquidistantAxis(gctx, surfacesRaw, binR, protoLayer,
0157 ftransform, binsR);
0158 ProtoAxis pAxisPhi = createEquidistantAxis(gctx, surfacesRaw, binPhi,
0159 protoLayer, ftransform, binsPhi);
0160
0161 double Z = protoLayer.medium(binZ, true);
0162 ACTS_VERBOSE("- z-position of disk estimated as " << Z);
0163
0164 Transform3 itransform = transform.inverse();
0165
0166 auto globalToLocal = [ftransform](const Vector3& pos) {
0167 Vector3 loc = ftransform * pos;
0168 return Vector2(perp(loc), phi(loc));
0169 };
0170 auto localToGlobal = [itransform, Z](const Vector2& loc) {
0171 return itransform *
0172 Vector3(loc[0] * std::cos(loc[1]), loc[0] * std::sin(loc[1]), Z);
0173 };
0174
0175 std::unique_ptr<SurfaceArray::ISurfaceGridLookup> sl =
0176 makeSurfaceGridLookup2D<detail::AxisBoundaryType::Bound,
0177 detail::AxisBoundaryType::Closed>(
0178 globalToLocal, localToGlobal, pAxisR, pAxisPhi);
0179
0180
0181 auto axes = sl->getAxes();
0182 std::size_t bins0 = axes.at(0)->getNBins();
0183 std::size_t bins1 = axes.at(1)->getNBins();
0184
0185 ACTS_VERBOSE(" -- with " << surfaces.size() << " surfaces.")
0186 ACTS_VERBOSE(" -- with r x phi = " << bins0 << " x " << bins1 << " = "
0187 << bins0 * bins1 << " bins.");
0188 sl->fill(gctx, surfacesRaw);
0189 completeBinning(gctx, *sl, surfacesRaw);
0190
0191 return std::make_unique<SurfaceArray>(std::move(sl), std::move(surfaces),
0192 ftransform);
0193 }
0194
0195 std::unique_ptr<Acts::SurfaceArray>
0196 Acts::SurfaceArrayCreator::surfaceArrayOnDisc(
0197 const GeometryContext& gctx,
0198 std::vector<std::shared_ptr<const Surface>> surfaces, BinningType bTypeR,
0199 BinningType bTypePhi, std::optional<ProtoLayer> protoLayerOpt,
0200 const Transform3& transform) const {
0201 std::vector<const Surface*> surfacesRaw = unpack_shared_vector(surfaces);
0202
0203 ProtoLayer protoLayer =
0204 protoLayerOpt ? *protoLayerOpt : ProtoLayer(gctx, surfacesRaw);
0205
0206 ACTS_VERBOSE("Creating a SurfaceArray on a disc");
0207
0208 ProtoAxis pAxisPhi;
0209 ProtoAxis pAxisR;
0210
0211 Transform3 ftransform = transform;
0212
0213 if (bTypeR == equidistant) {
0214 pAxisR =
0215 createEquidistantAxis(gctx, surfacesRaw, binR, protoLayer, ftransform);
0216 } else {
0217 pAxisR =
0218 createVariableAxis(gctx, surfacesRaw, binR, protoLayer, ftransform);
0219 }
0220
0221
0222
0223 if (pAxisR.nBins > 1) {
0224
0225
0226 std::vector<std::vector<const Surface*>> phiModules(pAxisR.nBins);
0227 for (const auto& srf : surfacesRaw) {
0228 Vector3 bpos = srf->binningPosition(gctx, binR);
0229 std::size_t bin = pAxisR.getBin(perp(bpos));
0230 phiModules.at(bin).push_back(srf);
0231 }
0232
0233 std::vector<std::size_t> nPhiModules;
0234 auto matcher = m_cfg.surfaceMatcher;
0235 auto equal = [&gctx, &matcher](const Surface* a, const Surface* b) {
0236 return matcher(gctx, binPhi, a, b);
0237 };
0238
0239 std::transform(
0240 phiModules.begin(), phiModules.end(), std::back_inserter(nPhiModules),
0241 [&equal,
0242 this](const std::vector<const Surface*>& surfaces_) -> std::size_t {
0243 return this->findKeySurfaces(surfaces_, equal).size();
0244 });
0245
0246
0247
0248
0249
0250
0251
0252 std::size_t nBinsPhi =
0253 (*std::min_element(nPhiModules.begin(), nPhiModules.end()));
0254 pAxisPhi = createEquidistantAxis(gctx, surfacesRaw, binPhi, protoLayer,
0255 ftransform, nBinsPhi);
0256
0257 } else {
0258
0259 if (bTypePhi == equidistant) {
0260 pAxisPhi = createEquidistantAxis(gctx, surfacesRaw, binPhi, protoLayer,
0261 ftransform, 0);
0262 } else {
0263 pAxisPhi =
0264 createVariableAxis(gctx, surfacesRaw, binPhi, protoLayer, ftransform);
0265 }
0266 }
0267
0268 double Z = protoLayer.medium(binZ, true);
0269 ACTS_VERBOSE("- z-position of disk estimated as " << Z);
0270
0271 Transform3 itransform = ftransform.inverse();
0272
0273 auto globalToLocal = [ftransform](const Vector3& pos) {
0274 Vector3 loc = ftransform * pos;
0275 return Vector2(perp(loc), phi(loc));
0276 };
0277 auto localToGlobal = [itransform, Z](const Vector2& loc) {
0278 return itransform *
0279 Vector3(loc[0] * std::cos(loc[1]), loc[0] * std::sin(loc[1]), Z);
0280 };
0281
0282 std::unique_ptr<SurfaceArray::ISurfaceGridLookup> sl =
0283 makeSurfaceGridLookup2D<detail::AxisBoundaryType::Bound,
0284 detail::AxisBoundaryType::Closed>(
0285 globalToLocal, localToGlobal, pAxisR, pAxisPhi);
0286
0287
0288 auto axes = sl->getAxes();
0289 std::size_t bins0 = axes.at(0)->getNBins();
0290 std::size_t bins1 = axes.at(1)->getNBins();
0291
0292 ACTS_VERBOSE(" -- with " << surfaces.size() << " surfaces.")
0293 ACTS_VERBOSE(" -- with r x phi = " << bins0 << " x " << bins1 << " = "
0294 << bins0 * bins1 << " bins.");
0295
0296 sl->fill(gctx, surfacesRaw);
0297 completeBinning(gctx, *sl, surfacesRaw);
0298
0299 return std::make_unique<SurfaceArray>(std::move(sl), std::move(surfaces),
0300 ftransform);
0301 }
0302
0303
0304 std::unique_ptr<Acts::SurfaceArray>
0305 Acts::SurfaceArrayCreator::surfaceArrayOnPlane(
0306 const GeometryContext& gctx,
0307 std::vector<std::shared_ptr<const Surface>> surfaces, std::size_t bins1,
0308 std::size_t bins2, BinningValue bValue,
0309 std::optional<ProtoLayer> protoLayerOpt,
0310 const Transform3& transform) const {
0311 std::vector<const Surface*> surfacesRaw = unpack_shared_vector(surfaces);
0312
0313 ProtoLayer protoLayer =
0314 protoLayerOpt ? *protoLayerOpt : ProtoLayer(gctx, surfacesRaw);
0315
0316 ACTS_VERBOSE("Creating a SurfaceArray on a plance");
0317 ACTS_VERBOSE(" -- with " << surfaces.size() << " surfaces.")
0318 ACTS_VERBOSE(" -- with " << bins1 << " x " << bins2 << " = " << bins1 * bins2
0319 << " bins.");
0320 Transform3 ftransform = transform;
0321 Transform3 itransform = transform.inverse();
0322
0323 auto globalToLocal = [ftransform](const Vector3& pos) {
0324 Vector3 loc = ftransform * pos;
0325 return Vector2(loc.x(), loc.y());
0326 };
0327 auto localToGlobal = [itransform](const Vector2& loc) {
0328 return itransform * Vector3(loc.x(), loc.y(), 0.);
0329 };
0330
0331 std::unique_ptr<SurfaceArray::ISurfaceGridLookup> sl;
0332
0333
0334 switch (bValue) {
0335 case BinningValue::binX: {
0336 ProtoAxis pAxis1 = createEquidistantAxis(gctx, surfacesRaw, binY,
0337 protoLayer, ftransform, bins1);
0338 ProtoAxis pAxis2 = createEquidistantAxis(gctx, surfacesRaw, binZ,
0339 protoLayer, ftransform, bins2);
0340 sl = makeSurfaceGridLookup2D<detail::AxisBoundaryType::Bound,
0341 detail::AxisBoundaryType::Bound>(
0342 globalToLocal, localToGlobal, pAxis1, pAxis2);
0343 break;
0344 }
0345 case BinningValue::binY: {
0346 ProtoAxis pAxis1 = createEquidistantAxis(gctx, surfacesRaw, binX,
0347 protoLayer, ftransform, bins1);
0348 ProtoAxis pAxis2 = createEquidistantAxis(gctx, surfacesRaw, binZ,
0349 protoLayer, ftransform, bins2);
0350 sl = makeSurfaceGridLookup2D<detail::AxisBoundaryType::Bound,
0351 detail::AxisBoundaryType::Bound>(
0352 globalToLocal, localToGlobal, pAxis1, pAxis2);
0353 break;
0354 }
0355 case BinningValue::binZ: {
0356 ProtoAxis pAxis1 = createEquidistantAxis(gctx, surfacesRaw, binX,
0357 protoLayer, ftransform, bins1);
0358 ProtoAxis pAxis2 = createEquidistantAxis(gctx, surfacesRaw, binY,
0359 protoLayer, ftransform, bins2);
0360 sl = makeSurfaceGridLookup2D<detail::AxisBoundaryType::Bound,
0361 detail::AxisBoundaryType::Bound>(
0362 globalToLocal, localToGlobal, pAxis1, pAxis2);
0363 break;
0364 }
0365 default: {
0366 throw std::invalid_argument(
0367 "Acts::SurfaceArrayCreator::"
0368 "surfaceArrayOnPlane: Invalid binning "
0369 "direction");
0370 }
0371 }
0372
0373 sl->fill(gctx, surfacesRaw);
0374 completeBinning(gctx, *sl, surfacesRaw);
0375
0376 return std::make_unique<SurfaceArray>(std::move(sl), std::move(surfaces),
0377 ftransform);
0378
0379 }
0380
0381 std::vector<const Acts::Surface*> Acts::SurfaceArrayCreator::findKeySurfaces(
0382 const std::vector<const Surface*>& surfaces,
0383 const std::function<bool(const Surface*, const Surface*)>& equal) const {
0384 std::vector<const Surface*> keys;
0385 for (const auto& srfA : surfaces) {
0386 bool exists = false;
0387 for (const auto& srfB : keys) {
0388 if (equal(srfA, srfB)) {
0389 exists = true;
0390 break;
0391 }
0392 }
0393 if (!exists) {
0394 keys.push_back(srfA);
0395 }
0396 }
0397
0398 return keys;
0399 }
0400
0401 std::size_t Acts::SurfaceArrayCreator::determineBinCount(
0402 const GeometryContext& gctx, const std::vector<const Surface*>& surfaces,
0403 BinningValue bValue) const {
0404 auto matcher = m_cfg.surfaceMatcher;
0405 auto equal = [&gctx, &bValue, &matcher](const Surface* a, const Surface* b) {
0406 return matcher(gctx, bValue, a, b);
0407 };
0408 std::vector<const Surface*> keys = findKeySurfaces(surfaces, equal);
0409
0410 return keys.size();
0411 }
0412
0413 Acts::SurfaceArrayCreator::ProtoAxis
0414 Acts::SurfaceArrayCreator::createVariableAxis(
0415 const GeometryContext& gctx, const std::vector<const Surface*>& surfaces,
0416 BinningValue bValue, const ProtoLayer& protoLayer,
0417 Transform3& transform) const {
0418 if (surfaces.empty()) {
0419 throw std::logic_error(
0420 "No surfaces handed over for creating arbitrary bin utility!");
0421 }
0422
0423
0424
0425
0426 auto matcher = m_cfg.surfaceMatcher;
0427
0428 auto equal = [&gctx, &bValue, &matcher](const Surface* a, const Surface* b) {
0429 return matcher(gctx, bValue, a, b);
0430 };
0431 std::vector<const Acts::Surface*> keys = findKeySurfaces(surfaces, equal);
0432
0433 std::vector<AxisScalar> bValues;
0434 if (bValue == Acts::binPhi) {
0435 std::stable_sort(keys.begin(), keys.end(),
0436 [&gctx](const Acts::Surface* a, const Acts::Surface* b) {
0437 return (phi(a->binningPosition(gctx, binPhi)) <
0438 phi(b->binningPosition(gctx, binPhi)));
0439 });
0440
0441 AxisScalar maxPhi = 0.5 * (phi(keys.at(0)->binningPosition(gctx, binPhi)) +
0442 phi(keys.at(1)->binningPosition(gctx, binPhi)));
0443
0444
0445 AxisScalar angle = -(M_PI + maxPhi);
0446 transform = (transform)*AngleAxis3(angle, Vector3::UnitZ());
0447
0448
0449
0450
0451 AxisScalar previous = phi(keys.at(0)->binningPosition(gctx, binPhi));
0452
0453 for (std::size_t i = 1; i < keys.size(); i++) {
0454 const Surface* surface = keys.at(i);
0455
0456
0457
0458 AxisScalar edge =
0459 0.5 * (previous + phi(surface->binningPosition(gctx, binPhi))) +
0460 angle;
0461 bValues.push_back(edge);
0462 previous = phi(surface->binningPosition(gctx, binPhi));
0463 }
0464
0465
0466 unsigned int segments = 72;
0467
0468
0469 const Acts::Surface* backSurface = keys.back();
0470 const Acts::PlanarBounds* backBounds =
0471 dynamic_cast<const Acts::PlanarBounds*>(&(backSurface->bounds()));
0472 if (backBounds == nullptr) {
0473 ACTS_ERROR(
0474 "Given SurfaceBounds are not planar - not implemented for "
0475 "other bounds yet! ");
0476 }
0477
0478 std::vector<Acts::Vector3> backVertices =
0479 makeGlobalVertices(gctx, *backSurface, backBounds->vertices(segments));
0480 AxisScalar maxBValue = phi(
0481 *std::max_element(backVertices.begin(), backVertices.end(),
0482 [](const Acts::Vector3& a, const Acts::Vector3& b) {
0483 return phi(a) < phi(b);
0484 }));
0485
0486 bValues.push_back(maxBValue);
0487
0488 bValues.push_back(M_PI);
0489
0490 } else if (bValue == Acts::binZ) {
0491 std::stable_sort(keys.begin(), keys.end(),
0492 [&gctx](const Acts::Surface* a, const Acts::Surface* b) {
0493 return (a->binningPosition(gctx, binZ).z() <
0494 b->binningPosition(gctx, binZ).z());
0495 });
0496
0497 bValues.push_back(protoLayer.min(binZ));
0498 bValues.push_back(protoLayer.max(binZ));
0499
0500
0501 AxisScalar previous = keys.front()->binningPosition(gctx, binZ).z();
0502
0503 for (auto surface = keys.begin() + 1; surface != keys.end(); surface++) {
0504
0505
0506
0507 bValues.push_back(
0508 0.5 * (previous + (*surface)->binningPosition(gctx, binZ).z()));
0509 previous = (*surface)->binningPosition(gctx, binZ).z();
0510 }
0511 } else {
0512 std::stable_sort(keys.begin(), keys.end(),
0513 [&gctx](const Acts::Surface* a, const Acts::Surface* b) {
0514 return (perp(a->binningPosition(gctx, binR)) <
0515 perp(b->binningPosition(gctx, binR)));
0516 });
0517
0518 bValues.push_back(protoLayer.min(binR));
0519 bValues.push_back(protoLayer.max(binR));
0520
0521
0522 AxisScalar previous = perp(keys.front()->binningPosition(gctx, binR));
0523
0524
0525 for (auto surface = keys.begin() + 1; surface != keys.end(); surface++) {
0526
0527
0528
0529 bValues.push_back(
0530 0.5 * (previous + perp((*surface)->binningPosition(gctx, binR))));
0531 previous = perp((*surface)->binningPosition(gctx, binR));
0532 }
0533 }
0534 std::sort(bValues.begin(), bValues.end());
0535 ACTS_VERBOSE("Create variable binning Axis for binned SurfaceArray");
0536 ACTS_VERBOSE(" BinningValue: " << bValue);
0537 ACTS_VERBOSE(
0538 " (binX = 0, binY = 1, binZ = 2, binR = 3, binPhi = 4, "
0539 "binRPhi = 5, binH = 6, binEta = 7)");
0540 ACTS_VERBOSE(" Number of bins: " << (bValues.size() - 1));
0541 ACTS_VERBOSE(" (Min/Max) = (" << bValues.front() << "/"
0542 << bValues.back() << ")");
0543
0544 ProtoAxis pAxis;
0545 pAxis.bType = arbitrary;
0546 pAxis.bValue = bValue;
0547 pAxis.binEdges = bValues;
0548 pAxis.nBins = bValues.size() - 1;
0549
0550 return pAxis;
0551 }
0552
0553 Acts::SurfaceArrayCreator::ProtoAxis
0554 Acts::SurfaceArrayCreator::createEquidistantAxis(
0555 const GeometryContext& gctx, const std::vector<const Surface*>& surfaces,
0556 BinningValue bValue, const ProtoLayer& protoLayer, Transform3& transform,
0557 std::size_t nBins) const {
0558 if (surfaces.empty()) {
0559 throw std::logic_error(
0560 "No surfaces handed over for creating equidistant axis!");
0561 }
0562
0563
0564 double minimum = 0.;
0565 double maximum = 0.;
0566
0567
0568
0569
0570
0571
0572 std::vector<const Acts::Surface*> keys;
0573
0574 std::size_t binNumber = 0;
0575 if (nBins == 0) {
0576
0577 binNumber = determineBinCount(gctx, surfaces, bValue);
0578 } else {
0579
0580 binNumber = nBins;
0581 }
0582
0583
0584 auto matcher = m_cfg.surfaceMatcher;
0585
0586
0587 if (bValue == binPhi) {
0588 if (m_cfg.doPhiBinningOptimization) {
0589
0590
0591
0592 const Acts::Surface* maxElem = *std::max_element(
0593 surfaces.begin(), surfaces.end(),
0594 [&gctx](const Acts::Surface* a, const Acts::Surface* b) {
0595 return phi(a->binningPosition(gctx, binR)) <
0596 phi(b->binningPosition(gctx, binR));
0597 });
0598
0599
0600 auto equal = [&gctx, &bValue, &matcher](const Surface* a,
0601 const Surface* b) {
0602 return matcher(gctx, bValue, a, b);
0603 };
0604 keys = findKeySurfaces(surfaces, equal);
0605
0606
0607 if (keys.size() > 1) {
0608
0609
0610 minimum = -M_PI;
0611 maximum = M_PI;
0612
0613
0614 double step = 2 * M_PI / binNumber;
0615
0616
0617
0618 double max = phi(maxElem->binningPosition(gctx, binR));
0619 double angle = M_PI - (max + 0.5 * step);
0620
0621
0622 transform = (transform)*AngleAxis3(angle, Vector3::UnitZ());
0623
0624 } else {
0625 minimum = protoLayer.min(binPhi, true);
0626 maximum = protoLayer.max(binPhi, true);
0627
0628 }
0629 } else {
0630 minimum = -M_PI;
0631 maximum = M_PI;
0632 }
0633 } else {
0634 maximum = protoLayer.max(bValue, false);
0635 minimum = protoLayer.min(bValue, false);
0636 }
0637
0638
0639 ACTS_VERBOSE("Create equidistant binning Axis for binned SurfaceArray");
0640 ACTS_VERBOSE(" BinningValue: " << bValue);
0641 ACTS_VERBOSE(
0642 " (binX = 0, binY = 1, binZ = 2, binR = 3, binPhi = 4, "
0643 "binRPhi = 5, binH = 6, binEta = 7)");
0644 ACTS_VERBOSE(" Number of bins: " << binNumber);
0645 ACTS_VERBOSE(" (Min/Max) = (" << minimum << "/" << maximum << ")");
0646
0647 ProtoAxis pAxis;
0648 pAxis.max = maximum;
0649 pAxis.min = minimum;
0650 pAxis.bType = equidistant;
0651 pAxis.bValue = bValue;
0652 pAxis.nBins = binNumber;
0653
0654 return pAxis;
0655 }
0656
0657 std::vector<Acts::Vector3> Acts::SurfaceArrayCreator::makeGlobalVertices(
0658 const GeometryContext& gctx, const Acts::Surface& surface,
0659 const std::vector<Acts::Vector2>& locVertices) const {
0660 std::vector<Acts::Vector3> globVertices;
0661 for (auto& vertex : locVertices) {
0662 Acts::Vector3 globVertex =
0663 surface.localToGlobal(gctx, vertex, Acts::Vector3());
0664 globVertices.push_back(globVertex);
0665 }
0666 return globVertices;
0667 }