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