|
||||
File indexing completed on 2025-01-19 09:23:23
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/BinningType.hpp" 0018 #include "Acts/Utilities/Logger.hpp" 0019 #include "Acts/Utilities/detail/AxisFwd.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::binPhi) { 0246 // Take the two binning positions 0247 auto pos1 = a->binningPosition(gctx, binR), 0248 pos2 = b->binningPosition(gctx, 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::binZ) { 0264 return (std::abs(a->binningPosition(gctx, binR).z() - 0265 b->binningPosition(gctx, binR).z()) < 1_um); 0266 } 0267 0268 if (bValue == Acts::binR) { 0269 return (std::abs(perp(a->binningPosition(gctx, binR)) - 0270 perp(b->binningPosition(gctx, binR))) < 1_um); 0271 } 0272 0273 return false; 0274 } 0275 0276 /// Set logging instance 0277 /// @param logger is the logging instance to be set 0278 void setLogger(std::unique_ptr<const Logger> logger) { 0279 m_logger = std::move(logger); 0280 } 0281 0282 private: 0283 /// configuration object 0284 Config m_cfg; 0285 0286 /// Private access to logger 0287 const Logger& logger() const { return *m_logger; } 0288 0289 std::vector<const Surface*> findKeySurfaces( 0290 const std::vector<const Surface*>& surfaces, 0291 const std::function<bool(const Surface*, const Surface*)>& equal) const; 0292 0293 std::size_t determineBinCount(const GeometryContext& gctx, 0294 const std::vector<const Surface*>& surfaces, 0295 BinningValue bValue) const; 0296 0297 /// SurfaceArrayCreator internal method 0298 /// Creates a variable @c ProtoAxis from a vector of (unsorted) surfaces with 0299 /// PlanarBounds 0300 /// It loops through the surfaces and finds out the needed information 0301 /// First the surfaces are sorted in the binning direction and the so called 0302 /// "key" surfaces (surfaces with different positions in the binning 0303 /// direction) are extracted. The boundary value between two surfaces is the 0304 /// mean value of the two center position in the binning direction. The first 0305 /// and the last boundaries are calculated from the vertices of the first and 0306 /// last surface. 0307 /// @note currently implemented for phi, r and z bining 0308 /// @todo implement for x,y binning 0309 /// @param [in] gctx the geometry context for this call 0310 /// @param surfaces are the sensitive surfaces to be 0311 /// @param bValue the BinningValue in which direction should be binned 0312 /// (currently possible: binPhi, binR, binZ) 0313 /// @param protoLayer Instance of @c ProtoLayer holding generic layer info 0314 /// @param transform is the (optional) additional transform applied 0315 /// @return Instance of @c ProtoAxis containing determined properties 0316 /// @note This only creates the @c ProtoAxis, this needs to be turned 0317 /// into an actual @c Axis object to be used 0318 ProtoAxis createVariableAxis(const GeometryContext& gctx, 0319 const std::vector<const Surface*>& surfaces, 0320 BinningValue bValue, 0321 const ProtoLayer& protoLayer, 0322 Transform3& transform) const; 0323 0324 /// SurfaceArrayCreator internal method 0325 /// Creates a equidistant @c ProtoAxis when the extremas and the bin number 0326 /// are 0327 /// It loops through the surfaces and finds out the needed information 0328 /// First the surfaces are sorted in the binning direction and the so called 0329 /// "key" surfaces (surfaces with different positions in the binning 0330 /// direction) are extracted. The number of key surfaces euqals the number of 0331 /// bins. Afterwards the minimum and maximum are calculated by 0332 /// subtracting/adding half of a bin size to the center position (in the 0333 /// binning direction) to the first/last surface. 0334 /// @note currently implemented for phi, r and z bining 0335 /// @todo implement for x,y binning 0336 /// @param [in] gctx the geometry context for this call 0337 /// @param surfaces are the sensitive surfaces to be 0338 /// @param bValue the BinningValue in which direction should be binned 0339 /// (currently possible: binPhi, binR, binZ) 0340 /// @param protoLayer Instance of @c ProtoLayer holding generic layer info 0341 /// @param transform is the (optional) additional transform applied 0342 /// @param nBins Number of bins to use, 0 means determine automatically 0343 /// @return Instance of @c ProtoAxis containing determined properties 0344 /// @note This only creates the @c ProtoAxis, this needs to be turned 0345 /// into an actual @c Axis object to be used 0346 ProtoAxis createEquidistantAxis(const GeometryContext& gctx, 0347 const std::vector<const Surface*>& surfaces, 0348 BinningValue bValue, 0349 const ProtoLayer& protoLayer, 0350 Transform3& transform, 0351 std::size_t nBins = 0) const; 0352 0353 /// SurfaceArrayCreator internal method 0354 /// @brief Creates a SurfaceGridLookup instance within an any 0355 /// This is essentially a factory which absorbs some if/else logic 0356 /// that is required by the templating. 0357 /// @tparam bdtA AxisBoundaryType of axis A 0358 /// @tparam bdtB AxisBoundaryType of axis B 0359 /// @tparam F1 type-deducted value of g2l lambda 0360 /// @tparam F2 type-deducted value of l2g lambda 0361 /// @param globalToLocal transform callable 0362 /// @param localToGlobal transform callable 0363 /// @param pAxisA ProtoAxis object for axis A 0364 /// @param pAxisB ProtoAxis object for axis B 0365 template <detail::AxisBoundaryType bdtA, detail::AxisBoundaryType bdtB, 0366 typename F1, typename F2> 0367 static std::unique_ptr<SurfaceArray::ISurfaceGridLookup> 0368 makeSurfaceGridLookup2D(F1 globalToLocal, F2 localToGlobal, ProtoAxis pAxisA, 0369 ProtoAxis pAxisB) { 0370 using ISGL = SurfaceArray::ISurfaceGridLookup; 0371 std::unique_ptr<ISGL> ptr; 0372 0373 // this becomes completely unreadable otherwise 0374 // clang-format off 0375 if (pAxisA.bType == equidistant && pAxisB.bType == equidistant) { 0376 0377 detail::Axis<detail::AxisType::Equidistant, bdtA> axisA(pAxisA.min, pAxisA.max, pAxisA.nBins); 0378 detail::Axis<detail::AxisType::Equidistant, bdtB> axisB(pAxisB.min, pAxisB.max, pAxisB.nBins); 0379 0380 using SGL = SurfaceArray::SurfaceGridLookup<decltype(axisA), decltype(axisB)>; 0381 ptr = std::unique_ptr<ISGL>(static_cast<ISGL*>( 0382 new SGL(globalToLocal, localToGlobal, std::make_tuple(axisA, axisB), {pAxisA.bValue, pAxisB.bValue}))); 0383 0384 } else if (pAxisA.bType == equidistant && pAxisB.bType == arbitrary) { 0385 0386 detail::Axis<detail::AxisType::Equidistant, bdtA> axisA(pAxisA.min, pAxisA.max, pAxisA.nBins); 0387 detail::Axis<detail::AxisType::Variable, bdtB> axisB(pAxisB.binEdges); 0388 0389 using SGL = SurfaceArray::SurfaceGridLookup<decltype(axisA), decltype(axisB)>; 0390 ptr = std::unique_ptr<ISGL>(static_cast<ISGL*>( 0391 new SGL(globalToLocal, localToGlobal, std::make_tuple(axisA, axisB), {pAxisA.bValue, pAxisB.bValue}))); 0392 0393 } else if (pAxisA.bType == arbitrary && pAxisB.bType == equidistant) { 0394 0395 detail::Axis<detail::AxisType::Variable, bdtA> axisA(pAxisA.binEdges); 0396 detail::Axis<detail::AxisType::Equidistant, bdtB> axisB(pAxisB.min, pAxisB.max, pAxisB.nBins); 0397 0398 using SGL = SurfaceArray::SurfaceGridLookup<decltype(axisA), decltype(axisB)>; 0399 ptr = std::unique_ptr<ISGL>(static_cast<ISGL*>( 0400 new SGL(globalToLocal, localToGlobal, std::make_tuple(axisA, axisB), {pAxisA.bValue, pAxisB.bValue}))); 0401 0402 } else /*if (pAxisA.bType == arbitrary && pAxisB.bType == arbitrary)*/ { 0403 0404 detail::Axis<detail::AxisType::Variable, bdtA> axisA(pAxisA.binEdges); 0405 detail::Axis<detail::AxisType::Variable, bdtB> axisB(pAxisB.binEdges); 0406 0407 using SGL = SurfaceArray::SurfaceGridLookup<decltype(axisA), decltype(axisB)>; 0408 ptr = std::unique_ptr<ISGL>(static_cast<ISGL*>( 0409 new SGL(globalToLocal, localToGlobal, std::make_tuple(axisA, axisB), {pAxisA.bValue, pAxisB.bValue}))); 0410 } 0411 // clang-format on 0412 0413 return ptr; 0414 } 0415 0416 /// logging instance 0417 std::unique_ptr<const Logger> m_logger; 0418 0419 /// Private helper method to complete the binning 0420 /// 0421 /// 0422 /// given a grid point o 0423 /// | 0 | 1 | 2 | 3 | 4 | 0424 /// ------------------------------ 0425 /// 0 | x | | | | x | 0426 /// 1 | | | o | | | 0427 /// 2 | x | | | | x | 0428 /// 0429 /// This is being called when you chose to use more bins thans surfaces 0430 /// I.e. to put a finer granularity binning onto your surface 0431 /// Neighbour bins are then filled to contain pointers as well 0432 /// This method delegates to SurfaceGridLookup itself. 0433 /// @param [in] gctx the geometry context for this call 0434 /// @param sl The @c SurfaceGridLookup 0435 /// @param surfaces the surfaces 0436 void completeBinning(const GeometryContext& gctx, 0437 SurfaceArray::ISurfaceGridLookup& sl, 0438 const std::vector<const Surface*>& surfaces) const { 0439 ACTS_VERBOSE( 0440 "Complete binning by filling closest neighbour surfaces into " 0441 "empty bins."); 0442 0443 std::size_t binCompleted = sl.completeBinning(gctx, surfaces); 0444 0445 ACTS_VERBOSE(" filled : " << binCompleted 0446 << " (includes under/overflow)"); 0447 } 0448 0449 /// Private helper method to transform the vertices of surface bounds into 0450 /// global coordinates 0451 /// @param [in] gctx the geometry context for this call 0452 /// @param surface the surface associated with the given vertices 0453 /// @param locVertices a vector of the vertices in local coordinates 0454 /// @return a vector of the vertices in global coordinates 0455 std::vector<Acts::Vector3> makeGlobalVertices( 0456 const GeometryContext& gctx, const Acts::Surface& surface, 0457 const std::vector<Acts::Vector2>& locVertices) const; 0458 }; 0459 0460 } // 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 |