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