|
||||
File indexing completed on 2025-01-18 09:10:53
0001 // This file is part of the ACTS project. 0002 // 0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project 0004 // 0005 // This Source Code Form is subject to the terms of the Mozilla Public 0006 // License, v. 2.0. If a copy of the MPL was not distributed with this 0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/. 0008 0009 #pragma once 0010 0011 #include "Acts/Definitions/Algebra.hpp" 0012 #include "Acts/Definitions/Units.hpp" 0013 #include "Acts/Geometry/GeometryContext.hpp" 0014 #include "Acts/Geometry/ProtoLayer.hpp" 0015 #include "Acts/Surfaces/Surface.hpp" 0016 #include "Acts/Surfaces/SurfaceArray.hpp" 0017 #include "Acts/Utilities/AxisDefinitions.hpp" 0018 #include "Acts/Utilities/BinningType.hpp" 0019 #include "Acts/Utilities/Logger.hpp" 0020 0021 #include <algorithm> 0022 #include <cmath> 0023 #include <cstddef> 0024 #include <functional> 0025 #include <iterator> 0026 #include <memory> 0027 #include <numbers> 0028 #include <optional> 0029 #include <ostream> 0030 #include <tuple> 0031 #include <utility> 0032 #include <vector> 0033 0034 namespace Acts { 0035 namespace Test { 0036 struct SurfaceArrayCreatorFixture; 0037 } 0038 0039 using SurfaceMatcher = 0040 std::function<bool(const GeometryContext& gctx, AxisDirection, 0041 const Surface*, const Surface*)>; 0042 0043 using SurfaceVector = std::vector<const Surface*>; 0044 using SurfaceMatrix = std::vector<SurfaceVector>; 0045 0046 using V3Vector = std::vector<Vector3>; 0047 using V3Matrix = std::vector<V3Vector>; 0048 0049 using AxisScalar = Vector3::Scalar; 0050 0051 /// @class SurfaceArrayCreator 0052 /// 0053 /// It is designed create sub surface arrays to be ordered on Surfaces 0054 /// 0055 /// @todo write more documentation on how this is done 0056 class SurfaceArrayCreator { 0057 public: 0058 friend struct Acts::Test::SurfaceArrayCreatorFixture; 0059 friend class Acts::SurfaceArray; 0060 0061 struct ProtoAxis { 0062 BinningType bType = BinningType::equidistant; 0063 AxisDirection axisDir = AxisDirection::AxisX; 0064 std::size_t nBins = 0; 0065 AxisScalar min = 0; 0066 AxisScalar max = 0; 0067 std::vector<AxisScalar> binEdges; 0068 0069 std::size_t getBin(AxisScalar x) const { 0070 if (binEdges.empty()) { 0071 // equidistant 0072 AxisScalar w = (max - min) / nBins; 0073 return static_cast<std::size_t>(std::floor((x - min) / w)); 0074 } else { 0075 // variable 0076 const auto it = 0077 std::upper_bound(std::begin(binEdges), std::end(binEdges), x); 0078 return std::distance(std::begin(binEdges), it) - 1; 0079 } 0080 } 0081 }; 0082 0083 // Configuration struct 0084 struct Config { 0085 /// Type-erased function which determines whether two surfaces are supposed 0086 /// to be considered equivalent in terms of the binning 0087 SurfaceMatcher surfaceMatcher = SurfaceArrayCreator::isSurfaceEquivalent; 0088 0089 /// Optimize the binning in phi for disc layers. Reduces the number 0090 /// of bins to the lowest number of non-equivalent phi surfaces 0091 /// of all r-bins. If false, this step is skipped. 0092 bool doPhiBinningOptimization = true; 0093 }; 0094 0095 /// Constructor with default config 0096 /// 0097 /// @param logger logging instance 0098 SurfaceArrayCreator(std::unique_ptr<const Logger> logger = getDefaultLogger( 0099 "SurfaceArrayCreator", Logging::INFO)) 0100 : m_cfg(Config()), m_logger(std::move(logger)) {} 0101 /// Constructor with explicit config 0102 /// 0103 /// @param cfg Explicit config struct 0104 /// @param logger logging instance 0105 SurfaceArrayCreator(const Config& cfg, 0106 std::unique_ptr<const Logger> logger = getDefaultLogger( 0107 "SurfaceArrayCreator", Logging::INFO)) 0108 : m_cfg(cfg), m_logger(std::move(logger)) {} 0109 0110 /// Destructor 0111 virtual ~SurfaceArrayCreator() = default; 0112 0113 /// SurfaceArrayCreator interface method 0114 /// 0115 /// - create an array in a cylinder, binned in phi, z when extremas and 0116 /// bin numbers are known 0117 /// @warning This function requires the cylinder aligned with the z-axis 0118 /// @param surfaces is the vector of pointers to sensitive surfaces 0119 /// to be ordered on the cylinder 0120 /// @pre the pointers to the sensitive surfaces in the surfaces vectors all 0121 /// need to be valid, since no check is performed 0122 /// @param [in] gctx The gometry context for this building call 0123 /// @param protoLayerOpt The proto layer containing the layer size 0124 /// @param binsPhi is the number of bins in phi for the surfaces 0125 /// @param binsZ is the number of bin in Z for the surfaces 0126 /// @param transform is the (optional) additional transform applied 0127 /// 0128 /// @return a unique pointer to a new SurfaceArray 0129 std::unique_ptr<SurfaceArray> surfaceArrayOnCylinder( 0130 const GeometryContext& gctx, 0131 std::vector<std::shared_ptr<const Surface>> surfaces, std::size_t binsPhi, 0132 std::size_t binsZ, std::optional<ProtoLayer> protoLayerOpt = std::nullopt, 0133 const Transform3& transform = Transform3::Identity()) const; 0134 0135 /// SurfaceArrayCreator interface method 0136 /// 0137 /// - create an array in a cylinder, binned in phi, z when extremas and bin 0138 /// numbers are unknown - this method goes through the surfaces and finds out 0139 /// the needed information 0140 /// @warning This function requires the cylinder aligned with the z-axis 0141 /// @param surfaces is the vector of pointers to sensitive surfaces 0142 /// to be ordered on the cylinder 0143 /// @pre the pointers to the sensitive surfaces in the surfaces vectors all 0144 /// need to be valid, since no check is performed 0145 /// @param [in] gctx The gometry context for this building call 0146 /// @param protoLayerOpt The proto layer containing the layer size 0147 /// @param bTypePhi the binning type in phi direction (equidistant/arbitrary) 0148 /// @param bTypeZ the binning type in z direction (equidistant/arbitrary) 0149 /// @param transform is the (optional) additional transform applied 0150 /// 0151 /// @return a unique pointer a new SurfaceArray 0152 std::unique_ptr<Acts::SurfaceArray> surfaceArrayOnCylinder( 0153 const GeometryContext& gctx, 0154 std::vector<std::shared_ptr<const Surface>> surfaces, 0155 BinningType bTypePhi = equidistant, BinningType bTypeZ = equidistant, 0156 std::optional<ProtoLayer> protoLayerOpt = std::nullopt, 0157 const Transform3& transform = Transform3::Identity()) const; 0158 0159 /// SurfaceArrayCreator interface method 0160 /// - create an array on a disc, binned in r, phi when extremas and 0161 /// bin numbers are known 0162 /// 0163 /// @param surfaces is the vector of pointers to sensitive surfaces 0164 /// to be ordered on the disc 0165 /// @pre the pointers to the sensitive surfaces in the surfaces vectors all 0166 /// need to be valid, since no check is performed 0167 /// @warning This function requires the disc aligned with the z-axis 0168 /// @param [in] gctx The gometry context for this building call 0169 /// @param protoLayerOpt The proto layer containing the layer size 0170 /// @param binsPhi is the number of bins in phi for the surfaces 0171 /// @param binsR is the number of bin in R for the surfaces 0172 /// @param transform is the (optional) additional transform applied 0173 /// 0174 /// @return a unique pointer a new SurfaceArray 0175 std::unique_ptr<SurfaceArray> surfaceArrayOnDisc( 0176 const GeometryContext& gctx, 0177 std::vector<std::shared_ptr<const Surface>> surfaces, std::size_t binsR, 0178 std::size_t binsPhi, 0179 std::optional<ProtoLayer> protoLayerOpt = std::nullopt, 0180 const Transform3& transform = Transform3::Identity()) const; 0181 0182 /// SurfaceArrayCreator interface method 0183 /// 0184 /// - create an array in a cylinder, binned in phi, r when extremas and bin 0185 /// numbers are unknown - this method goes through the surfaces and finds out 0186 /// the needed information 0187 /// @param surfaces is the vector of pointers to sensitive surfaces 0188 /// to be ordered on the disc 0189 /// @pre the pointers to the sensitive surfaces in the surfaces vectors all 0190 /// need to be valid, since no check is performed 0191 /// @warning This function requires the disc aligned with the z-axis 0192 /// @param [in] gctx The gometry context for this building call 0193 /// @param protoLayerOpt The proto layer containing the layer size 0194 /// @param bTypeR the binning type in r direction (equidistant/arbitrary) 0195 /// @param bTypePhi the binning type in phi direction (equidistant/arbitrary) 0196 /// @param transform is the (optional) additional transform applied 0197 /// 0198 /// @return a unique pointer a new SurfaceArray 0199 /// @note If there is more than on R-Ring, number of phi bins 0200 /// will be set to lowest number of surfaces of any R-ring. 0201 /// This ignores bTypePhi and produces equidistant binning in phi 0202 std::unique_ptr<Acts::SurfaceArray> surfaceArrayOnDisc( 0203 const GeometryContext& gctx, 0204 std::vector<std::shared_ptr<const Surface>> surfaces, BinningType bTypeR, 0205 BinningType bTypePhi, 0206 std::optional<ProtoLayer> protoLayerOpt = std::nullopt, 0207 const Transform3& transform = Transform3::Identity()) const; 0208 0209 /// SurfaceArrayCreator interface method 0210 /// - create an array on a plane 0211 /// 0212 /// @param [in] gctx The gometry context for this building call 0213 /// @param [in] surfaces is the vector of pointers to sensitive surfaces 0214 /// to be ordered on the plane 0215 /// @pre the pointers to the sensitive surfaces in the surfaces vectors all 0216 /// need to be valid, since no check is performed 0217 /// @warning This function requires the plane aligned with either the x-, y- 0218 /// or z-axis 0219 /// @param [in] bins1 is the number of bins in the orthogonal direction to @p 0220 /// aDir 0221 /// @param [in] bins2 is the number of bins in the orthogonal direction to @p 0222 /// aDir 0223 /// @param [in] aDir Direction of the aligned surfaces 0224 /// @param [in] protoLayerOpt Optional @c ProtoLayer instance 0225 /// @param [in] transform is the (optional) additional transform applied 0226 /// 0227 /// @return a unique pointer a new SurfaceArray 0228 std::unique_ptr<SurfaceArray> surfaceArrayOnPlane( 0229 const GeometryContext& gctx, 0230 std::vector<std::shared_ptr<const Surface>> surfaces, std::size_t bins1, 0231 std::size_t bins2, AxisDirection aDir, 0232 std::optional<ProtoLayer> protoLayerOpt = std::nullopt, 0233 const Transform3& transform = Transform3::Identity()) const; 0234 0235 /// Static check function for surface equivalent 0236 /// 0237 /// @param [in] gctx the geometry context for this check 0238 /// @param aDir the axis direction for the binning 0239 /// @param a first surface for checking 0240 /// @param b second surface for checking 0241 static bool isSurfaceEquivalent(const GeometryContext& gctx, 0242 AxisDirection aDir, const Surface* a, 0243 const Surface* b) { 0244 using namespace UnitLiterals; 0245 using VectorHelpers::perp; 0246 0247 if (aDir == Acts::AxisDirection::AxisPhi) { 0248 // Take the two binning positions 0249 Vector3 pos1 = a->referencePosition(gctx, AxisDirection::AxisR); 0250 Vector3 pos2 = b->referencePosition(gctx, AxisDirection::AxisR); 0251 0252 // Project them on the (x, y) plane, where Phi angles are calculated 0253 auto proj1 = pos1.head<2>(), proj2 = pos2.head<2>(); 0254 0255 // Basic dot and cross products identities give us the cosine and sine 0256 // of these angles, time the squared vector norm 0257 auto cos_dPhi_n2 = proj1.dot(proj2); 0258 auto sin_dPhi_n2 = proj1.x() * proj2.y() - proj2.x() * proj1.y(); 0259 0260 // ...so by injecting them into atan2, we get the angle between them 0261 auto dPhi = std::atan2(sin_dPhi_n2, cos_dPhi_n2); 0262 return std::abs(dPhi) < std::numbers::pi / 180.; 0263 } 0264 0265 if (aDir == Acts::AxisDirection::AxisZ) { 0266 return (std::abs(a->referencePosition(gctx, AxisDirection::AxisR).z() - 0267 b->referencePosition(gctx, AxisDirection::AxisR).z()) < 0268 1_um); 0269 } 0270 0271 if (aDir == Acts::AxisDirection::AxisR) { 0272 return (std::abs(perp(a->referencePosition(gctx, AxisDirection::AxisR)) - 0273 perp(b->referencePosition(gctx, AxisDirection::AxisR))) < 0274 1_um); 0275 } 0276 0277 return false; 0278 } 0279 0280 /// Set logging instance 0281 /// @param logger is the logging instance to be set 0282 void setLogger(std::unique_ptr<const Logger> logger) { 0283 m_logger = std::move(logger); 0284 } 0285 0286 private: 0287 /// configuration object 0288 Config m_cfg; 0289 0290 /// Private access to logger 0291 const Logger& logger() const { return *m_logger; } 0292 0293 std::vector<const Surface*> findKeySurfaces( 0294 const std::vector<const Surface*>& surfaces, 0295 const std::function<bool(const Surface*, const Surface*)>& equal) const; 0296 0297 std::size_t determineBinCount(const GeometryContext& gctx, 0298 const std::vector<const Surface*>& surfaces, 0299 AxisDirection aDir) const; 0300 0301 /// SurfaceArrayCreator internal method 0302 /// Creates a variable @c ProtoAxis from a vector of (unsorted) surfaces with 0303 /// PlanarBounds 0304 /// It loops through the surfaces and finds out the needed information 0305 /// First the surfaces are sorted in the binning direction and the so called 0306 /// "key" surfaces (surfaces with different positions in the binning 0307 /// direction) are extracted. The boundary value between two surfaces is the 0308 /// mean value of the two center position in the binning direction. The first 0309 /// and the last boundaries are calculated from the vertices of the first and 0310 /// last surface. 0311 /// @note currently implemented for phi, r and z bining 0312 /// @todo implement for x,y binning 0313 /// @param [in] gctx the geometry context for this call 0314 /// @param surfaces are the sensitive surfaces to be 0315 /// @param aDir the AxisDirection in which direction should be binned 0316 /// (currently possible: AxisPhi, AxisR, AxisZ) 0317 /// @param protoLayer Instance of @c ProtoLayer holding generic layer info 0318 /// @param transform is the (optional) additional transform applied 0319 /// @return Instance of @c ProtoAxis containing determined properties 0320 /// @note This only creates the @c ProtoAxis, this needs to be turned 0321 /// into an actual @c Axis object to be used 0322 ProtoAxis createVariableAxis(const GeometryContext& gctx, 0323 const std::vector<const Surface*>& surfaces, 0324 AxisDirection aDir, const ProtoLayer& protoLayer, 0325 Transform3& transform) const; 0326 0327 /// SurfaceArrayCreator internal method 0328 /// Creates a equidistant @c ProtoAxis when the extremas and the bin number 0329 /// are 0330 /// It loops through the surfaces and finds out the needed information 0331 /// First the surfaces are sorted in the binning direction and the so called 0332 /// "key" surfaces (surfaces with different positions in the binning 0333 /// direction) are extracted. The number of key surfaces euqals the number of 0334 /// bins. Afterwards the minimum and maximum are calculated by 0335 /// subtracting/adding half of a bin size to the center position (in the 0336 /// binning direction) to the first/last surface. 0337 /// @note currently implemented for phi, r and z bining 0338 /// @todo implement for x,y binning 0339 /// @param [in] gctx the geometry context for this call 0340 /// @param surfaces are the sensitive surfaces to be 0341 /// @param aDir the AxisDirection in which direction should be binned 0342 /// (currently possible: AxisPhi, AxisR, AxisZ) 0343 /// @param protoLayer Instance of @c ProtoLayer holding generic layer info 0344 /// @param transform is the (optional) additional transform applied 0345 /// @param nBins Number of bins to use, 0 means determine automatically 0346 /// @return Instance of @c ProtoAxis containing determined properties 0347 /// @note This only creates the @c ProtoAxis, this needs to be turned 0348 /// into an actual @c Axis object to be used 0349 ProtoAxis createEquidistantAxis(const GeometryContext& gctx, 0350 const std::vector<const Surface*>& surfaces, 0351 AxisDirection aDir, 0352 const ProtoLayer& protoLayer, 0353 Transform3& transform, 0354 std::size_t nBins = 0) const; 0355 0356 /// SurfaceArrayCreator internal method 0357 /// @brief Creates a SurfaceGridLookup instance within an any 0358 /// This is essentially a factory which absorbs some if/else logic 0359 /// that is required by the templating. 0360 /// @tparam bdtA AxisBoundaryType of axis A 0361 /// @tparam bdtB AxisBoundaryType of axis B 0362 /// @tparam F1 type-deducted value of g2l lambda 0363 /// @tparam F2 type-deducted value of l2g lambda 0364 /// @param globalToLocal transform callable 0365 /// @param localToGlobal transform callable 0366 /// @param pAxisA ProtoAxis object for axis A 0367 /// @param pAxisB ProtoAxis object for axis B 0368 template <AxisBoundaryType bdtA, AxisBoundaryType bdtB, typename F1, 0369 typename F2> 0370 static std::unique_ptr<SurfaceArray::ISurfaceGridLookup> 0371 makeSurfaceGridLookup2D(F1 globalToLocal, F2 localToGlobal, ProtoAxis pAxisA, 0372 ProtoAxis pAxisB) { 0373 using ISGL = SurfaceArray::ISurfaceGridLookup; 0374 std::unique_ptr<ISGL> ptr; 0375 0376 // this becomes completely unreadable otherwise 0377 // clang-format off 0378 if (pAxisA.bType == equidistant && pAxisB.bType == equidistant) { 0379 0380 Axis<AxisType::Equidistant, bdtA> axisA(pAxisA.min, pAxisA.max, pAxisA.nBins); 0381 Axis<AxisType::Equidistant, bdtB> axisB(pAxisB.min, pAxisB.max, pAxisB.nBins); 0382 0383 using SGL = SurfaceArray::SurfaceGridLookup<decltype(axisA), decltype(axisB)>; 0384 ptr = std::make_unique<SGL>( 0385 globalToLocal, localToGlobal, std::pair{axisA, axisB}, std::vector{pAxisA.axisDir, pAxisB.axisDir}); 0386 0387 } else if (pAxisA.bType == equidistant && pAxisB.bType == arbitrary) { 0388 0389 Axis<AxisType::Equidistant, bdtA> axisA(pAxisA.min, pAxisA.max, pAxisA.nBins); 0390 Axis<AxisType::Variable, bdtB> axisB(pAxisB.binEdges); 0391 0392 using SGL = SurfaceArray::SurfaceGridLookup<decltype(axisA), decltype(axisB)>; 0393 ptr = std::make_unique<SGL>( 0394 globalToLocal, localToGlobal, std::pair{axisA, axisB}, std::vector{pAxisA.axisDir, pAxisB.axisDir}); 0395 0396 } else if (pAxisA.bType == arbitrary && pAxisB.bType == equidistant) { 0397 0398 Axis<AxisType::Variable, bdtA> axisA(pAxisA.binEdges); 0399 Axis<AxisType::Equidistant, bdtB> axisB(pAxisB.min, pAxisB.max, pAxisB.nBins); 0400 0401 using SGL = SurfaceArray::SurfaceGridLookup<decltype(axisA), decltype(axisB)>; 0402 ptr = std::make_unique<SGL>( 0403 globalToLocal, localToGlobal, std::pair{axisA, axisB}, std::vector{pAxisA.axisDir, pAxisB.axisDir}); 0404 0405 } else /*if (pAxisA.bType == arbitrary && pAxisB.bType == arbitrary)*/ { 0406 0407 Axis<AxisType::Variable, bdtA> axisA(pAxisA.binEdges); 0408 Axis<AxisType::Variable, bdtB> axisB(pAxisB.binEdges); 0409 0410 using SGL = SurfaceArray::SurfaceGridLookup<decltype(axisA), decltype(axisB)>; 0411 ptr = std::make_unique<SGL>( 0412 globalToLocal, localToGlobal, std::pair{axisA, axisB}, std::vector{pAxisA.axisDir, pAxisB.axisDir}); 0413 } 0414 // clang-format on 0415 0416 return ptr; 0417 } 0418 0419 /// logging instance 0420 std::unique_ptr<const Logger> m_logger; 0421 0422 /// Private helper method to complete the binning 0423 /// 0424 /// 0425 /// given a grid point o 0426 /// | 0 | 1 | 2 | 3 | 4 | 0427 /// ------------------------------ 0428 /// 0 | x | | | | x | 0429 /// 1 | | | o | | | 0430 /// 2 | x | | | | x | 0431 /// 0432 /// This is being called when you chose to use more bins thans surfaces 0433 /// I.e. to put a finer granularity binning onto your surface 0434 /// Neighbour bins are then filled to contain pointers as well 0435 /// This method delegates to SurfaceGridLookup itself. 0436 /// @param [in] gctx the geometry context for this call 0437 /// @param sl The @c SurfaceGridLookup 0438 /// @param surfaces the surfaces 0439 void completeBinning(const GeometryContext& gctx, 0440 SurfaceArray::ISurfaceGridLookup& sl, 0441 const std::vector<const Surface*>& surfaces) const { 0442 ACTS_VERBOSE( 0443 "Complete binning by filling closest neighbour surfaces into " 0444 "empty bins."); 0445 0446 std::size_t binCompleted = sl.completeBinning(gctx, surfaces); 0447 0448 ACTS_VERBOSE(" filled : " << binCompleted 0449 << " (includes under/overflow)"); 0450 } 0451 0452 /// Private helper method to transform the vertices of surface bounds into 0453 /// global coordinates 0454 /// @param [in] gctx the geometry context for this call 0455 /// @param surface the surface associated with the given vertices 0456 /// @param locVertices a vector of the vertices in local coordinates 0457 /// @return a vector of the vertices in global coordinates 0458 std::vector<Acts::Vector3> makeGlobalVertices( 0459 const GeometryContext& gctx, const Acts::Surface& surface, 0460 const std::vector<Acts::Vector2>& locVertices) const; 0461 }; 0462 0463 } // namespace Acts
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |