|
|
|||
File indexing completed on 2026-04-17 07:46:20
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/Geometry/BlueprintNode.hpp" 0013 #include "Acts/Geometry/ContainerBlueprintNode.hpp" 0014 #include "Acts/Geometry/Extent.hpp" 0015 #include "Acts/Geometry/LayerBlueprintNode.hpp" 0016 #include "Acts/Geometry/NavigationPolicyFactory.hpp" 0017 #include "Acts/Geometry/VolumeAttachmentStrategy.hpp" 0018 #include "Acts/Navigation/CylinderNavigationPolicy.hpp" 0019 #include "Acts/Surfaces/Surface.hpp" 0020 #include "Acts/Utilities/Logger.hpp" 0021 0022 #include <concepts> 0023 #include <functional> 0024 #include <memory> 0025 #include <optional> 0026 #include <regex> 0027 #include <span> 0028 #include <string> 0029 #include <string_view> 0030 #include <type_traits> 0031 #include <utility> 0032 #include <variant> 0033 #include <vector> 0034 0035 namespace Acts::Experimental { 0036 0037 namespace detail { 0038 0039 /// @brief Concept requiring @p BackendT to expose a nested `LayerSpec` type. 0040 /// 0041 /// A backend satisfying this concept must define a `LayerSpec` struct that 0042 /// carries the configuration needed to construct a single detector layer. 0043 template <typename BackendT> 0044 concept HasLayerSpec = requires { typename BackendT::LayerSpec; }; 0045 0046 /// @brief Concept requiring a backend to expose axis-definition support in its 0047 /// `LayerSpec`. 0048 /// 0049 /// In addition to satisfying @ref HasLayerSpec, the backend must define an 0050 /// `AxisDefinition` type and the corresponding `LayerSpec` must have 0051 /// - `axes` : optional axes used to orient sensitive surfaces, and 0052 /// - `layerAxes` : optional axes used to determine the layer transform from the 0053 /// parent detector element shape. 0054 template <typename BackendT> 0055 concept HasAxisDefinition = 0056 HasLayerSpec<BackendT> && requires { typename BackendT::AxisDefinition; } && 0057 requires(typename BackendT::LayerSpec layerSpec, 0058 typename BackendT::AxisDefinition axes, 0059 std::optional<typename BackendT::AxisDefinition> layerAxes) { 0060 layerSpec.axes = std::move(axes); 0061 { layerSpec.axes.has_value() } -> std::convertible_to<bool>; 0062 layerSpec.layerAxes = std::move(axes); 0063 layerSpec.layerAxes = std::move(layerAxes); 0064 }; 0065 0066 using LayerNodePtr = std::shared_ptr<LayerBlueprintNode>; 0067 using ContainerNodePtr = std::shared_ptr<ContainerBlueprintNode>; 0068 using SurfacePtr = std::shared_ptr<Acts::Surface>; 0069 using SurfaceVector = std::vector<SurfacePtr>; 0070 0071 /// @brief Callback type that can replace or wrap a @ref LayerBlueprintNode. 0072 /// 0073 /// Receives the source layer element (or @c std::nullopt when no element 0074 /// context exists) and the newly created layer node, and returns the 0075 /// (possibly replaced) node to be added to the container. 0076 template <typename ElementT> 0077 using LayerCustomizer = std::function<std::shared_ptr<LayerBlueprintNode>( 0078 const std::optional<ElementT>&, std::shared_ptr<LayerBlueprintNode>)>; 0079 0080 /// @brief Callback type that can replace or wrap a 0081 /// @ref CylinderContainerBlueprintNode. 0082 template <typename ElementT> 0083 using ContainerCustomizer = 0084 std::function<std::shared_ptr<ContainerBlueprintNode>( 0085 const ElementT&, std::shared_ptr<ContainerBlueprintNode>)>; 0086 0087 /// @brief Concept satisfied when @p CallableT can be called with an optional 0088 /// element and a @ref LayerBlueprintNode shared pointer and returns a (possibly 0089 /// different) @ref LayerBlueprintNode shared pointer. 0090 /// 0091 /// Used to constrain the returning form of the `onLayer` callback accepted by 0092 /// the assembler builders. 0093 template <typename ElementT, typename CallableT> 0094 concept LayerNodeReturningCallable = 0095 std::invocable<CallableT&, const std::optional<ElementT>&, LayerNodePtr> && 0096 std::same_as<std::invoke_result_t< 0097 CallableT&, const std::optional<ElementT>&, LayerNodePtr>, 0098 LayerNodePtr>; 0099 0100 /// @brief Concept satisfied when @p CallableT can be called with an optional 0101 /// element and a mutable @ref LayerBlueprintNode reference and returns `void`. 0102 /// 0103 /// Used to constrain the in-place (mutating) form of the `onLayer` callback. 0104 template <typename ElementT, typename CallableT> 0105 concept LayerNodeReplacingCallable = 0106 std::invocable<CallableT&, const std::optional<ElementT>&, 0107 LayerBlueprintNode&> && 0108 std::same_as< 0109 std::invoke_result_t<CallableT&, const std::optional<ElementT>&, 0110 LayerBlueprintNode&>, 0111 void>; 0112 0113 /// @brief Concept satisfied when @p CallableT can be called with an element and 0114 /// a @ref ContainerBlueprintNode shared pointer and returns a (possibly 0115 /// different) @ref ContainerBlueprintNode shared pointer. 0116 /// 0117 /// Used to constrain the returning form of the `onContainer` callback. 0118 template <typename ElementT, typename CallableT> 0119 concept ContainerNodeReturningCallable = 0120 std::invocable<CallableT&, const ElementT&, ContainerNodePtr> && 0121 std::same_as< 0122 std::invoke_result_t<CallableT&, const ElementT&, ContainerNodePtr>, 0123 ContainerNodePtr>; 0124 0125 /// @brief Concept satisfied when @p CallableT can be called with an element and 0126 /// a mutable @ref ContainerBlueprintNode reference and returns `void`. 0127 /// 0128 /// Used to constrain the in-place (mutating) form of the `onContainer` 0129 /// callback. 0130 template <typename ElementT, typename CallableT> 0131 concept ContainerNodeReplacingCallable = 0132 std::invocable<CallableT&, const ElementT&, ContainerBlueprintNode&> && 0133 std::same_as<std::invoke_result_t<CallableT&, const ElementT&, 0134 ContainerBlueprintNode&>, 0135 void>; 0136 0137 /// @brief Concept requiring a backend to provide a surface-construction method. 0138 /// 0139 /// The method must accept a span of sensitive child elements plus a `LayerSpec` 0140 /// and return the corresponding ACTS surfaces. 0141 template <typename BackendT> 0142 concept HasSurfaceFactory = 0143 HasLayerSpec<BackendT> && 0144 requires(const BackendT& backend, 0145 std::span<const typename BackendT::Element> sensitives, 0146 const typename BackendT::LayerSpec& layerSpec) { 0147 { 0148 backend.makeSurfaces(sensitives, layerSpec) 0149 } -> std::same_as<SurfaceVector>; 0150 }; 0151 0152 /// @brief Optional backend capability to extract a layer transform from one 0153 /// context element and a layer specification. 0154 /// 0155 /// Backends that satisfy this concept may provide automatic layer-transform 0156 /// extraction (for example from detector-element geometry). The interface layer 0157 /// applies this only when a context element is available. 0158 template <typename BackendT> 0159 concept HasLayerTransformLookup = 0160 HasLayerSpec<BackendT> && 0161 requires(const BackendT& backend, const typename BackendT::Element& elem, 0162 const typename BackendT::LayerSpec& layerSpec) { 0163 { 0164 backend.lookupLayerTransform(elem, layerSpec) 0165 } -> std::same_as<std::optional<Acts::Transform3>>; 0166 }; 0167 0168 /// @brief Concept requiring `LayerSpec` to carry an optional `layerName` field. 0169 /// 0170 /// The `layerName` member, when set, overrides the name derived from the 0171 /// detector element hierarchy when constructing a layer node. 0172 template <typename BackendT> 0173 concept HasLayerNameMember = 0174 HasLayerSpec<BackendT> && requires(typename BackendT::LayerSpec layerSpec, 0175 std::optional<std::string> layerName) { 0176 layerSpec.layerName = std::move(layerName); 0177 { layerSpec.layerName.has_value() } -> std::convertible_to<bool>; 0178 }; 0179 0180 /// @brief Optional backend capability for barrel/endcap assembly discovery. 0181 template <typename BackendT> 0182 concept HasBarrelEndcapClassifier = requires( 0183 const BackendT& backend, const typename BackendT::Element& element) { 0184 { backend.isBarrel(element) } -> std::same_as<bool>; 0185 { backend.isEndcap(element) } -> std::same_as<bool>; 0186 { backend.isTracker(element) } -> std::same_as<bool>; 0187 }; 0188 0189 /// @brief Concept that fully constrains a geometry backend usable with 0190 /// @ref BlueprintBuilder. 0191 /// 0192 /// A conforming backend must: 0193 /// - satisfy @ref HasSurfaceFactory and @ref HasLayerNameMember, 0194 /// - be constructible from a `Config` object and an `Acts::Logger` reference, 0195 /// - expose the element-hierarchy query interface (`world`, `nameOf`, 0196 /// `children`, `parent`), 0197 /// - expose `isSensitive()`, and 0198 /// - support equality comparison between `Element` instances, and 0199 /// - define `static constexpr std::string_view kIdentifier`. 0200 template <typename BackendT> 0201 concept BlueprintBackend = 0202 HasSurfaceFactory<BackendT> && HasLayerNameMember<BackendT> && 0203 requires(const typename BackendT::Config& cfg, const Acts::Logger& logger, 0204 const BackendT& backend, 0205 const typename BackendT::Element& element) { 0206 BackendT{cfg, logger}; 0207 { BackendT::kIdentifier } -> std::convertible_to<std::string_view>; 0208 { backend.world() } -> std::same_as<typename BackendT::Element>; 0209 { backend.nameOf(element) } -> std::same_as<std::string>; 0210 { 0211 backend.children(element) 0212 } -> std::same_as<std::vector<typename BackendT::Element>>; 0213 { backend.parent(element) } -> std::same_as<typename BackendT::Element>; 0214 { backend.isSensitive(element) } -> std::same_as<bool>; 0215 requires requires(const typename BackendT::Element& a, 0216 const typename BackendT::Element& b) { 0217 { a == b } -> std::convertible_to<bool>; 0218 }; 0219 }; 0220 0221 } // namespace detail 0222 0223 template <detail::BlueprintBackend BackendT> 0224 class BlueprintBuilder; 0225 0226 template <detail::BlueprintBackend BackendT> 0227 class SensorLayerAssembler; 0228 0229 template <detail::BlueprintBackend BackendT> 0230 class SensorLayer; 0231 0232 /// @brief Fluent builder that assembles a flat collection of cylindrical or 0233 /// disc-like detector layers from layer-representative detector elements into a 0234 /// @ref CylinderContainerBlueprintNode. 0235 /// 0236 /// Each supplied element represents one layer: its hierarchy path is used as 0237 /// the layer name and (optionally) its geometry drives the layer transform. 0238 /// Obtained from @ref BlueprintBuilder::layers(). 0239 /// 0240 /// ```cpp 0241 /// builder.layers() 0242 /// .barrel() 0243 /// .setSensorAxes(myAxes) 0244 /// .setLayerFilter(layerPattern) 0245 /// .setContainer(containerElement) 0246 /// .addTo(parentNode); 0247 /// ``` 0248 /// 0249 /// @tparam BackendT Geometry backend that provides detector elements, layer 0250 /// specifications, hierarchy traversal, sensitive-element 0251 /// classification, and surface construction. 0252 template <detail::BlueprintBackend BackendT> 0253 class ElementLayerAssembler { 0254 public: 0255 /// The associated @ref BlueprintBuilder type. 0256 using Builder = BlueprintBuilder<BackendT>; 0257 /// Distinguishes barrel (Cylinder) from endcap (Disc) layer geometry. 0258 using LayerType = Acts::Experimental::LayerBlueprintNode::LayerType; 0259 /// Backend detector element handle type. 0260 using Element = typename BackendT::Element; 0261 /// Backend layer-specification type. 0262 using LayerSpec = typename BackendT::LayerSpec; 0263 /// Axis definition type, or `std::monostate` when the backend does not 0264 /// support axis definitions. 0265 using AxisDefinition = 0266 std::conditional_t<detail::HasAxisDefinition<BackendT>, 0267 typename BackendT::AxisDefinition, std::monostate>; 0268 /// Callback type that can replace or wrap a @ref LayerBlueprintNode. 0269 using LayerCustomizer = detail::LayerCustomizer<Element>; 0270 0271 /// @brief Set the layer geometry type explicitly. 0272 /// @param layerType `LayerType::Cylinder` for barrel, `LayerType::Disc` for 0273 /// endcap. 0274 /// @return `*this` (rvalue). 0275 [[nodiscard]] ElementLayerAssembler&& setLayerType(LayerType layerType) &&; 0276 0277 /// @brief Shorthand for `setLayerType(LayerType::Disc)`. 0278 /// @return `*this` (rvalue). 0279 [[nodiscard]] ElementLayerAssembler&& endcap() &&; 0280 0281 /// @brief Shorthand for `setLayerType(LayerType::Cylinder)`. 0282 /// @return `*this` (rvalue). 0283 [[nodiscard]] ElementLayerAssembler&& barrel() &&; 0284 0285 /// @brief Shorthand for `setLayerType(LayerType::Plane)`. 0286 /// @return `*this` (rvalue). 0287 [[nodiscard]] ElementLayerAssembler&& planar() &&; 0288 0289 /// @brief Set the axis definition used to orient sensitive surfaces. 0290 /// 0291 /// Only available when the backend defines an @ref AxisDefinition type and 0292 /// stores optional surface-axis information in `LayerSpec`. 0293 /// @param axes Axis definition forwarded to `LayerSpec::axes`. 0294 /// @return `*this` (rvalue). 0295 template <typename B = BackendT> 0296 [[nodiscard]] ElementLayerAssembler&& setSensorAxes( 0297 typename B::AxisDefinition axes) && 0298 requires(detail::HasAxisDefinition<B>) { 0299 m_layerSpec.axes = std::move(axes); 0300 return std::move(*this); 0301 } 0302 0303 /// @brief Set the axis definition used to derive the layer transform from the 0304 /// parent element shape. 0305 /// 0306 /// Only available when the backend defines an @ref AxisDefinition type and 0307 /// stores optional layer-axis information in `LayerSpec`. 0308 /// When set, the layer transform is extracted automatically from the 0309 /// geometry of the enclosing detector element. 0310 /// @param layerAxes Axis definition forwarded to `LayerSpec::layerAxes`. 0311 /// @return `*this` (rvalue). 0312 template <typename B = BackendT> 0313 [[nodiscard]] ElementLayerAssembler&& setLayerAxes( 0314 typename B::AxisDefinition layerAxes) && 0315 requires(detail::HasAxisDefinition<B>) { 0316 m_layerSpec.layerAxes = std::move(layerAxes); 0317 return std::move(*this); 0318 } 0319 0320 /// @brief Set the regex filter used to select layer elements inside the 0321 /// container by name string. 0322 /// @param pattern Regular-expression string; converted to `std::regex` 0323 /// internally. 0324 /// @return `*this` (rvalue). 0325 [[nodiscard]] ElementLayerAssembler&& setLayerFilter( 0326 const std::string& pattern) &&; 0327 0328 /// @brief Set the regex filter used to select layer elements inside the 0329 /// container. 0330 /// @param pattern Pre-compiled regular expression matched against each 0331 /// child element name. 0332 /// @return `*this` (rvalue). 0333 [[nodiscard]] ElementLayerAssembler&& setLayerFilter( 0334 const std::regex& pattern) &&; 0335 0336 /// @brief Set the detector element that acts as the containing volume for the 0337 /// layer search. 0338 /// @param container Element whose subtree is searched for layers matching the 0339 /// filter. 0340 /// @return `*this` (rvalue). 0341 [[nodiscard]] ElementLayerAssembler&& setContainer( 0342 const Element& container) &&; 0343 0344 /// @brief Override the output container node name. 0345 /// 0346 /// If set, this name is used verbatim for the produced 0347 /// @ref CylinderContainerBlueprintNode. Otherwise, the name is taken from the 0348 /// configured container element (when @ref setContainer is used). 0349 /// @param containerName Explicit container-node name to use. 0350 /// @return `*this` (rvalue). 0351 [[nodiscard]] ElementLayerAssembler&& setContainerName( 0352 std::string containerName) &&; 0353 0354 /// @brief Set an explicit suffix for produced layer node names. 0355 /// 0356 /// The final node name is `"<anchor path>|<suffix>"`. Use `std::nullopt` to 0357 /// clear a previously configured suffix. 0358 /// @param layerNameSuffix Optional suffix appended to each produced layer 0359 /// name. 0360 /// @return `*this` (rvalue). 0361 [[nodiscard]] ElementLayerAssembler&& setLayerNameSuffix( 0362 const std::optional<std::string>& layerNameSuffix) &&; 0363 0364 /// @brief Set an explicit list of layer-representative elements. 0365 /// 0366 /// When set, the assembler skips subtree discovery via `setContainer()` and 0367 /// uses these elements directly as layer representatives. `setLayerFilter()` 0368 /// still applies as an optional post-filter on this list. Set either 0369 /// @ref setContainerName or @ref setContainer to define the output container 0370 /// name. 0371 /// @param layerElements Layer-representative elements; one layer per element. 0372 /// @return `*this` (rvalue). 0373 [[nodiscard]] ElementLayerAssembler&& setLayerElements( 0374 std::vector<Element> layerElements) &&; 0375 0376 /// @brief Set the container element by name, searching from the world root. 0377 /// 0378 /// @throws std::runtime_error if no element with @p name is found. 0379 /// @param name Name of the detector element to use as the container. 0380 /// @return `*this` (rvalue). 0381 [[nodiscard]] ElementLayerAssembler&& setContainer( 0382 const std::string& name) &&; 0383 0384 /// @brief Set an envelope to be applied to every layer node produced. 0385 /// @param envelope Envelope margins added around each layer's extent. 0386 /// @return `*this` (rvalue). 0387 [[nodiscard]] ElementLayerAssembler&& setEnvelope( 0388 const Acts::ExtentEnvelope& envelope) &&; 0389 0390 /// @brief Control whether an empty layer collection is an error. 0391 /// 0392 /// When @p emptyOk is `false` (the default) and no layers are found in the 0393 /// container, @ref build() throws. Setting it to `true` downgrades the 0394 /// failure to an informational log message. 0395 /// @param emptyOk If `true`, silently accept an empty result. 0396 /// @return `*this` (rvalue). 0397 [[nodiscard]] ElementLayerAssembler&& setEmptyOk(bool emptyOk) &&; 0398 0399 /// @brief Register a callback invoked for each created layer node. 0400 /// 0401 /// The callback may either: 0402 /// - return a (possibly replaced/wrapped) @ref LayerBlueprintNode, or 0403 /// - mutate a @ref LayerBlueprintNode in-place and return `void`. 0404 /// 0405 /// In both cases, the first argument is the source layer element. 0406 /// @param customizer Callback applied to each created layer node. 0407 /// @return `*this` (rvalue). 0408 template <typename CustomizerT> 0409 [[nodiscard]] ElementLayerAssembler&& onLayer(CustomizerT customizer) && 0410 requires( 0411 detail::LayerNodeReturningCallable<Element, 0412 std::decay_t<CustomizerT>> || 0413 detail::LayerNodeReplacingCallable<Element, std::decay_t<CustomizerT>>) 0414 { 0415 if constexpr (detail::LayerNodeReturningCallable< 0416 Element, std::decay_t<CustomizerT>>) { 0417 m_onLayer = std::move(customizer); 0418 } else { 0419 m_onLayer = [customizer = std::move(customizer)]( 0420 const std::optional<Element>& layerElement, 0421 std::shared_ptr<LayerBlueprintNode> layer) mutable { 0422 customizer(layerElement, *layer); 0423 return layer; 0424 }; 0425 } 0426 return std::move(*this); 0427 } 0428 0429 /// @brief Override the attachment strategy for the container node. 0430 /// 0431 /// When unset the backend's default strategy is used. 0432 /// @param strategy Optional attachment strategy; pass `std::nullopt` to 0433 /// reset to the default. 0434 /// @return `*this` (rvalue). 0435 [[nodiscard]] ElementLayerAssembler&& setAttachmentStrategy( 0436 std::optional<Acts::VolumeAttachmentStrategy> strategy) &&; 0437 0438 /// @brief Build and return the assembled container node. 0439 /// 0440 /// Each resolved layer element becomes exactly one @ref LayerBlueprintNode. 0441 /// The layer name is derived from the element's full path in the hierarchy 0442 /// (plus an optional suffix). The layer transform is deduced from the element 0443 /// when `setLayerAxes()` is configured. 0444 /// 0445 /// @throws std::runtime_error if the layer type has not been set, if the 0446 /// backend requires axes and none were provided, if neither a layer 0447 /// filter nor explicit layer elements have been provided, if no 0448 /// container name is resolvable, or if the container yields no 0449 /// matching elements and @p emptyOk is `false`. 0450 /// @return Shared pointer to the fully assembled container node. 0451 [[nodiscard]] std::shared_ptr<Acts::Experimental::ContainerBlueprintNode> 0452 build() const; 0453 0454 /// @brief Build the container node and attach it as a child of @p node. 0455 /// 0456 /// Equivalent to `node.addChild(build())`. 0457 /// @param node Blueprint node that will receive the built container as a 0458 /// child. 0459 void addTo(Acts::Experimental::BlueprintNode& node) const&&; 0460 0461 private: 0462 friend class BlueprintBuilder<BackendT>; 0463 0464 /// @brief Construct an @ref ElementLayerAssembler bound to @p builder. 0465 /// @param builder The owning @ref BlueprintBuilder; must outlive this object. 0466 explicit ElementLayerAssembler(const Builder& builder); 0467 0468 const Builder* m_builder = nullptr; 0469 std::optional<LayerType> m_layerType; 0470 LayerSpec m_layerSpec{}; 0471 std::optional<std::regex> m_filter; 0472 std::optional<Element> m_container; 0473 std::optional<std::string> m_containerName; 0474 std::optional<std::vector<Element>> m_layerElements; 0475 std::optional<Acts::ExtentEnvelope> m_envelope; 0476 std::optional<Acts::VolumeAttachmentStrategy> m_attachmentStrategy; 0477 bool m_emptyOk = false; 0478 LayerCustomizer m_onLayer; 0479 }; 0480 0481 /// @brief Fluent builder that assembles multiple cylindrical or disc-like 0482 /// detector layers directly from sensor elements into a 0483 /// @ref CylinderContainerBlueprintNode. 0484 /// 0485 /// Unlike @ref ElementLayerAssembler, no layer-representative element is 0486 /// assumed to exist. Names and transforms are never deduced from the element 0487 /// hierarchy; they come solely from @ref groupBy keys. 0488 /// Obtained from @ref BlueprintBuilder::layersFromSensors(). 0489 /// 0490 /// A `groupBy` function is required: sensors mapped to the same key are merged 0491 /// into one layer, and the key becomes the layer name. 0492 /// 0493 /// For a single layer (no grouping), use @ref SensorLayer via 0494 /// @ref BlueprintBuilder::layerFromSensors() instead. 0495 /// 0496 /// ```cpp 0497 /// builder.layersFromSensors() 0498 /// .barrel() 0499 /// .setSensorAxes(myAxes) 0500 /// .setSensors(sensorElements) 0501 /// .groupBy(keyExtractor) 0502 /// .setContainerName("MyBarrel") 0503 /// .addTo(parentNode); 0504 /// ``` 0505 /// 0506 /// @tparam BackendT Geometry backend that provides detector elements, layer 0507 /// specifications, hierarchy traversal, sensitive-element 0508 /// classification, and surface construction. 0509 template <detail::BlueprintBackend BackendT> 0510 class SensorLayerAssembler { 0511 public: 0512 /// The associated @ref BlueprintBuilder type. 0513 using Builder = BlueprintBuilder<BackendT>; 0514 /// Distinguishes barrel (Cylinder) from endcap (Disc) layer geometry. 0515 using LayerType = LayerBlueprintNode::LayerType; 0516 /// Backend detector element handle type. 0517 using Element = typename BackendT::Element; 0518 /// Backend layer-specification type. 0519 using LayerSpec = typename BackendT::LayerSpec; 0520 /// Axis definition type, or `std::monostate` when the backend does not 0521 /// support axis definitions. 0522 using AxisDefinition = 0523 std::conditional_t<detail::HasAxisDefinition<BackendT>, 0524 typename BackendT::AxisDefinition, std::monostate>; 0525 /// Callback type that can replace or wrap a @ref LayerBlueprintNode. 0526 using LayerCustomizer = detail::LayerCustomizer<Element>; 0527 /// Callable that maps a sensor element to a string group key. 0528 using LayerGrouper = std::function<std::string(const Element&)>; 0529 0530 /// @brief Set the layer geometry type explicitly. 0531 /// @param layerType `LayerType::Cylinder` for barrel, `LayerType::Disc` for 0532 /// endcap. 0533 /// @return `*this` (rvalue). 0534 [[nodiscard]] SensorLayerAssembler&& setLayerType(LayerType layerType) &&; 0535 0536 /// @brief Shorthand for `setLayerType(LayerType::Disc)`. 0537 /// @return `*this` (rvalue). 0538 [[nodiscard]] SensorLayerAssembler&& endcap() &&; 0539 0540 /// @brief Shorthand for `setLayerType(LayerType::Cylinder)`. 0541 /// @return `*this` (rvalue). 0542 [[nodiscard]] SensorLayerAssembler&& barrel() &&; 0543 0544 /// @brief Shorthand for `setLayerType(LayerType::Plane)`. 0545 /// @return `*this` (rvalue). 0546 [[nodiscard]] SensorLayerAssembler&& planar() &&; 0547 0548 /// @brief Set the axis definition used to orient sensitive surfaces. 0549 /// 0550 /// Only available when the backend defines an @ref AxisDefinition type and 0551 /// stores optional surface-axis information in `LayerSpec`. 0552 /// @param axes Axis definition forwarded to `LayerSpec::axes`. 0553 /// @return `*this` (rvalue). 0554 template <typename B = BackendT> 0555 [[nodiscard]] SensorLayerAssembler&& setSensorAxes( 0556 typename B::AxisDefinition axes) && 0557 requires(detail::HasAxisDefinition<B>) { 0558 m_layerSpec.axes = std::move(axes); 0559 return std::move(*this); 0560 } 0561 0562 /// @brief Set the sensor elements to assemble into layers. 0563 /// @param sensors Sensor elements (leaf-level sensitives). 0564 /// @return `*this` (rvalue). 0565 [[nodiscard]] SensorLayerAssembler&& setSensors( 0566 std::vector<Element> sensors) &&; 0567 0568 /// @brief Group sensors into layers by key (required). 0569 /// 0570 /// Sensors mapped to the same key are merged into one layer. The key becomes 0571 /// the layer name. 0572 /// @param grouper Callable `std::string(const Element& sensor)`. 0573 /// @return `*this` (rvalue). 0574 [[nodiscard]] SensorLayerAssembler&& groupBy(LayerGrouper grouper) &&; 0575 0576 /// @brief Set the output container node name (required). 0577 /// @param containerName Name of the produced 0578 /// @ref CylinderContainerBlueprintNode. 0579 /// @return `*this` (rvalue). 0580 [[nodiscard]] SensorLayerAssembler&& setContainerName( 0581 std::string containerName) &&; 0582 0583 /// @brief Set an envelope applied to every produced layer node. 0584 /// @param envelope Envelope margins added around each layer's extent. 0585 /// @return `*this` (rvalue). 0586 [[nodiscard]] SensorLayerAssembler&& setEnvelope( 0587 const Acts::ExtentEnvelope& envelope) &&; 0588 0589 /// @brief Override the attachment strategy for the container node. 0590 /// 0591 /// When unset the backend's default strategy is used. 0592 /// @param strategy Optional attachment strategy; pass `std::nullopt` to 0593 /// reset to the default. 0594 /// @return `*this` (rvalue). 0595 [[nodiscard]] SensorLayerAssembler&& setAttachmentStrategy( 0596 std::optional<Acts::VolumeAttachmentStrategy> strategy) &&; 0597 0598 /// @brief Register a callback invoked for each created layer node. 0599 /// 0600 /// The callback may either return a (possibly replaced/wrapped) layer node, 0601 /// or mutate a layer node in-place and return `void`. 0602 /// @param customizer Callback applied to each created layer node. 0603 /// @return `*this` (rvalue). 0604 template <typename CustomizerT> 0605 [[nodiscard]] SensorLayerAssembler&& onLayer(CustomizerT customizer) && 0606 requires( 0607 detail::LayerNodeReturningCallable<Element, 0608 std::decay_t<CustomizerT>> || 0609 detail::LayerNodeReplacingCallable<Element, std::decay_t<CustomizerT>>) 0610 { 0611 if constexpr (detail::LayerNodeReturningCallable< 0612 Element, std::decay_t<CustomizerT>>) { 0613 m_onLayer = std::move(customizer); 0614 } else { 0615 m_onLayer = [customizer = std::move(customizer)]( 0616 const std::optional<Element>& elem, 0617 std::shared_ptr<LayerBlueprintNode> layer) mutable { 0618 customizer(elem, *layer); 0619 return layer; 0620 }; 0621 } 0622 return std::move(*this); 0623 } 0624 0625 /// @brief Build and return the assembled container node. 0626 /// 0627 /// @throws std::runtime_error if the layer type is not set, if the backend 0628 /// requires axes and none were provided, if sensors are not set, 0629 /// if 0630 /// the container name is not set, or if @ref groupBy has not been 0631 /// configured. 0632 /// @return Shared pointer to the assembled container node. 0633 [[nodiscard]] std::shared_ptr<ContainerBlueprintNode> build() const; 0634 0635 /// @brief Build the container node and attach it as a child of @p node. 0636 /// 0637 /// Equivalent to `node.addChild(build())`. 0638 /// @param node Blueprint node that will receive the built container as a 0639 /// child. 0640 void addTo(BlueprintNode& node) const&&; 0641 0642 private: 0643 friend class BlueprintBuilder<BackendT>; 0644 0645 /// @brief Construct a @ref SensorLayerAssembler bound to @p builder. 0646 /// @param builder The owning @ref BlueprintBuilder; must outlive this object. 0647 explicit SensorLayerAssembler(const Builder& builder); 0648 0649 const Builder* m_builder = nullptr; 0650 std::optional<LayerType> m_layerType; 0651 LayerSpec m_layerSpec{}; 0652 std::optional<std::vector<Element>> m_sensors; 0653 LayerGrouper m_groupBy; 0654 std::optional<std::string> m_containerName; 0655 std::optional<Acts::ExtentEnvelope> m_envelope; 0656 std::optional<Acts::VolumeAttachmentStrategy> m_attachmentStrategy; 0657 LayerCustomizer m_onLayer; 0658 }; 0659 0660 /// @brief Fluent builder that assembles a single cylindrical or disc-like 0661 /// detector layer directly from sensor elements, returning a 0662 /// @ref LayerBlueprintNode (no container wrapper). 0663 /// 0664 /// Unlike @ref SensorLayerAssembler, this builder produces exactly one layer. 0665 /// The layer name must be provided explicitly via @ref setLayerName. No 0666 /// grouping function is required or supported. 0667 /// Obtained from @ref BlueprintBuilder::layerFromSensors(). 0668 /// 0669 /// ```cpp 0670 /// builder.layerFromSensors() 0671 /// .barrel() 0672 /// .setSensorAxes(myAxes) 0673 /// .setSensors(sensorElements) 0674 /// .setLayerName("MyLayer") 0675 /// .addTo(parentNode); 0676 /// ``` 0677 /// 0678 /// @tparam BackendT Geometry backend that provides detector elements, layer 0679 /// specifications, hierarchy traversal, sensitive-element 0680 /// classification, and surface construction. 0681 template <detail::BlueprintBackend BackendT> 0682 class SensorLayer { 0683 public: 0684 /// The associated @ref BlueprintBuilder type. 0685 using Builder = BlueprintBuilder<BackendT>; 0686 /// Distinguishes barrel (Cylinder) from endcap (Disc) layer geometry. 0687 using LayerType = LayerBlueprintNode::LayerType; 0688 /// Backend detector element handle type. 0689 using Element = typename BackendT::Element; 0690 /// Backend layer-specification type. 0691 using LayerSpec = typename BackendT::LayerSpec; 0692 /// Axis definition type, or `std::monostate` when the backend does not 0693 /// support axis definitions. 0694 using AxisDefinition = 0695 std::conditional_t<detail::HasAxisDefinition<BackendT>, 0696 typename BackendT::AxisDefinition, std::monostate>; 0697 /// Callback type that can replace or wrap a @ref LayerBlueprintNode. 0698 using LayerCustomizer = detail::LayerCustomizer<Element>; 0699 0700 /// @brief Set the layer geometry type explicitly. 0701 /// @param layerType `LayerType::Cylinder` for barrel, `LayerType::Disc` for 0702 /// endcap. 0703 /// @return `*this` (rvalue). 0704 [[nodiscard]] SensorLayer&& setLayerType(LayerType layerType) &&; 0705 0706 /// @brief Shorthand for `setLayerType(LayerType::Disc)`. 0707 /// @return `*this` (rvalue). 0708 [[nodiscard]] SensorLayer&& endcap() &&; 0709 0710 /// @brief Shorthand for `setLayerType(LayerType::Cylinder)`. 0711 /// @return `*this` (rvalue). 0712 [[nodiscard]] SensorLayer&& barrel() &&; 0713 0714 /// @brief Shorthand for `setLayerType(LayerType::Plane)`. 0715 /// @return `*this` (rvalue). 0716 [[nodiscard]] SensorLayer&& planar() &&; 0717 0718 /// @brief Set the axis definition used to orient sensitive surfaces. 0719 /// 0720 /// Only available when the backend defines an @ref AxisDefinition type and 0721 /// stores optional surface-axis information in `LayerSpec`. 0722 /// @param axes Axis definition forwarded to `LayerSpec::axes`. 0723 /// @return `*this` (rvalue). 0724 template <typename B = BackendT> 0725 [[nodiscard]] SensorLayer&& setSensorAxes( 0726 typename B::AxisDefinition axes) && 0727 requires(detail::HasAxisDefinition<B>) { 0728 m_layerSpec.axes = std::move(axes); 0729 return std::move(*this); 0730 } 0731 0732 /// @brief Set the sensor elements to assemble into the layer. 0733 /// @param sensors Sensor elements (leaf-level sensitives). 0734 /// @return `*this` (rvalue). 0735 [[nodiscard]] SensorLayer&& setSensors(std::vector<Element> sensors) &&; 0736 0737 /// @brief Set the name for the produced layer node (required). 0738 /// @param name Layer node name. 0739 /// @return `*this` (rvalue). 0740 [[nodiscard]] SensorLayer&& setLayerName(std::string name) &&; 0741 0742 /// @brief Set an envelope applied to the produced layer node. 0743 /// @param envelope Envelope margins added around the layer's extent. 0744 /// @return `*this` (rvalue). 0745 [[nodiscard]] SensorLayer&& setEnvelope( 0746 const Acts::ExtentEnvelope& envelope) &&; 0747 0748 /// @brief Register a callback invoked for the created layer node. 0749 /// 0750 /// The callback may either return a (possibly replaced/wrapped) layer node, 0751 /// or mutate a layer node in-place and return `void`. 0752 /// @param customizer Callback applied to the created layer node. 0753 /// @return `*this` (rvalue). 0754 template <typename CustomizerT> 0755 [[nodiscard]] SensorLayer&& onLayer(CustomizerT customizer) && 0756 requires( 0757 detail::LayerNodeReturningCallable<Element, 0758 std::decay_t<CustomizerT>> || 0759 detail::LayerNodeReplacingCallable<Element, std::decay_t<CustomizerT>>) 0760 { 0761 if constexpr (detail::LayerNodeReturningCallable< 0762 Element, std::decay_t<CustomizerT>>) { 0763 m_onLayer = std::move(customizer); 0764 } else { 0765 m_onLayer = [customizer = std::move(customizer)]( 0766 const std::optional<Element>& elem, 0767 std::shared_ptr<LayerBlueprintNode> layer) mutable { 0768 customizer(elem, *layer); 0769 return layer; 0770 }; 0771 } 0772 return std::move(*this); 0773 } 0774 0775 /// @brief Build and return the assembled layer node. 0776 /// 0777 /// @throws std::runtime_error if the layer type is not set, if the backend 0778 /// requires axes and none were provided, if sensors are not set, 0779 /// or 0780 /// if @ref setLayerName has not been called. 0781 /// @return Shared pointer to the assembled @ref LayerBlueprintNode. 0782 [[nodiscard]] std::shared_ptr<LayerBlueprintNode> build() const; 0783 0784 /// @brief Build the layer node and attach it as a child of @p node. 0785 /// 0786 /// Equivalent to `node.addChild(build())`. 0787 /// @param node Blueprint node that will receive the built layer as a child. 0788 void addTo(BlueprintNode& node) const&&; 0789 0790 private: 0791 friend class BlueprintBuilder<BackendT>; 0792 0793 /// @brief Construct a @ref SensorLayer bound to @p builder. 0794 /// @param builder The owning @ref BlueprintBuilder; must outlive this object. 0795 explicit SensorLayer(const Builder& builder); 0796 0797 const Builder* m_builder = nullptr; 0798 std::optional<LayerType> m_layerType; 0799 LayerSpec m_layerSpec{}; 0800 std::optional<std::vector<Element>> m_sensors; 0801 std::optional<std::string> m_layerName; 0802 std::optional<Acts::ExtentEnvelope> m_envelope; 0803 LayerCustomizer m_onLayer; 0804 }; 0805 0806 /// @brief Fluent builder that assembles a combined barrel + endcap subdetector 0807 /// into a @ref CylinderContainerBlueprintNode arranged along the Z axis. 0808 /// 0809 /// Instances are obtained from @ref BlueprintBuilder::barrelEndcap(). The 0810 /// builder inspects the subtree of the provided assembly element for barrel and 0811 /// endcap children (using the backend's `isBarrel` / `isEndcap` / `isTracker` 0812 /// predicates, when available) and delegates individual layer assembly to 0813 /// @ref ElementLayerAssembler internally. 0814 /// 0815 /// Typical usage: 0816 /// @code 0817 /// builder.barrelEndcap() 0818 /// .setAssembly(innerTrackerElement) 0819 /// .setSensorAxes(barrelAxes, endcapAxes) 0820 /// .setLayerFilter(layerPattern) 0821 /// .addTo(rootNode); 0822 /// @endcode 0823 /// 0824 /// This builder requires backend predicates that classify elements as barrel, 0825 /// endcap, and tracker components. 0826 /// @tparam BackendT Geometry backend that provides detector elements, layer 0827 /// specifications, hierarchy traversal, sensitive-element 0828 /// classification, and surface construction. 0829 template <detail::BlueprintBackend BackendT> 0830 class BarrelEndcapAssembler { 0831 public: 0832 /// The associated @ref BlueprintBuilder type. 0833 using Builder = BlueprintBuilder<BackendT>; 0834 /// Backend detector element handle type. 0835 using Element = typename BackendT::Element; 0836 /// Axis definition type, or `std::monostate` when the backend does not 0837 /// support axis definitions. 0838 using AxisDefinition = 0839 std::conditional_t<detail::HasAxisDefinition<BackendT>, 0840 typename BackendT::AxisDefinition, std::monostate>; 0841 /// The @ref ElementLayerAssembler specialisation for this backend. 0842 using ElementLayerAssembler = 0843 ::Acts::Experimental::ElementLayerAssembler<BackendT>; 0844 /// Callback type that can replace or wrap a 0845 /// @ref CylinderContainerBlueprintNode. 0846 using ContainerCustomizer = detail::ContainerCustomizer<Element>; 0847 0848 /// @brief Construct a @ref BarrelEndcapAssembler bound to @p builder. 0849 /// @param builder The owning @ref BlueprintBuilder; must outlive this object. 0850 explicit BarrelEndcapAssembler(const Builder& builder); 0851 0852 /// @brief Build and return the assembled barrel+endcap container node. 0853 /// 0854 /// Locates barrel and endcap sub-elements inside the assembly, creates one 0855 /// @ref ElementLayerAssembler -based barrel container and one or more endcap 0856 /// containers, then returns a Z-axis @ref CylinderContainerBlueprintNode 0857 /// holding them all. 0858 /// 0859 /// @throws std::runtime_error if the assembly element has not been set, if 0860 /// axes are required by the backend but not provided, if the layer 0861 /// filter has not been set, or if more than one barrel element is 0862 /// found inside the assembly. 0863 /// @return Shared pointer to the assembled Z-axis container node. 0864 [[nodiscard]] std::shared_ptr<CylinderContainerBlueprintNode> build() const 0865 requires(detail::HasBarrelEndcapClassifier<BackendT>); 0866 0867 /// @brief Build the container node and attach it as a child of @p node. 0868 /// 0869 /// Equivalent to `node.addChild(build())`. 0870 /// @param node Blueprint node that will receive the built container as a 0871 /// child. 0872 void addTo(BlueprintNode& node) const&& 0873 requires(detail::HasBarrelEndcapClassifier<BackendT>); 0874 0875 /// @brief Register a layer callback forwarded to each inner 0876 /// @ref ElementLayerAssembler. 0877 /// 0878 /// The callback may either return a (possibly replaced/wrapped) layer node, 0879 /// or mutate a layer node in-place and return `void`. 0880 /// @param customizer Callback applied to each created layer node. 0881 /// @return `*this` (rvalue). 0882 template <typename CustomizerT> 0883 [[nodiscard]] BarrelEndcapAssembler&& onLayer(CustomizerT customizer) && 0884 requires( 0885 detail::LayerNodeReturningCallable<Element, 0886 std::decay_t<CustomizerT>> || 0887 detail::LayerNodeReplacingCallable<Element, std::decay_t<CustomizerT>>) 0888 { 0889 if constexpr (detail::LayerNodeReturningCallable< 0890 Element, std::decay_t<CustomizerT>>) { 0891 m_onLayer = std::move(customizer); 0892 } else { 0893 m_onLayer = [customizer = std::move(customizer)]( 0894 const std::optional<Element>& elem, 0895 std::shared_ptr<LayerBlueprintNode> layer) mutable { 0896 customizer(elem, *layer); 0897 return layer; 0898 }; 0899 } 0900 return std::move(*this); 0901 } 0902 0903 /// @brief Register a callback invoked for each barrel or endcap container 0904 /// node. 0905 /// 0906 /// The callback may either return a (possibly replaced/wrapped) container 0907 /// node, or mutate a container node in-place and return `void`. 0908 /// @param customizer Callback applied to each created barrel or endcap 0909 /// container node. 0910 /// @return `*this` (rvalue). 0911 template <typename CustomizerT> 0912 [[nodiscard]] BarrelEndcapAssembler&& onContainer(CustomizerT customizer) && 0913 requires(detail::ContainerNodeReturningCallable< 0914 Element, std::decay_t<CustomizerT>> || 0915 detail::ContainerNodeReplacingCallable<Element, 0916 std::decay_t<CustomizerT>>) 0917 { 0918 if constexpr (detail::ContainerNodeReturningCallable< 0919 Element, std::decay_t<CustomizerT>>) { 0920 m_onContainer = std::move(customizer); 0921 } else { 0922 m_onContainer = 0923 [customizer = std::move(customizer)]( 0924 const Element& elem, 0925 std::shared_ptr<ContainerBlueprintNode> node) mutable { 0926 customizer(elem, *node); 0927 return node; 0928 }; 0929 } 0930 return std::move(*this); 0931 } 0932 0933 /// @brief Set the top-level detector element whose subtree is searched for 0934 /// barrel and endcap elements. 0935 /// @param assembly Root element of the barrel+endcap sub-detector. 0936 /// @return `*this` (rvalue). 0937 [[nodiscard]] BarrelEndcapAssembler&& setAssembly(const Element& assembly) &&; 0938 0939 /// @brief Set the axis definitions for both barrel and endcap layers at once. 0940 /// 0941 /// Only available when the backend defines an @ref AxisDefinition type and 0942 /// stores optional surface-axis information in `LayerSpec`. 0943 /// @param barrel Axis definition forwarded to barrel 0944 /// @ref ElementLayerAssembler s. 0945 /// @param endcap Axis definition forwarded to endcap 0946 /// @ref ElementLayerAssembler s. 0947 /// @return `*this` (rvalue). 0948 [[nodiscard]] BarrelEndcapAssembler&& setSensorAxes(AxisDefinition barrel, 0949 AxisDefinition endcap) && 0950 requires(detail::HasAxisDefinition<BackendT>); 0951 0952 /// @brief Set the axis definition used for endcap layers only. 0953 /// 0954 /// Only available when the backend defines an @ref AxisDefinition type and 0955 /// stores optional surface-axis information in `LayerSpec`. 0956 /// @param axes Axis definition forwarded to endcap 0957 /// @ref ElementLayerAssembler s. 0958 /// @return `*this` (rvalue). 0959 [[nodiscard]] BarrelEndcapAssembler&& setEndcapAxes(AxisDefinition axes) && 0960 requires(detail::HasAxisDefinition<BackendT>); 0961 0962 /// @brief Set the regex filter used to select individual layer elements 0963 /// within each barrel or endcap container. 0964 /// @param pattern Regular expression matched against child element names. 0965 /// @return `*this` (rvalue). 0966 [[nodiscard]] BarrelEndcapAssembler&& setLayerFilter( 0967 const std::regex& pattern) &&; 0968 0969 private: 0970 typename ElementLayerAssembler::LayerCustomizer m_onLayer; 0971 ContainerCustomizer m_onContainer = 0972 [](const Element&, std::shared_ptr<ContainerBlueprintNode> node) { 0973 return node; 0974 }; 0975 0976 std::optional<Element> m_assembly; 0977 std::optional<AxisDefinition> m_barrelAxes; 0978 std::optional<AxisDefinition> m_endcapAxes; 0979 std::optional<std::regex> m_layerFilter; 0980 const Builder* m_builder = nullptr; 0981 }; 0982 0983 /// @brief High-level builder that converts a backend detector element hierarchy 0984 /// into a blueprint node tree. 0985 /// 0986 /// @ref BlueprintBuilder provides the entry points for blueprint construction: 0987 /// - @ref BlueprintBuilder::layers() returns an @ref ElementLayerAssembler 0988 /// for building a layer stack from layer-representative detector elements, 0989 /// - @ref BlueprintBuilder::layersFromSensors() returns a 0990 /// @ref SensorLayerAssembler for building multiple layers directly from 0991 /// sensor elements (`groupBy` required), 0992 /// - @ref BlueprintBuilder::layerFromSensors() returns a @ref SensorLayer for 0993 /// building a single layer directly from sensor elements, 0994 /// - @ref BlueprintBuilder::barrelEndcap() returns a 0995 /// @ref BarrelEndcapAssembler for combined barrel+endcap sub-detectors. 0996 /// 0997 /// It also exposes helpers for traversing and querying the detector element 0998 /// hierarchy, which are used internally by the assembler classes. 0999 /// 1000 /// The builder is parameterised on a backend type @p BackendT. The backend 1001 /// must be constructible from its `Config` plus an `Acts::Logger`, expose 1002 /// `Element` and `LayerSpec` types, traverse the detector hierarchy via 1003 /// `world()` / `children()` / `parent()` / `nameOf()`, classify sensitive 1004 /// elements with `isSensitive()`, and build ACTS surfaces from sensitive 1005 /// elements and a layer specification. It encapsulates all 1006 /// geometry-framework-specific knowledge (e.g. DD4hep `DetElement` 1007 /// navigation, type-flag interpretation, surface conversion). 1008 /// 1009 /// @tparam BackendT Geometry backend that provides detector elements, layer 1010 /// specifications, hierarchy traversal, sensitive-element 1011 /// classification, and surface construction. 1012 template <detail::BlueprintBackend BackendT> 1013 class BlueprintBuilder { 1014 public: 1015 /// The backend type. 1016 using Backend = BackendT; 1017 /// Backend detector element handle type. 1018 using Element = typename Backend::Element; 1019 /// Backend layer-specification type. 1020 using LayerSpec = typename Backend::LayerSpec; 1021 /// Axis definition type, or `std::monostate` when the backend does not 1022 /// support axis definitions. 1023 using AxisDefinition = 1024 std::conditional_t<detail::HasAxisDefinition<Backend>, 1025 typename Backend::AxisDefinition, std::monostate>; 1026 /// The @ref ElementLayerAssembler specialisation for this backend. 1027 using ElementLayerAssembler = 1028 ::Acts::Experimental::ElementLayerAssembler<Backend>; 1029 /// The @ref SensorLayerAssembler specialisation for this backend. 1030 using SensorLayerAssembler = 1031 ::Acts::Experimental::SensorLayerAssembler<Backend>; 1032 /// The @ref SensorLayer specialisation for this backend. 1033 using SensorLayer = ::Acts::Experimental::SensorLayer<Backend>; 1034 /// The @ref BarrelEndcapAssembler specialisation for this backend. 1035 using BarrelEndcapAssembler = 1036 ::Acts::Experimental::BarrelEndcapAssembler<Backend>; 1037 1038 /// @brief Construct a `BlueprintBuilder` from a backend configuration. 1039 /// 1040 /// @param cfg Backend-specific configuration object passed directly to the 1041 /// backend constructor. 1042 /// @param logger_ Optional logger; defaults to an `INFO`-level logger named 1043 /// `"BlueprintBuilder"`. 1044 explicit BlueprintBuilder(const typename Backend::Config& cfg, 1045 std::unique_ptr<const Acts::Logger> logger_ = 1046 Acts::getDefaultLogger("BlueprintBuilder", 1047 Acts::Logging::INFO)); 1048 1049 /// @brief Create a @ref LayerBlueprintNode from a single detector element. 1050 /// 1051 /// Recursively collects all sensitive descendants of @p layerElement and 1052 /// delegates to the two-argument overload. 1053 /// @param layerElement Layer element whose subtree is scanned for 1054 /// sensitive volumes. 1055 /// @param layerSpec Specification controlling surface axes and optional 1056 /// name/transform overrides. 1057 /// @return Shared pointer to the constructed @ref LayerBlueprintNode. 1058 std::shared_ptr<LayerBlueprintNode> makeLayer( 1059 const Element& layerElement, const LayerSpec& layerSpec) const; 1060 1061 /// @brief Create a @ref LayerBlueprintNode from an explicit list of sensitive 1062 /// elements. 1063 /// 1064 /// This is a low-level forwarding API: @p layerSpec is passed to the backend 1065 /// as-is. 1066 /// @param parent Detector element that contextualises the layer 1067 /// (used for naming and transform extraction). 1068 /// @param sensitives Span of sensitive detector elements to be converted to 1069 /// surfaces and assigned to the node. 1070 /// @param layerSpec Specification controlling surface axes and optional 1071 /// name/transform overrides. 1072 /// @return Shared pointer to the constructed @ref LayerBlueprintNode. 1073 std::shared_ptr<LayerBlueprintNode> makeLayer( 1074 const Element& parent, std::span<const Element> sensitives, 1075 const LayerSpec& layerSpec) const; 1076 1077 /// @brief Create a @ref LayerBlueprintNode from sensitive elements without 1078 /// a parent/context element. 1079 /// 1080 /// This variant cannot perform parent-based transform extraction. 1081 /// `layerSpec.layerName` must be set and is used verbatim. 1082 /// @param sensitives Span of sensitive detector elements to be converted to 1083 /// surfaces and assigned to the node. 1084 /// @param layerSpec Specification controlling surface axes and name. 1085 /// @throws std::runtime_error if `layerSpec.layerName` is not set. 1086 /// @return Shared pointer to the constructed @ref LayerBlueprintNode. 1087 std::shared_ptr<LayerBlueprintNode> makeLayer( 1088 std::span<const Element> sensitives, const LayerSpec& layerSpec) const; 1089 1090 /// @brief Create an @ref ElementLayerAssembler bound to this builder. 1091 /// 1092 /// Use when layer-representative detector elements exist in the hierarchy. 1093 /// Each element becomes one layer; name and transform are deduced from it. 1094 /// @return A new @ref ElementLayerAssembler instance. 1095 [[nodiscard]] ElementLayerAssembler layers() const; 1096 1097 /// @brief Create a @ref SensorLayerAssembler bound to this builder. 1098 /// 1099 /// Use when sensor elements are supplied directly and no layer-representative 1100 /// element exists. A @ref SensorLayerAssembler::groupBy function is required; 1101 /// sensors sharing the same key are merged into one layer per key. For a 1102 /// single layer without grouping, use @ref layerFromSensors() instead. 1103 /// @return A new @ref SensorLayerAssembler instance. 1104 [[nodiscard]] SensorLayerAssembler layersFromSensors() const; 1105 1106 /// @brief Create a @ref SensorLayer bound to this builder. 1107 /// 1108 /// Use when all sensor elements belong to exactly one layer and no grouping 1109 /// is needed. The layer name must be set explicitly via 1110 /// @ref SensorLayer::setLayerName. The result is a single 1111 /// @ref LayerBlueprintNode (no container wrapper). 1112 /// @return A new @ref SensorLayer instance. 1113 [[nodiscard]] SensorLayer layerFromSensors() const; 1114 1115 /// @brief Create a @ref BarrelEndcapAssembler bound to this builder. 1116 /// 1117 /// The returned assembler must be configured (assembly element, axes, layer 1118 /// filter) and then finalised via @ref BarrelEndcapAssembler::build() or 1119 /// @ref BarrelEndcapAssembler::addTo(). 1120 /// @return A new @ref BarrelEndcapAssembler instance. 1121 [[nodiscard]] BarrelEndcapAssembler barrelEndcap() const 1122 requires(detail::HasBarrelEndcapClassifier<Backend>); 1123 1124 /// @brief Search for a detector element by exact name within a subtree. 1125 /// 1126 /// Performs a depth-first search starting at @p parent. 1127 /// @param parent Starting element for the search. 1128 /// @param name Exact element name to match. 1129 /// @return The first matching element, or `std::nullopt` if not found. 1130 std::optional<Element> findDetElementByName(const Element& parent, 1131 const std::string& name) const; 1132 1133 /// @brief Search for a detector element by exact name starting from the world 1134 /// root. 1135 /// @param name Exact element name to match. 1136 /// @return The first matching element, or `std::nullopt` if not found. 1137 std::optional<Element> findDetElementByName(const std::string& name) const; 1138 1139 /// @brief Build a separator-joined path string from the world root down to 1140 /// @p elem. 1141 /// 1142 /// The path consists of element names at each level of the hierarchy, from 1143 /// the immediate child of the world element down to @p elem, joined by 1144 /// @p separator. 1145 /// @param elem Target element. 1146 /// @param separator String inserted between successive name components 1147 /// (default: `"|"`). 1148 /// @return The assembled path string. 1149 std::string getPathToElementName(const Element& elem, 1150 std::string_view separator = "|") const; 1151 1152 /// @brief Collect all elements in a subtree whose names match a regex. 1153 /// 1154 /// Performs a depth-first traversal of the subtree rooted at @p parent and 1155 /// returns every element whose name fully matches @p pattern 1156 /// (`std::regex_match`). 1157 /// @param parent Root of the subtree to search. 1158 /// @param pattern Regular expression matched against each element name. 1159 /// @return Vector of matching elements in depth-first order. 1160 std::vector<Element> findDetElementByNamePattern( 1161 const Element& parent, const std::regex& pattern) const; 1162 1163 /// @brief Collect all barrel tracker elements within an assembly subtree. 1164 /// 1165 /// An element is included when the backend reports it as both a tracker 1166 /// element and a barrel element. 1167 /// @param assembly Root element of the assembly subtree to search. 1168 /// @return Vector of barrel elements in depth-first order. 1169 std::vector<Element> findBarrelElements(const Element& assembly) const 1170 requires(detail::HasBarrelEndcapClassifier<Backend>); 1171 1172 /// @brief Collect all endcap tracker elements within an assembly subtree. 1173 /// 1174 /// An element is included when the backend reports it as both a tracker 1175 /// element and an endcap element. 1176 /// @param assembly Root element of the assembly subtree to search. 1177 /// @return Vector of endcap elements in depth-first order. 1178 std::vector<Element> findEndcapElements(const Element& assembly) const 1179 requires(detail::HasBarrelEndcapClassifier<Backend>); 1180 1181 /// @brief Return the logger associated with this builder. 1182 /// @return Reference to the logger instance. 1183 const Acts::Logger& logger() const; 1184 1185 /// @brief Return the backend associated with this builder. 1186 /// @return Const reference to the backend instance. 1187 const Backend& backend() const; 1188 1189 /// @brief Recursively collect all sensitive descendant elements. 1190 /// 1191 /// Traverses the subtree rooted at @p detElement and returns every element 1192 /// for which the backend's `isSensitive()` predicate returns `true`. 1193 /// @param detElement Root of the subtree to scan. 1194 /// @return Vector of sensitive elements in depth-first order. 1195 std::vector<Element> resolveSensitives(const Element& detElement) const; 1196 1197 private: 1198 std::unique_ptr<const Acts::Logger> m_logger; 1199 Backend m_backend; 1200 }; 1201 1202 } // namespace Acts::Experimental
| [ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
|
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
|