File indexing completed on 2026-04-17 07:47:15
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "ActsPlugins/DD4hep/BlueprintBuilder.hpp"
0010
0011 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/Geometry/TrackingVolume.hpp"
0013
0014 #include "Acts/Geometry/detail/BlueprintBuilder_impl.hpp"
0015 #include "Acts/Surfaces/CylinderBounds.hpp"
0016 #include "Acts/Surfaces/Surface.hpp"
0017 #include "ActsPlugins/DD4hep/DD4hepDetectorElement.hpp"
0018 #include "ActsPlugins/Root/TGeoSurfaceConverter.hpp"
0019
0020 #include <functional>
0021 #include <optional>
0022 #include <stdexcept>
0023 #include <string>
0024 #include <vector>
0025
0026 #include <DD4hep/DetElement.h>
0027 #include <DD4hep/DetType.h>
0028 #include <DD4hep/Detector.h>
0029 #include <DDRec/DetectorData.h>
0030
0031 namespace ActsPlugins::DD4hep {
0032
0033 using ActsPlugins::TGeoAxes;
0034
0035 DD4hepBackend::DetectorElementPtr DD4hepBackend::defaultElementFactory(
0036 const Element& detElement, AxisDefinition axes, double lengthScale) {
0037 return std::make_shared<DD4hepDetectorElement>(detElement, axes, lengthScale);
0038 }
0039
0040 DD4hepBackend::DD4hepBackend(const Config& cfg, const Acts::Logger& logger)
0041 : m_cfg(cfg), m_logger(&logger) {
0042 if (m_cfg.dd4hepDetector == nullptr) {
0043 throw std::invalid_argument("DD4hepBackend: dd4hepDetector is null");
0044 }
0045 }
0046
0047 DD4hepBackend::DetectorElementPtr DD4hepBackend::createDetectorElement(
0048 const Element& detElement, AxisDefinition axes) const {
0049 auto elem = m_cfg.elementFactory(detElement, axes, m_cfg.lengthScale);
0050
0051 detElement.addExtension<DD4hepDetectorElementExtension>(
0052 new dd4hep::rec::StructExtension(DD4hepDetectorElementExtension(elem)));
0053
0054 return elem;
0055 }
0056
0057 namespace {
0058 void visitSubtree(
0059 const dd4hep::DetElement& detElement,
0060 const std::function<void(const dd4hep::DetElement&)>& visitor) {
0061 visitor(detElement);
0062
0063 for (const auto& [name, child] : detElement.children()) {
0064 (void)name;
0065 visitSubtree(child, visitor);
0066 }
0067 }
0068 }
0069
0070 DD4hepBackend::Element DD4hepBackend::world() const {
0071 return m_cfg.dd4hepDetector->world();
0072 }
0073
0074 std::string DD4hepBackend::nameOf(const Element& element) const {
0075 return element.name();
0076 }
0077
0078 std::vector<DD4hepBackend::Element> DD4hepBackend::children(
0079 const Element& parent) const {
0080 std::vector<Element> result;
0081 result.reserve(parent.children().size());
0082 for (const auto& [name, child] : parent.children()) {
0083 (void)name;
0084 result.push_back(child);
0085 }
0086 return result;
0087 }
0088
0089 DD4hepBackend::Element DD4hepBackend::parent(const Element& element) const {
0090 return element.parent();
0091 }
0092
0093 bool DD4hepBackend::isSensitive(const Element& element) const {
0094 return element.volume().isSensitive();
0095 }
0096
0097 bool DD4hepBackend::isBarrel(const Element& element) const {
0098 return dd4hep::DetType{element.typeFlag()}.is(dd4hep::DetType::BARREL);
0099 }
0100
0101 bool DD4hepBackend::isEndcap(const Element& element) const {
0102 return dd4hep::DetType{element.typeFlag()}.is(dd4hep::DetType::ENDCAP);
0103 }
0104
0105 bool DD4hepBackend::isTracker(const Element& element) const {
0106 return dd4hep::DetType{element.typeFlag()}.is(dd4hep::DetType::TRACKER);
0107 }
0108
0109 std::vector<std::shared_ptr<Acts::Surface>> DD4hepBackend::makeSurfaces(
0110 std::span<const dd4hep::DetElement> sensitives,
0111 const LayerSpec& layerSpec) const {
0112 if (!layerSpec.axes.has_value()) {
0113 throw std::runtime_error("DD4hepBackend::makeSurfaces: axes not set");
0114 }
0115
0116 ACTS_DEBUG("Using " << sensitives.size() << " sensitive elements.");
0117
0118 std::vector<std::shared_ptr<Acts::Surface>> surfaces;
0119 surfaces.reserve(sensitives.size());
0120
0121 for (const auto& sensitive : sensitives) {
0122 auto elem = createDetectorElement(sensitive, layerSpec.axes.value());
0123 surfaces.push_back(elem->surface().getSharedPtr());
0124 }
0125
0126 return surfaces;
0127 }
0128
0129 std::optional<Acts::Transform3> DD4hepBackend::lookupLayerTransform(
0130 const dd4hep::DetElement& element, const LayerSpec& layerSpec) const {
0131 if (layerSpec.layerAxes.has_value()) {
0132 ACTS_DEBUG("Finding layer transform automatically using layer axes: "
0133 << layerSpec.layerAxes.value());
0134 Acts::Transform3 layerTransform = TGeoSurfaceConverter::transformFromShape(
0135 *element.placement().ptr()->GetVolume()->GetShape(),
0136 element.nominal().worldTransformation(), layerSpec.layerAxes.value(),
0137 m_cfg.lengthScale);
0138
0139 ACTS_VERBOSE(" -> Layer transform:\n" << layerTransform.matrix());
0140 return layerTransform;
0141 }
0142
0143 return std::nullopt;
0144 }
0145
0146 std::shared_ptr<Acts::Experimental::StaticBlueprintNode>
0147 DD4hepBackend::makeBeampipe() const {
0148 std::optional<dd4hep::DetElement> beampipeElement = std::nullopt;
0149
0150 visitSubtree(world(), [this,
0151 &beampipeElement](const dd4hep::DetElement& elem) {
0152 if (!dd4hep::DetType{elem.typeFlag()}.is(dd4hep::DetType::BEAMPIPE)) {
0153 return;
0154 }
0155 if (beampipeElement.has_value()) {
0156 ACTS_WARNING("Multiple beampipe elements found, using first: "
0157 << beampipeElement->name() << ", ignoring: " << elem.name());
0158 return;
0159 }
0160 beampipeElement = elem;
0161 });
0162
0163 if (!beampipeElement.has_value()) {
0164 ACTS_ERROR("No beampipe element found in DD4hep detector.");
0165 throw std::runtime_error("No beampipe element found in DD4hep detector.");
0166 }
0167
0168 ACTS_INFO("Beampipe element found: " << beampipeElement->name());
0169
0170 const auto tgTransform = beampipeElement->nominal().worldTransformation();
0171 auto [bounds, transform, thickness] =
0172 ActsPlugins::TGeoSurfaceConverter::cylinderComponents(
0173 *beampipeElement->placement().ptr()->GetVolume()->GetShape(),
0174 tgTransform.GetRotationMatrix(), tgTransform.GetTranslation(), "XYZ",
0175 m_cfg.lengthScale);
0176 (void)thickness;
0177
0178 if (bounds == nullptr) {
0179 ACTS_ERROR("Beampipe element shape could not be converted to cylinder.");
0180 throw std::runtime_error(
0181 "Beampipe element shape could not be converted to cylinder.");
0182 }
0183
0184 auto volumeBounds = std::make_shared<Acts::CylinderVolumeBounds>(
0185 0, bounds->get(Acts::CylinderBounds::eR),
0186 bounds->get(Acts::CylinderBounds::eHalfLengthZ));
0187 auto volume = std::make_unique<Acts::TrackingVolume>(transform, volumeBounds,
0188 beampipeElement->name());
0189 return std::make_shared<Acts::Experimental::StaticBlueprintNode>(
0190 std::move(volume));
0191 }
0192
0193 }
0194
0195
0196
0197
0198 namespace Acts::Experimental {
0199 template class BlueprintBuilder<ActsPlugins::DD4hep::DD4hepBackend>;
0200 template class ElementLayerAssembler<ActsPlugins::DD4hep::DD4hepBackend>;
0201 template class SensorLayerAssembler<ActsPlugins::DD4hep::DD4hepBackend>;
0202 template class SensorLayer<ActsPlugins::DD4hep::DD4hepBackend>;
0203 template class BarrelEndcapAssembler<ActsPlugins::DD4hep::DD4hepBackend>;
0204 }