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