File indexing completed on 2026-04-17 07:46:20
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #pragma once
0015
0016 #include "Acts/Geometry/BlueprintBuilder.hpp"
0017 #include "Acts/Utilities/FunctionComposition.hpp"
0018
0019 namespace Acts::Experimental {
0020
0021 namespace detail {
0022
0023 template <typename ElementT>
0024 struct LayerBuildInputs {
0025 std::vector<ElementT> layerElements;
0026 std::optional<std::string> deducedContainerName;
0027 };
0028
0029 template <detail::BlueprintBackend BackendT>
0030 LayerBuildInputs<typename BackendT::Element> resolveLayerBuildInputs(
0031 const BlueprintBuilder<BackendT>& builder,
0032 const std::optional<typename BackendT::Element>& container,
0033 const std::optional<std::vector<typename BackendT::Element>>&
0034 explicitLayerElements,
0035 const std::optional<std::regex>& filter) {
0036 using Element = typename BackendT::Element;
0037 LayerBuildInputs<Element> inputs;
0038
0039 if (container.has_value()) {
0040 inputs.deducedContainerName = builder.backend().nameOf(container.value());
0041 }
0042
0043 if (explicitLayerElements.has_value()) {
0044 inputs.layerElements = *explicitLayerElements;
0045
0046 if (filter.has_value()) {
0047 std::vector<Element> filteredLayerElements;
0048 filteredLayerElements.reserve(inputs.layerElements.size());
0049 for (const auto& layerElement : inputs.layerElements) {
0050 const std::string layerElementName =
0051 builder.backend().nameOf(layerElement);
0052 if (std::regex_match(layerElementName, filter.value())) {
0053 filteredLayerElements.push_back(layerElement);
0054 }
0055 }
0056 inputs.layerElements = std::move(filteredLayerElements);
0057 }
0058 return inputs;
0059 }
0060
0061 if (!container.has_value()) {
0062 throw std::runtime_error("Container not set in ElementLayerAssembler");
0063 }
0064 if (!filter.has_value()) {
0065 throw std::runtime_error("Pattern not set in ElementLayerAssembler");
0066 }
0067
0068 inputs.layerElements =
0069 builder.findDetElementByNamePattern(container.value(), filter.value());
0070 return inputs;
0071 }
0072
0073
0074
0075
0076 template <detail::BlueprintBackend BackendT, typename CustomizerT>
0077 std::shared_ptr<Acts::Experimental::LayerBlueprintNode> finalizeLayer(
0078 const std::optional<typename BackendT::Element>& layerElement,
0079 std::shared_ptr<Acts::Experimental::LayerBlueprintNode> layer,
0080 const std::optional<Acts::ExtentEnvelope>& envelope,
0081 const CustomizerT& onLayer) {
0082 if (envelope.has_value()) {
0083 layer->setEnvelope(envelope.value());
0084 }
0085 if (onLayer) {
0086 layer = onLayer(layerElement, std::move(layer));
0087 }
0088 return layer;
0089 }
0090
0091 }
0092
0093
0094 template <detail::BlueprintBackend BackendT>
0095 ElementLayerAssembler<BackendT>::ElementLayerAssembler(const Builder& builder)
0096 : m_builder{&builder} {}
0097
0098 template <detail::BlueprintBackend BackendT>
0099 ElementLayerAssembler<BackendT>&& ElementLayerAssembler<BackendT>::setLayerType(
0100 LayerType layerType) && {
0101 m_layerType = layerType;
0102 return std::move(*this);
0103 }
0104
0105 template <detail::BlueprintBackend BackendT>
0106 ElementLayerAssembler<BackendT>&& ElementLayerAssembler<BackendT>::endcap() && {
0107 return std::move(*this).setLayerType(LayerType::Disc);
0108 }
0109
0110 template <detail::BlueprintBackend BackendT>
0111 ElementLayerAssembler<BackendT>&& ElementLayerAssembler<BackendT>::barrel() && {
0112 return std::move(*this).setLayerType(LayerType::Cylinder);
0113 }
0114
0115 template <detail::BlueprintBackend BackendT>
0116 ElementLayerAssembler<BackendT>&& ElementLayerAssembler<BackendT>::planar() && {
0117 return std::move(*this).setLayerType(LayerType::Plane);
0118 }
0119
0120 template <detail::BlueprintBackend BackendT>
0121 ElementLayerAssembler<BackendT>&&
0122 ElementLayerAssembler<BackendT>::setLayerFilter(const std::string& pattern) && {
0123 return std::move(*this).setLayerFilter(std::regex{pattern});
0124 }
0125
0126 template <detail::BlueprintBackend BackendT>
0127 ElementLayerAssembler<BackendT>&&
0128 ElementLayerAssembler<BackendT>::setLayerFilter(const std::regex& pattern) && {
0129 m_filter = pattern;
0130 return std::move(*this);
0131 }
0132
0133 template <detail::BlueprintBackend BackendT>
0134 ElementLayerAssembler<BackendT>&& ElementLayerAssembler<BackendT>::setContainer(
0135 const Element& container) && {
0136 m_container = container;
0137 return std::move(*this);
0138 }
0139
0140 template <detail::BlueprintBackend BackendT>
0141 ElementLayerAssembler<BackendT>&&
0142 ElementLayerAssembler<BackendT>::setContainerName(
0143 std::string containerName) && {
0144 m_containerName = std::move(containerName);
0145 return std::move(*this);
0146 }
0147
0148 template <detail::BlueprintBackend BackendT>
0149 ElementLayerAssembler<BackendT>&&
0150 ElementLayerAssembler<BackendT>::setLayerNameSuffix(
0151 const std::optional<std::string>& layerNameSuffix) && {
0152 m_layerSpec.layerName = layerNameSuffix;
0153 return std::move(*this);
0154 }
0155
0156 template <detail::BlueprintBackend BackendT>
0157 ElementLayerAssembler<BackendT>&&
0158 ElementLayerAssembler<BackendT>::setLayerElements(
0159 std::vector<Element> layerElements) && {
0160 m_layerElements = std::move(layerElements);
0161 return std::move(*this);
0162 }
0163
0164 template <detail::BlueprintBackend BackendT>
0165 ElementLayerAssembler<BackendT>&& ElementLayerAssembler<BackendT>::setContainer(
0166 const std::string& name) && {
0167 m_container = m_builder->findDetElementByName(name);
0168 if (!m_container.has_value()) {
0169 throw std::runtime_error("Could not find DetElement with name " + name +
0170 " in ElementLayerAssembler");
0171 }
0172 return std::move(*this);
0173 }
0174
0175 template <detail::BlueprintBackend BackendT>
0176 ElementLayerAssembler<BackendT>&& ElementLayerAssembler<BackendT>::setEnvelope(
0177 const Acts::ExtentEnvelope& envelope) && {
0178 m_envelope = envelope;
0179 return std::move(*this);
0180 }
0181
0182 template <detail::BlueprintBackend BackendT>
0183 ElementLayerAssembler<BackendT>&& ElementLayerAssembler<BackendT>::setEmptyOk(
0184 bool emptyOk) && {
0185 m_emptyOk = emptyOk;
0186 return std::move(*this);
0187 }
0188
0189 template <detail::BlueprintBackend BackendT>
0190 ElementLayerAssembler<BackendT>&&
0191 ElementLayerAssembler<BackendT>::setAttachmentStrategy(
0192 std::optional<Acts::VolumeAttachmentStrategy> strategy) && {
0193 m_attachmentStrategy = strategy;
0194 return std::move(*this);
0195 }
0196
0197 template <detail::BlueprintBackend BackendT>
0198 void ElementLayerAssembler<BackendT>::addTo(
0199 Acts::Experimental::BlueprintNode& node) const&& {
0200 node.addChild(build());
0201 }
0202
0203 template <detail::BlueprintBackend BackendT>
0204 std::shared_ptr<Acts::Experimental::ContainerBlueprintNode>
0205 ElementLayerAssembler<BackendT>::build() const {
0206 const auto& logger = m_builder->logger();
0207
0208 if (!m_layerType.has_value()) {
0209 throw std::runtime_error("Layer type not set in ElementLayerAssembler");
0210 }
0211
0212 if constexpr (detail::HasAxisDefinition<BackendT>) {
0213 if (!m_layerSpec.axes.has_value()) {
0214 throw std::runtime_error("Axes not set in ElementLayerAssembler");
0215 }
0216 }
0217
0218 if (!m_filter.has_value() && !m_layerElements.has_value()) {
0219 throw std::runtime_error(
0220 "Neither filter nor layer elements set in ElementLayerAssembler");
0221 }
0222
0223
0224 auto inputs = detail::resolveLayerBuildInputs<BackendT>(
0225 *m_builder, m_container, m_layerElements, m_filter);
0226
0227
0228 std::string containerName;
0229 if (m_containerName.has_value()) {
0230 containerName = m_containerName.value();
0231 } else if (inputs.deducedContainerName.has_value()) {
0232 containerName = inputs.deducedContainerName.value();
0233 } else {
0234 throw std::runtime_error(
0235 "Container name is not set in ElementLayerAssembler. Provide "
0236 "setContainerName() or setContainer().");
0237 }
0238
0239 if (inputs.layerElements.empty()) {
0240 ACTS_LOG(m_emptyOk ? Acts::Logging::INFO : Acts::Logging::ERROR,
0241 "No layers found in container " << containerName
0242 << " matching pattern");
0243 if (!m_emptyOk) {
0244 throw std::runtime_error(std::format(
0245 "No layers found in container {} matching pattern", containerName));
0246 }
0247 }
0248
0249 std::shared_ptr<Acts::Experimental::ContainerBlueprintNode> node;
0250 if (m_layerType != LayerType::Plane) {
0251 const Acts::AxisDirection axisDir = m_layerType == LayerType::Cylinder
0252 ? Acts::AxisDirection::AxisR
0253 : Acts::AxisDirection::AxisZ;
0254 node = std::make_shared<Acts::Experimental::CylinderContainerBlueprintNode>(
0255 containerName, axisDir);
0256 } else {
0257 node = std::make_shared<Acts::Experimental::CuboidContainerBlueprintNode>(
0258 containerName, Acts::AxisDirection::AxisZ);
0259 }
0260
0261 if (m_attachmentStrategy.has_value()) {
0262 node->setAttachmentStrategy(m_attachmentStrategy.value());
0263 }
0264
0265 for (const auto& layerElement : inputs.layerElements) {
0266 LayerSpec resolvedLayerSpec = m_layerSpec;
0267 std::string fullLayerName = m_builder->getPathToElementName(layerElement);
0268 if (resolvedLayerSpec.layerName.has_value() &&
0269 !resolvedLayerSpec.layerName->empty()) {
0270 fullLayerName += "|" + *resolvedLayerSpec.layerName;
0271 }
0272 resolvedLayerSpec.layerName = std::move(fullLayerName);
0273 auto layer = m_builder->makeLayer(layerElement, resolvedLayerSpec);
0274 layer->setLayerType(m_layerType.value());
0275 node->addChild(detail::finalizeLayer<BackendT>(
0276 std::optional<Element>{layerElement}, std::move(layer), m_envelope,
0277 m_onLayer));
0278 }
0279
0280 return node;
0281 }
0282
0283
0284 template <detail::BlueprintBackend BackendT>
0285 SensorLayerAssembler<BackendT>::SensorLayerAssembler(const Builder& builder)
0286 : m_builder{&builder} {}
0287
0288 template <detail::BlueprintBackend BackendT>
0289 SensorLayerAssembler<BackendT>&& SensorLayerAssembler<BackendT>::setLayerType(
0290 LayerType layerType) && {
0291 m_layerType = layerType;
0292 return std::move(*this);
0293 }
0294
0295 template <detail::BlueprintBackend BackendT>
0296 SensorLayerAssembler<BackendT>&& SensorLayerAssembler<BackendT>::endcap() && {
0297 return std::move(*this).setLayerType(LayerType::Disc);
0298 }
0299
0300 template <detail::BlueprintBackend BackendT>
0301 SensorLayerAssembler<BackendT>&& SensorLayerAssembler<BackendT>::barrel() && {
0302 return std::move(*this).setLayerType(LayerType::Cylinder);
0303 }
0304
0305 template <detail::BlueprintBackend BackendT>
0306 SensorLayerAssembler<BackendT>&& SensorLayerAssembler<BackendT>::planar() && {
0307 return std::move(*this).setLayerType(LayerType::Plane);
0308 }
0309
0310 template <detail::BlueprintBackend BackendT>
0311 SensorLayerAssembler<BackendT>&& SensorLayerAssembler<BackendT>::setSensors(
0312 std::vector<Element> sensors) && {
0313 m_sensors = std::move(sensors);
0314 return std::move(*this);
0315 }
0316
0317 template <detail::BlueprintBackend BackendT>
0318 SensorLayerAssembler<BackendT>&& SensorLayerAssembler<BackendT>::groupBy(
0319 typename SensorLayerAssembler<BackendT>::LayerGrouper grouper) && {
0320 m_groupBy = std::move(grouper);
0321 return std::move(*this);
0322 }
0323
0324 template <detail::BlueprintBackend BackendT>
0325 SensorLayerAssembler<BackendT>&&
0326 SensorLayerAssembler<BackendT>::setContainerName(std::string containerName) && {
0327 m_containerName = std::move(containerName);
0328 return std::move(*this);
0329 }
0330
0331 template <detail::BlueprintBackend BackendT>
0332 SensorLayerAssembler<BackendT>&& SensorLayerAssembler<BackendT>::setEnvelope(
0333 const Acts::ExtentEnvelope& envelope) && {
0334 m_envelope = envelope;
0335 return std::move(*this);
0336 }
0337
0338 template <detail::BlueprintBackend BackendT>
0339 SensorLayerAssembler<BackendT>&&
0340 SensorLayerAssembler<BackendT>::setAttachmentStrategy(
0341 std::optional<Acts::VolumeAttachmentStrategy> strategy) && {
0342 m_attachmentStrategy = strategy;
0343 return std::move(*this);
0344 }
0345
0346 template <detail::BlueprintBackend BackendT>
0347 void SensorLayerAssembler<BackendT>::addTo(
0348 Acts::Experimental::BlueprintNode& node) const&& {
0349 node.addChild(build());
0350 }
0351
0352 template <detail::BlueprintBackend BackendT>
0353 std::shared_ptr<Acts::Experimental::ContainerBlueprintNode>
0354 SensorLayerAssembler<BackendT>::build() const {
0355 using enum Acts::AxisDirection;
0356
0357 if (!m_layerType.has_value()) {
0358 throw std::runtime_error("Layer type not set in SensorLayerAssembler");
0359 }
0360
0361 if constexpr (detail::HasAxisDefinition<BackendT>) {
0362 if (!m_layerSpec.axes.has_value()) {
0363 throw std::runtime_error(
0364 std::format("Axes not set in SensorLayerAssembler (backend: {})",
0365 BackendT::kIdentifier));
0366 }
0367 }
0368
0369 if (!m_sensors.has_value()) {
0370 throw std::runtime_error("Sensors not set in SensorLayerAssembler");
0371 }
0372 if (!m_containerName.has_value()) {
0373 throw std::runtime_error(
0374 "Container name not set in SensorLayerAssembler. "
0375 "Call setContainerName().");
0376 }
0377 if (!m_groupBy) {
0378 throw std::runtime_error(
0379 "SensorLayerAssembler requires groupBy(). For a single layer without "
0380 "grouping, use BlueprintBuilder::layerFromSensors() instead.");
0381 }
0382
0383 std::shared_ptr<Acts::Experimental::ContainerBlueprintNode> node;
0384 if (m_layerType != LayerType::Plane) {
0385 const AxisDirection axisDir =
0386 m_layerType == LayerType::Cylinder ? AxisR : AxisZ;
0387 node = std::make_shared<Acts::Experimental::CylinderContainerBlueprintNode>(
0388 m_containerName.value(), axisDir);
0389 } else {
0390 node = std::make_shared<Acts::Experimental::CuboidContainerBlueprintNode>(
0391 m_containerName.value(), AxisZ);
0392 }
0393
0394 if (m_attachmentStrategy.has_value()) {
0395 node->setAttachmentStrategy(m_attachmentStrategy.value());
0396 }
0397
0398 struct GroupData {
0399 std::string key;
0400 std::vector<Element> sensors;
0401 };
0402
0403
0404 std::vector<GroupData> groups;
0405 for (const auto& sensor : *m_sensors) {
0406 const std::string key = m_groupBy(sensor);
0407 auto it = std::ranges::find_if(
0408 groups, [&](const GroupData& g) { return g.key == key; });
0409 if (it == groups.end()) {
0410 groups.push_back(GroupData{.key = key, .sensors = {}});
0411 it = std::prev(groups.end());
0412 }
0413 it->sensors.push_back(sensor);
0414 }
0415
0416 for (const auto& group : groups) {
0417 if (group.key.empty()) {
0418 throw std::runtime_error(
0419 "groupBy() key must be non-empty for all sensors in "
0420 "SensorLayerAssembler");
0421 }
0422 LayerSpec layerSpec = m_layerSpec;
0423 layerSpec.layerName = group.key;
0424 auto layer = m_builder->makeLayer(std::span<const Element>{group.sensors},
0425 layerSpec);
0426 layer->setLayerType(m_layerType.value());
0427 node->addChild(detail::finalizeLayer<BackendT>(
0428 std::nullopt, std::move(layer), m_envelope, m_onLayer));
0429 }
0430
0431 return node;
0432 }
0433
0434
0435 template <detail::BlueprintBackend BackendT>
0436 SensorLayer<BackendT>::SensorLayer(const Builder& builder)
0437 : m_builder{&builder} {}
0438
0439 template <detail::BlueprintBackend BackendT>
0440 SensorLayer<BackendT>&& SensorLayer<BackendT>::setLayerType(
0441 LayerType layerType) && {
0442 m_layerType = layerType;
0443 return std::move(*this);
0444 }
0445
0446 template <detail::BlueprintBackend BackendT>
0447 SensorLayer<BackendT>&& SensorLayer<BackendT>::endcap() && {
0448 return std::move(*this).setLayerType(LayerType::Disc);
0449 }
0450
0451 template <detail::BlueprintBackend BackendT>
0452 SensorLayer<BackendT>&& SensorLayer<BackendT>::barrel() && {
0453 return std::move(*this).setLayerType(LayerType::Cylinder);
0454 }
0455
0456 template <detail::BlueprintBackend BackendT>
0457 SensorLayer<BackendT>&& SensorLayer<BackendT>::planar() && {
0458 return std::move(*this).setLayerType(LayerType::Plane);
0459 }
0460
0461 template <detail::BlueprintBackend BackendT>
0462 SensorLayer<BackendT>&& SensorLayer<BackendT>::setSensors(
0463 std::vector<Element> sensors) && {
0464 m_sensors = std::move(sensors);
0465 return std::move(*this);
0466 }
0467
0468 template <detail::BlueprintBackend BackendT>
0469 SensorLayer<BackendT>&& SensorLayer<BackendT>::setLayerName(
0470 std::string name) && {
0471 m_layerName = std::move(name);
0472 return std::move(*this);
0473 }
0474
0475 template <detail::BlueprintBackend BackendT>
0476 SensorLayer<BackendT>&& SensorLayer<BackendT>::setEnvelope(
0477 const Acts::ExtentEnvelope& envelope) && {
0478 m_envelope = envelope;
0479 return std::move(*this);
0480 }
0481
0482 template <detail::BlueprintBackend BackendT>
0483 void SensorLayer<BackendT>::addTo(
0484 Acts::Experimental::BlueprintNode& node) const&& {
0485 node.addChild(build());
0486 }
0487
0488 template <detail::BlueprintBackend BackendT>
0489 std::shared_ptr<Acts::Experimental::LayerBlueprintNode>
0490 SensorLayer<BackendT>::build() const {
0491 if (!m_layerType.has_value()) {
0492 throw std::runtime_error("Layer type not set in SensorLayer");
0493 }
0494
0495 if constexpr (detail::HasAxisDefinition<BackendT>) {
0496 if (!m_layerSpec.axes.has_value()) {
0497 throw std::runtime_error("Axes not set in SensorLayer");
0498 }
0499 }
0500
0501 if (!m_sensors.has_value()) {
0502 throw std::runtime_error("Sensors not set in SensorLayer");
0503 }
0504 if (!m_layerName.has_value() || m_layerName->empty()) {
0505 throw std::runtime_error(
0506 "Layer name not set in SensorLayer. Call setLayerName().");
0507 }
0508
0509 LayerSpec layerSpec = m_layerSpec;
0510 layerSpec.layerName = m_layerName;
0511 auto layer =
0512 m_builder->makeLayer(std::span<const Element>{*m_sensors}, layerSpec);
0513 layer->setLayerType(m_layerType.value());
0514 return detail::finalizeLayer<BackendT>(std::nullopt, std::move(layer),
0515 m_envelope, m_onLayer);
0516 }
0517
0518
0519 template <detail::BlueprintBackend BackendT>
0520 BarrelEndcapAssembler<BackendT>::BarrelEndcapAssembler(const Builder& builder)
0521 : m_builder{&builder} {}
0522
0523 template <detail::BlueprintBackend BackendT>
0524 void BarrelEndcapAssembler<BackendT>::addTo(
0525 Acts::Experimental::BlueprintNode& node) const&&
0526 requires(detail::HasBarrelEndcapClassifier<BackendT>)
0527 {
0528 node.addChild(build());
0529 }
0530
0531 template <detail::BlueprintBackend BackendT>
0532 BarrelEndcapAssembler<BackendT>&& BarrelEndcapAssembler<BackendT>::setAssembly(
0533 const Element& assembly) && {
0534 m_assembly = assembly;
0535 return std::move(*this);
0536 }
0537
0538 template <detail::BlueprintBackend BackendT>
0539 BarrelEndcapAssembler<BackendT>&&
0540 BarrelEndcapAssembler<BackendT>::setSensorAxes(
0541 typename BarrelEndcapAssembler<BackendT>::AxisDefinition barrel,
0542 typename BarrelEndcapAssembler<BackendT>::AxisDefinition endcap) &&
0543 requires(detail::HasAxisDefinition<BackendT>)
0544 {
0545 m_barrelAxes = std::move(barrel);
0546 m_endcapAxes = std::move(endcap);
0547 return std::move(*this);
0548 }
0549
0550 template <detail::BlueprintBackend BackendT>
0551 BarrelEndcapAssembler<BackendT>&&
0552 BarrelEndcapAssembler<BackendT>::setEndcapAxes(
0553 typename BarrelEndcapAssembler<BackendT>::AxisDefinition axes) &&
0554 requires(detail::HasAxisDefinition<BackendT>)
0555 {
0556 m_endcapAxes = std::move(axes);
0557 return std::move(*this);
0558 }
0559
0560 template <detail::BlueprintBackend BackendT>
0561 BarrelEndcapAssembler<BackendT>&&
0562 BarrelEndcapAssembler<BackendT>::setLayerFilter(const std::regex& pattern) && {
0563 m_layerFilter = pattern;
0564 return std::move(*this);
0565 }
0566
0567 template <detail::BlueprintBackend BackendT>
0568 std::shared_ptr<Acts::Experimental::CylinderContainerBlueprintNode>
0569 BarrelEndcapAssembler<BackendT>::build() const
0570 requires(detail::HasBarrelEndcapClassifier<BackendT>)
0571 {
0572 using enum Acts::AxisDirection;
0573
0574 const auto& logger = m_builder->logger();
0575
0576 if (!m_assembly.has_value()) {
0577 throw std::runtime_error(
0578 "Assembly detector element not set in BarrelEndcapAssembler");
0579 }
0580
0581 if constexpr (detail::HasAxisDefinition<BackendT>) {
0582 if (!m_barrelAxes.has_value()) {
0583 throw std::runtime_error("Barrel axes not set in BarrelEndcapAssembler");
0584 }
0585
0586 if (!m_endcapAxes.has_value()) {
0587 throw std::runtime_error("Endcap axes not set in BarrelEndcapAssembler");
0588 }
0589 }
0590
0591 if (!m_layerFilter.has_value()) {
0592 throw std::runtime_error("Layer pattern not set in BarrelEndcapAssembler");
0593 }
0594
0595 const auto& assembly = m_assembly.value();
0596 const std::string assemblyName = m_builder->backend().nameOf(assembly);
0597
0598 ACTS_INFO("Converting barrel-endcap assembly from element: " << assemblyName);
0599 auto barrels = m_builder->findBarrelElements(assembly);
0600
0601 ACTS_DEBUG("Have " << barrels.size() << " barrel elements in assembly "
0602 << assemblyName);
0603 if (barrels.size() > 1) {
0604 ACTS_ERROR("Expected exactly zero or one barrel in assembly "
0605 << assemblyName << ", found " << barrels.size());
0606 throw std::runtime_error(std::format(
0607 "Expected exactly zero or one barrel in assembly {}", assemblyName));
0608 }
0609
0610 auto endcaps = m_builder->findEndcapElements(assembly);
0611
0612 ACTS_DEBUG("Have " << endcaps.size() << " endcap elements in assembly "
0613 << assemblyName);
0614
0615 auto node =
0616 std::make_shared<Acts::Experimental::CylinderContainerBlueprintNode>(
0617 assemblyName, Acts::AxisDirection::AxisZ);
0618
0619 auto maybeAddAxes = [](const auto& axes) {
0620 return [&axes]<typename T>(T&& assembler) {
0621 if constexpr (detail::HasAxisDefinition<BackendT>) {
0622 return std::forward<T>(assembler).setSensorAxes(axes.value());
0623 } else {
0624 return std::forward<T>(assembler);
0625 }
0626 };
0627 };
0628
0629 auto build = []<typename T>(T&& assembler) {
0630 return std::forward<T>(assembler).build();
0631 };
0632
0633 auto addTo =
0634 std::bind_front(&Acts::Experimental::BlueprintNode::addChild, node.get());
0635
0636 for (const auto& barrel : barrels) {
0637 auto compose = Acts::compose(addTo, std::bind_front(m_onContainer, barrel),
0638 build, maybeAddAxes(m_barrelAxes));
0639
0640 compose(m_builder->layers()
0641 .barrel()
0642 .setLayerFilter(m_layerFilter.value())
0643 .setContainer(barrel)
0644 .onLayer(m_onLayer));
0645 }
0646
0647 for (const auto& endcap : endcaps) {
0648 auto compose = Acts::compose(addTo, std::bind_front(m_onContainer, endcap),
0649 build, maybeAddAxes(m_endcapAxes));
0650
0651 compose(m_builder->layers()
0652 .endcap()
0653 .setLayerFilter(m_layerFilter.value())
0654 .setContainer(endcap)
0655 .onLayer(m_onLayer));
0656 }
0657
0658 return node;
0659 }
0660
0661
0662 template <detail::BlueprintBackend BackendT>
0663 BlueprintBuilder<BackendT>::BlueprintBuilder(
0664 const typename Backend::Config& cfg,
0665 std::unique_ptr<const Acts::Logger> logger_)
0666 : m_logger(logger_ ? std::move(logger_)
0667 : Acts::getDefaultLogger("BlueprintBuilder",
0668 Acts::Logging::INFO)),
0669 m_backend(cfg, *m_logger) {}
0670
0671 template <detail::BlueprintBackend BackendT>
0672 std::shared_ptr<Acts::Experimental::LayerBlueprintNode>
0673 BlueprintBuilder<BackendT>::makeLayer(const Element& layerElement,
0674 const LayerSpec& layerSpec) const {
0675 auto sensitives = resolveSensitives(layerElement);
0676 return makeLayer(layerElement, sensitives, layerSpec);
0677 }
0678
0679 template <detail::BlueprintBackend BackendT>
0680 typename BlueprintBuilder<BackendT>::ElementLayerAssembler
0681 BlueprintBuilder<BackendT>::layers() const {
0682 return ElementLayerAssembler(*this);
0683 }
0684
0685 template <detail::BlueprintBackend BackendT>
0686 typename BlueprintBuilder<BackendT>::SensorLayerAssembler
0687 BlueprintBuilder<BackendT>::layersFromSensors() const {
0688 return SensorLayerAssembler(*this);
0689 }
0690
0691 template <detail::BlueprintBackend BackendT>
0692 typename BlueprintBuilder<BackendT>::SensorLayer
0693 BlueprintBuilder<BackendT>::layerFromSensors() const {
0694 return SensorLayer(*this);
0695 }
0696
0697 template <detail::BlueprintBackend BackendT>
0698 typename BlueprintBuilder<BackendT>::BarrelEndcapAssembler
0699 BlueprintBuilder<BackendT>::barrelEndcap() const
0700 requires(detail::HasBarrelEndcapClassifier<BackendT>)
0701 {
0702 return BarrelEndcapAssembler(*this);
0703 }
0704
0705 template <detail::BlueprintBackend BackendT>
0706 const Acts::Logger& BlueprintBuilder<BackendT>::logger() const {
0707 return *m_logger;
0708 }
0709
0710 template <detail::BlueprintBackend BackendT>
0711 const typename BlueprintBuilder<BackendT>::Backend&
0712 BlueprintBuilder<BackendT>::backend() const {
0713 return m_backend;
0714 }
0715
0716 template <detail::BlueprintBackend BackendT>
0717 std::optional<typename BlueprintBuilder<BackendT>::Element>
0718 BlueprintBuilder<BackendT>::findDetElementByName(
0719 const Element& parent, const std::string& name) const {
0720 if (m_backend.nameOf(parent) == name) {
0721 return parent;
0722 }
0723
0724 for (const auto& child : m_backend.children(parent)) {
0725 auto result = findDetElementByName(child, name);
0726 if (result.has_value()) {
0727 return result;
0728 }
0729 }
0730
0731 return std::nullopt;
0732 }
0733
0734 template <detail::BlueprintBackend BackendT>
0735 std::optional<typename BlueprintBuilder<BackendT>::Element>
0736 BlueprintBuilder<BackendT>::findDetElementByName(
0737 const std::string& name) const {
0738 return findDetElementByName(m_backend.world(), name);
0739 }
0740
0741 template <detail::BlueprintBackend BackendT>
0742 std::string BlueprintBuilder<BackendT>::getPathToElementName(
0743 const Element& elem, std::string_view separator) const {
0744 std::vector<std::string> names;
0745 names.emplace_back(m_backend.nameOf(elem));
0746
0747 const auto world = m_backend.world();
0748 auto current = elem;
0749 while (current != world) {
0750 current = m_backend.parent(current);
0751 if (current == world) {
0752 break;
0753 }
0754 names.emplace_back(m_backend.nameOf(current));
0755 }
0756
0757 std::ranges::reverse(names);
0758 std::string path;
0759 for (std::size_t i = 0; i < names.size(); ++i) {
0760 if (i > 0) {
0761 path += separator;
0762 }
0763 path += names[i];
0764 }
0765 return path;
0766 }
0767
0768 template <detail::BlueprintBackend BackendT>
0769 std::vector<typename BlueprintBuilder<BackendT>::Element>
0770 BlueprintBuilder<BackendT>::findDetElementByNamePattern(
0771 const Element& parent, const std::regex& pattern) const {
0772 std::vector<Element> matches;
0773
0774 std::function<void(const Element&)> visit = [&](const Element& elem) {
0775 if (const std::string elemName = m_backend.nameOf(elem);
0776 std::regex_match(elemName, pattern)) {
0777 matches.push_back(elem);
0778 }
0779 for (const auto& child : m_backend.children(elem)) {
0780 visit(child);
0781 }
0782 };
0783 visit(parent);
0784
0785 return matches;
0786 }
0787
0788 template <detail::BlueprintBackend BackendT>
0789 std::vector<typename BlueprintBuilder<BackendT>::Element>
0790 BlueprintBuilder<BackendT>::findBarrelElements(const Element& assembly) const
0791 requires(detail::HasBarrelEndcapClassifier<BackendT>)
0792 {
0793 std::vector<Element> barrels;
0794
0795 std::function<void(const Element&)> visit = [&](const Element& elem) {
0796 if (m_backend.isTracker(elem) && m_backend.isBarrel(elem)) {
0797 barrels.push_back(elem);
0798 }
0799 for (const auto& child : m_backend.children(elem)) {
0800 visit(child);
0801 }
0802 };
0803 visit(assembly);
0804 return barrels;
0805 }
0806
0807 template <detail::BlueprintBackend BackendT>
0808 std::vector<typename BlueprintBuilder<BackendT>::Element>
0809 BlueprintBuilder<BackendT>::findEndcapElements(const Element& assembly) const
0810 requires(detail::HasBarrelEndcapClassifier<BackendT>)
0811 {
0812 std::vector<Element> endcaps;
0813
0814 std::function<void(const Element&)> visit = [&](const Element& elem) {
0815 if (m_backend.isTracker(elem) && m_backend.isEndcap(elem)) {
0816 endcaps.push_back(elem);
0817 }
0818 for (const auto& child : m_backend.children(elem)) {
0819 visit(child);
0820 }
0821 };
0822 visit(assembly);
0823 return endcaps;
0824 }
0825
0826 template <detail::BlueprintBackend BackendT>
0827 std::shared_ptr<Acts::Experimental::LayerBlueprintNode>
0828 BlueprintBuilder<BackendT>::makeLayer(const Element& parent,
0829 std::span<const Element> sensitives,
0830 const LayerSpec& layerSpec) const {
0831 const std::string nodeName =
0832 layerSpec.layerName.value_or(m_backend.nameOf(parent));
0833 auto node =
0834 std::make_shared<Acts::Experimental::LayerBlueprintNode>(nodeName);
0835 node->setSurfaces(m_backend.makeSurfaces(sensitives, layerSpec));
0836
0837 if constexpr (detail::HasLayerTransformLookup<BackendT>) {
0838 if (const auto transform =
0839 m_backend.lookupLayerTransform(parent, layerSpec);
0840 transform.has_value()) {
0841 node->setTransform(transform.value());
0842 }
0843 }
0844
0845 return node;
0846 }
0847
0848 template <detail::BlueprintBackend BackendT>
0849 std::shared_ptr<Acts::Experimental::LayerBlueprintNode>
0850 BlueprintBuilder<BackendT>::makeLayer(std::span<const Element> sensitives,
0851 const LayerSpec& layerSpec) const {
0852 if (!layerSpec.layerName.has_value() || layerSpec.layerName->empty()) {
0853 throw std::runtime_error(
0854 "BlueprintBuilder::makeLayer(sensitives, layerSpec): "
0855 "layerSpec.layerName must be set");
0856 }
0857
0858 auto node = std::make_shared<Acts::Experimental::LayerBlueprintNode>(
0859 layerSpec.layerName.value());
0860 node->setSurfaces(m_backend.makeSurfaces(sensitives, layerSpec));
0861 return node;
0862 }
0863
0864 template <detail::BlueprintBackend BackendT>
0865 std::vector<typename BlueprintBuilder<BackendT>::Element>
0866 BlueprintBuilder<BackendT>::resolveSensitives(const Element& detElement) const {
0867 std::vector<Element> sensitives;
0868
0869 std::function<void(const Element&)> visit = [&](const Element& elem) {
0870 if (m_backend.isSensitive(elem)) {
0871 sensitives.push_back(elem);
0872 }
0873 for (const auto& child : m_backend.children(elem)) {
0874 visit(child);
0875 }
0876 };
0877 visit(detElement);
0878 return sensitives;
0879 }
0880
0881 }