File indexing completed on 2026-08-28 08:28:13
0001
0002
0003
0004 #if Acts_VERSION_MAJOR < 45
0005 #include <Acts/Geometry/DetectorElementBase.hpp>
0006 #endif
0007 #include <Acts/Geometry/GeometryIdentifier.hpp>
0008 #include <Acts/Geometry/TrackingGeometry.hpp>
0009 #include <Acts/Geometry/TrackingVolume.hpp>
0010 #include <Acts/MagneticField/MagneticFieldContext.hpp>
0011 #include <Acts/Material/IMaterialDecorator.hpp>
0012 #if Acts_VERSION_MAJOR >= 45
0013 #include <Acts/Surfaces/SurfacePlacementBase.hpp>
0014 #endif
0015 #include <Acts/Utilities/Logger.hpp>
0016 #include <boost/container/detail/std_fwd.hpp>
0017 #include <fmt/format.h>
0018 #include <ActsPlugins/DD4hep/ConvertDD4hepDetector.hpp>
0019 #include <ActsPlugins/DD4hep/DD4hepDetectorElement.hpp>
0020 #include <ActsPlugins/DD4hep/DD4hepFieldAdapter.hpp>
0021 #include <ActsPlugins/Json/JsonMaterialDecorator.hpp>
0022 #include <ActsPlugins/Json/MaterialMapJsonConverter.hpp>
0023 #include <Acts/Surfaces/Surface.hpp>
0024 #include <Acts/Utilities/BinningType.hpp>
0025 #include <Acts/Utilities/Result.hpp>
0026 #include <Acts/Visualization/GeometryView3D.hpp>
0027 #include <Acts/Visualization/ObjVisualization3D.hpp>
0028 #include <Acts/Visualization/PlyVisualization3D.hpp>
0029 #include <DD4hep/DetElement.h>
0030 #include <DD4hep/VolumeManager.h>
0031 #include <TGeoManager.h>
0032 #include <fmt/ostream.h>
0033 #include <spdlog/common.h>
0034
0035 #include <Eigen/Core>
0036 #include <exception>
0037 #include <filesystem>
0038 #include <functional>
0039 #include <initializer_list>
0040 #include <set>
0041 #include <type_traits>
0042 #include <utility>
0043
0044 #include "ActsGeometryProvider.h"
0045 #include "extensions/spdlog/SpdlogToActs.h"
0046
0047 template <typename T>
0048 struct fmt::formatter<T, std::enable_if_t<std::is_base_of_v<Eigen::MatrixBase<T>, T>, char>>
0049 : fmt::ostream_formatter {};
0050
0051
0052
0053
0054
0055
0056
0057
0058 class EpicJsonMaterialDecorator : public Acts::IMaterialDecorator {
0059 public:
0060
0061 using LayerKey = std::pair<Acts::GeometryIdentifier::Value, Acts::GeometryIdentifier::Value>;
0062
0063 EpicJsonMaterialDecorator(const Acts::MaterialMapJsonConverter::Config& rConfig,
0064 const std::string& jFileName, Acts::Logging::Level level,
0065 std::shared_ptr<spdlog::logger> logger)
0066 : m_inner(rConfig, jFileName, level), m_log(std::move(logger)) {}
0067
0068 void decorate(Acts::Surface& surface) const override {
0069 m_inner.decorate(surface);
0070 const auto id = surface.geometryId();
0071 m_log->trace("{} assigned to surface with geometryId=(volume={}, boundary={}, layer={}, "
0072 "approach={}, sensitive={}, extra={})",
0073 (surface.surfaceMaterial() != nullptr) ? "Material" : "No material", id.volume(),
0074 id.boundary(), id.layer(), id.approach(), id.sensitive(), id.extra());
0075
0076 if (id.approach() == 0) {
0077 return;
0078 }
0079 LayerKey key{id.volume(), id.layer()};
0080
0081 m_decoratedLayers.insert(key);
0082
0083 if (surface.surfaceMaterial() != nullptr) {
0084 m_layersWithMaterial.insert(key);
0085 }
0086 }
0087
0088 void decorate(Acts::TrackingVolume& volume) const override { m_inner.decorate(volume); }
0089
0090
0091 void check() const {
0092 for (const auto& key : m_decoratedLayers) {
0093 if (m_layersWithMaterial.find(key) == m_layersWithMaterial.end()) {
0094 m_log->critical(
0095 "No material assigned to any approach surface in layer (volume={}, layer={})",
0096 key.first, key.second);
0097 }
0098 }
0099 }
0100
0101 private:
0102 Acts::JsonMaterialDecorator m_inner;
0103 std::shared_ptr<spdlog::logger> m_log;
0104
0105 mutable std::set<LayerKey> m_decoratedLayers;
0106
0107 mutable std::set<LayerKey> m_layersWithMaterial;
0108 };
0109
0110 void ActsGeometryProvider::initialize(const dd4hep::Detector* dd4hep_geo, std::string material_file,
0111 std::shared_ptr<spdlog::logger> log,
0112 std::shared_ptr<spdlog::logger> init_log) {
0113
0114 m_log = log;
0115 m_init_log = init_log;
0116
0117 m_init_log->debug("ActsGeometryProvider initializing...");
0118
0119 m_init_log->debug("Set TGeoManager and acts_init_log_level log levels");
0120
0121 if (m_log->level() >= (int)spdlog::level::info) {
0122 TGeoManager::SetVerboseLevel(0);
0123 }
0124
0125
0126 auto acts_init_log_level = eicrecon::SpdlogToActsLevel(m_init_log->level());
0127
0128 m_dd4hepDetector = dd4hep_geo;
0129
0130
0131 std::shared_ptr<const Acts::IMaterialDecorator> materialDeco{nullptr};
0132 if (!material_file.empty()) {
0133 m_init_log->info("loading materials map from file: '{}'", material_file);
0134
0135 Acts::MaterialMapJsonConverter::Config jsonGeoConvConfig;
0136
0137 materialDeco = std::make_shared<const EpicJsonMaterialDecorator>(
0138 jsonGeoConvConfig, material_file, acts_init_log_level, m_init_log);
0139 }
0140
0141
0142 class ConvertDD4hepDetectorGeometryIdentifierHook : public Acts::GeometryIdentifierHook {
0143 Acts::GeometryIdentifier decorateIdentifier(Acts::GeometryIdentifier identifier,
0144 const Acts::Surface& surface) const override {
0145 #if Acts_VERSION_MAJOR >= 45
0146 const auto* placement = surface.surfacePlacement();
0147 const auto* dd4hep_det_element =
0148 dynamic_cast<const ActsPlugins::DD4hepDetectorElement*>(placement);
0149 #else
0150 const auto* dd4hep_det_element = dynamic_cast<const ActsPlugins::DD4hepDetectorElement*>(
0151 surface.associatedDetectorElement());
0152 #endif
0153 if (dd4hep_det_element == nullptr) {
0154 return identifier;
0155 }
0156
0157 return identifier.withExtra(0xff & dd4hep_det_element->identifier());
0158 };
0159 };
0160 auto geometryIdHook = std::make_shared<ConvertDD4hepDetectorGeometryIdentifierHook>();
0161
0162
0163 m_init_log->info("Converting DD4Hep geometry to ACTS...");
0164 auto logger = eicrecon::getSpdlogLogger("CONV", m_log);
0165 Acts::BinningType bTypePhi = Acts::equidistant;
0166 Acts::BinningType bTypeR = Acts::equidistant;
0167 Acts::BinningType bTypeZ = Acts::equidistant;
0168 double layerEnvelopeR = Acts::UnitConstants::mm;
0169 double layerEnvelopeZ = Acts::UnitConstants::mm;
0170 double defaultLayerThickness = Acts::UnitConstants::fm;
0171
0172 try {
0173 m_trackingGeo = ActsPlugins::convertDD4hepDetector(
0174 m_dd4hepDetector->world(), *logger, bTypePhi, bTypeR, bTypeZ, layerEnvelopeR,
0175 layerEnvelopeZ, defaultLayerThickness, ActsPlugins::sortDetElementsByID, m_trackingGeoCtx,
0176 materialDeco, geometryIdHook);
0177 } catch (const std::exception& ex) {
0178 m_init_log->error("Error during DD4Hep -> ACTS geometry conversion: {}", ex.what());
0179 m_init_log->info("Set parameter acts:LogLevel=trace to see conversion info and possibly "
0180 "identify failing geometry");
0181 throw;
0182 }
0183
0184 m_init_log->info("DD4Hep geometry converted!");
0185
0186
0187 if (auto epicDeco = std::dynamic_pointer_cast<const EpicJsonMaterialDecorator>(materialDeco)) {
0188 epicDeco->check();
0189 }
0190
0191
0192 m_init_log->info("Checking surfaces...");
0193 if (m_trackingGeo) {
0194
0195 const Acts::TrackingVolume* world = m_trackingGeo->highestTrackingVolume();
0196 if (m_objWriteIt) {
0197 m_init_log->info("Writing obj files to {}...", m_outputDir);
0198 Acts::ObjVisualization3D objVis;
0199 Acts::GeometryView3D::drawTrackingVolume(objVis, *world, m_trackingGeoCtx, m_containerView,
0200 m_volumeView, m_passiveView, m_sensitiveView,
0201 m_gridView, m_objWriteIt, m_outputTag, m_outputDir);
0202 }
0203 if (m_plyWriteIt) {
0204 m_init_log->info("Writing ply files to {}...", m_outputDir);
0205 Acts::PlyVisualization3D plyVis;
0206 Acts::GeometryView3D::drawTrackingVolume(plyVis, *world, m_trackingGeoCtx, m_containerView,
0207 m_volumeView, m_passiveView, m_sensitiveView,
0208 m_gridView, m_plyWriteIt, m_outputTag, m_outputDir);
0209 }
0210
0211 m_init_log->debug("visiting all the surfaces ");
0212 m_trackingGeo->visitSurfaces([this](const Acts::Surface* surface) {
0213
0214 if (surface == nullptr) {
0215 m_init_log->info("no surface??? ");
0216 return;
0217 }
0218 #if Acts_VERSION_MAJOR >= 45
0219 const auto* placement = surface->surfacePlacement();
0220 const auto* det_element = dynamic_cast<const ActsPlugins::DD4hepDetectorElement*>(placement);
0221 #else
0222 const auto* det_element = dynamic_cast<const ActsPlugins::DD4hepDetectorElement*>(
0223 surface->associatedDetectorElement());
0224 #endif
0225
0226 if (det_element == nullptr) {
0227 m_init_log->error("invalid det_element!!! det_element == nullptr ");
0228 return;
0229 }
0230
0231
0232 m_init_log->debug(" det_element->identifier() = {} ", det_element->identifier());
0233 auto volman = m_dd4hepDetector->volumeManager();
0234 auto* vol_ctx = volman.lookupContext(det_element->identifier());
0235 auto vol_id = vol_ctx->identifier;
0236
0237 if (m_init_log->level() <= spdlog::level::debug) {
0238 auto de = vol_ctx->element;
0239 m_init_log->debug(" de.path = {}", de.path());
0240 m_init_log->debug(" de.placementPath = {}", de.placementPath());
0241 }
0242
0243 this->m_surfaces.insert_or_assign(vol_id, surface);
0244 });
0245 } else {
0246 m_init_log->error("m_trackingGeo==null why am I still alive???");
0247 }
0248
0249
0250 m_init_log->info("Loading magnetic field...");
0251 m_magneticField = std::make_shared<ActsPlugins::DD4hepFieldAdapter>(m_dd4hepDetector->field());
0252 auto bCache = m_magneticField->makeCache(Acts::MagneticFieldContext{});
0253 for (int z : {0, 500, 1000, 1500, 2000, 3000, 4000}) {
0254 auto b = m_magneticField->getField({0.0, 0.0, double(z)}, bCache).value();
0255 m_init_log->debug("B(z = {:>5} [mm]) = {} T", z, b.transpose() / Acts::UnitConstants::T);
0256 }
0257
0258 m_init_log->info("ActsGeometryProvider initialization complete");
0259 }
0260
0261 std::shared_ptr<const Acts::MagneticFieldProvider> ActsGeometryProvider::getFieldProvider() const {
0262 return m_magneticField;
0263 }