File indexing completed on 2026-05-08 08:00:33
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "ActsPlugins/Root/BlueprintBuilder.hpp"
0010
0011 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/Geometry/detail/BlueprintBuilder_impl.hpp"
0013 #include "Acts/Surfaces/Surface.hpp"
0014 #include "ActsPlugins/Root/TGeoSurfaceConverter.hpp"
0015
0016 #include <cstddef>
0017 #include <functional>
0018 #include <iterator>
0019 #include <optional>
0020 #include <stdexcept>
0021 #include <string>
0022 #include <utility>
0023 #include <vector>
0024
0025 #include "TGeoNode.h"
0026 #include "TGeoShape.h"
0027 #include "TGeoVolume.h"
0028
0029 namespace ActsPlugins {
0030
0031 TGeoBlueprintBuilderBackend::DetectorElementPtr
0032 TGeoBlueprintBuilderBackend::defaultElementFactory(
0033 const TGeoDetectorElement::Identifier& identifier, const TGeoNode& tGeoNode,
0034 const TGeoMatrix& tGeoMatrix, AxisDefinition axes, double lengthScale,
0035 std::shared_ptr<const Acts::ISurfaceMaterial> material) {
0036 return std::make_shared<TGeoDetectorElement>(
0037 identifier, tGeoNode, tGeoMatrix, axes, lengthScale, std::move(material));
0038 }
0039
0040 TGeoBlueprintBuilderBackend::TGeoBlueprintBuilderBackend(
0041 const Config& cfg, const Acts::Logger& logger)
0042 : m_cfg(cfg), m_logger(&logger) {
0043 if (m_cfg.root == nullptr) {
0044 throw std::invalid_argument(
0045 "TGeoBlueprintBuilderBackend: root node is null");
0046 }
0047 m_world = makeElement(*m_cfg.root, nullptr);
0048 }
0049
0050 auto TGeoBlueprintBuilderBackend::makeElement(
0051 const TGeoNode& node, std::shared_ptr<const NodeContext> parent) const
0052 -> Element {
0053 return Element{std::make_shared<NodeContext>(
0054 NodeContext{.node = &node, .parent = std::move(parent)})};
0055 }
0056
0057 const TGeoBlueprintBuilderBackend::NodeContext&
0058 TGeoBlueprintBuilderBackend::contextOf(const Element& element) const {
0059 if (element.context == nullptr) {
0060 throw std::invalid_argument(
0061 "TGeoBlueprintBuilderBackend: invalid element handle");
0062 }
0063 return *element.context;
0064 }
0065
0066 TGeoDetectorElement::Identifier
0067 TGeoBlueprintBuilderBackend::defaultIdentifierFor(
0068 const Element& element) const {
0069 const auto path = pathOf(element);
0070 return static_cast<TGeoDetectorElement::Identifier>(
0071 std::hash<std::string>{}(path));
0072 }
0073
0074 TGeoBlueprintBuilderBackend::DetectorElementPtr
0075 TGeoBlueprintBuilderBackend::createDetectorElement(const Element& element,
0076 AxisDefinition axes) const {
0077 const auto& context = contextOf(element);
0078 const auto identifier = m_cfg.identifierProvider != nullptr
0079 ? m_cfg.identifierProvider(element)
0080 : defaultIdentifierFor(element);
0081 const auto transform = transformOf(element);
0082
0083 auto detectorElement = m_cfg.elementFactory(
0084 identifier, *context.node, transform, axes, m_cfg.lengthScale, nullptr);
0085 m_detectorElementStore.push_back(detectorElement);
0086 return detectorElement;
0087 }
0088
0089 std::vector<std::shared_ptr<Acts::Surface>>
0090 TGeoBlueprintBuilderBackend::makeSurfaces(std::span<const Element> sensitives,
0091 const LayerSpec& layerSpec) const {
0092 if (!layerSpec.axes.has_value()) {
0093 throw std::runtime_error(
0094 "TGeoBlueprintBuilderBackend::makeSurfaces: axes not set");
0095 }
0096
0097 std::vector<std::shared_ptr<Acts::Surface>> surfaces;
0098 surfaces.reserve(sensitives.size());
0099
0100 for (const auto& sensitive : sensitives) {
0101 auto detectorElement =
0102 createDetectorElement(sensitive, layerSpec.axes.value());
0103 surfaces.push_back(detectorElement->surface().getSharedPtr());
0104 }
0105
0106 return surfaces;
0107 }
0108
0109 std::optional<Acts::Transform3>
0110 TGeoBlueprintBuilderBackend::lookupLayerTransform(
0111 const Element& element, const LayerSpec& layerSpec) const {
0112 if (!layerSpec.layerAxes.has_value()) {
0113 return std::nullopt;
0114 }
0115
0116 const auto& context = contextOf(element);
0117 return TGeoSurfaceConverter::transformFromShape(
0118 *context.node->GetVolume()->GetShape(), transformOf(element),
0119 layerSpec.layerAxes.value(), m_cfg.lengthScale);
0120 }
0121
0122 TGeoBlueprintBuilderBackend::Element TGeoBlueprintBuilderBackend::world()
0123 const {
0124 return m_world;
0125 }
0126
0127 std::string TGeoBlueprintBuilderBackend::nameOf(const Element& element) const {
0128 const auto& context = contextOf(element);
0129 if (const auto* volume = context.node->GetVolume();
0130 volume != nullptr && volume->GetName() != nullptr) {
0131 return volume->GetName();
0132 }
0133 if (context.node->GetName() != nullptr) {
0134 return context.node->GetName();
0135 }
0136 return {};
0137 }
0138
0139 std::vector<TGeoBlueprintBuilderBackend::Element>
0140 TGeoBlueprintBuilderBackend::children(const Element& parent) const {
0141 const auto& context = contextOf(parent);
0142 std::vector<Element> result;
0143 result.reserve(context.node->GetNdaughters());
0144 for (int i = 0; i < context.node->GetNdaughters(); ++i) {
0145 const TGeoNode* child = context.node->GetDaughter(i);
0146 if (child == nullptr) {
0147 continue;
0148 }
0149 result.push_back(makeElement(*child, parent.context));
0150 }
0151 return result;
0152 }
0153
0154 TGeoBlueprintBuilderBackend::Element TGeoBlueprintBuilderBackend::parent(
0155 const Element& element) const {
0156 return Element{contextOf(element).parent};
0157 }
0158
0159 bool TGeoBlueprintBuilderBackend::isSensitive(const Element& element) const {
0160 return m_cfg.sensitivePredicate != nullptr &&
0161 m_cfg.sensitivePredicate(element);
0162 }
0163
0164 const TGeoNode& TGeoBlueprintBuilderBackend::nodeOf(
0165 const Element& element) const {
0166 return *contextOf(element).node;
0167 }
0168
0169 TGeoHMatrix TGeoBlueprintBuilderBackend::transformOf(
0170 const Element& element) const {
0171 std::vector<const NodeContext*> chain;
0172 for (const NodeContext* current = element.context.get(); current != nullptr;
0173 current = current->parent.get()) {
0174 chain.push_back(current);
0175 }
0176
0177 std::optional<TGeoHMatrix> transform = std::nullopt;
0178 for (auto it = chain.rbegin(); it != chain.rend(); ++it) {
0179 const TGeoMatrix* localMatrix = (*it)->node->GetMatrix();
0180 if (localMatrix == nullptr) {
0181 continue;
0182 }
0183 if (!transform.has_value()) {
0184 transform.emplace(*localMatrix);
0185 continue;
0186 }
0187 transform = TGeoCombiTrans(*transform) * TGeoCombiTrans(*localMatrix);
0188 }
0189 return transform.value_or(TGeoHMatrix{});
0190 }
0191
0192 std::string TGeoBlueprintBuilderBackend::pathOf(const Element& element) const {
0193 std::vector<std::string> names;
0194 for (const NodeContext* current = element.context.get(); current != nullptr;
0195 current = current->parent.get()) {
0196 if (current->node->GetName() != nullptr) {
0197 names.emplace_back(current->node->GetName());
0198 } else {
0199 names.emplace_back(current->node->GetVolume()->GetName());
0200 }
0201 }
0202
0203 if (names.empty()) {
0204 return {};
0205 }
0206
0207 std::string path = names.back();
0208 for (auto it = std::next(names.rbegin()); it != names.rend(); ++it) {
0209 path += "|";
0210 path += *it;
0211 }
0212 return path;
0213 }
0214
0215 }
0216
0217 namespace Acts::Experimental {
0218 template class BlueprintBuilder<ActsPlugins::TGeoBlueprintBuilderBackend>;
0219 template class ElementLayerAssembler<ActsPlugins::TGeoBlueprintBuilderBackend>;
0220 template class SensorLayerAssembler<ActsPlugins::TGeoBlueprintBuilderBackend>;
0221 template class SensorLayer<ActsPlugins::TGeoBlueprintBuilderBackend>;
0222 }