From 523274e7215010da8359c94596fb63eb5e1f55fe Mon Sep 17 00:00:00 2001 From: Paul Gessinger Date: Thu, 25 Jun 2026 16:16:44 +0200 Subject: [PATCH 1/6] feat: Add TrackingGeometry::findVolumeByName --- Core/include/Acts/Geometry/TrackingGeometry.hpp | 7 +++++++ Core/src/Geometry/TrackingGeometry.cpp | 11 +++++++++++ 2 files changed, 18 insertions(+) diff --git a/Core/include/Acts/Geometry/TrackingGeometry.hpp b/Core/include/Acts/Geometry/TrackingGeometry.hpp index cd90132dcf3..f4423225587 100644 --- a/Core/include/Acts/Geometry/TrackingGeometry.hpp +++ b/Core/include/Acts/Geometry/TrackingGeometry.hpp @@ -204,6 +204,13 @@ class TrackingGeometry { /// @retval pointer to the found volume otherwise. const TrackingVolume* findVolume(GeometryIdentifier id) const; + /// Search for the first volume with the given name. + /// + /// @param name is the volume name to search for + /// @retval nullptr if no volume carries the name + /// @retval pointer to the first matching volume otherwise. + const TrackingVolume* findVolumeByName(std::string_view name) const; + /// Search for a surface with the given identifier. /// /// @param id is the geometry identifier of the surface diff --git a/Core/src/Geometry/TrackingGeometry.cpp b/Core/src/Geometry/TrackingGeometry.cpp index 94aaddaa55d..0c9d3661009 100644 --- a/Core/src/Geometry/TrackingGeometry.cpp +++ b/Core/src/Geometry/TrackingGeometry.cpp @@ -279,6 +279,17 @@ const TrackingVolume* TrackingGeometry::findVolume( return vol->second; } +const TrackingVolume* TrackingGeometry::findVolumeByName( + std::string_view name) const { + const TrackingVolume* found = nullptr; + apply([&](const TrackingVolume& volume) { + if (found == nullptr && volume.volumeName() == name) { + found = &volume; + } + }); + return found; +} + const Surface* TrackingGeometry::findSurface(GeometryIdentifier id) const { auto srf = m_surfacesById.find(id); if (srf == m_surfacesById.end()) { From aff2ec90aad2c041b9a67e671db304f92459c160 Mon Sep 17 00:00:00 2001 From: Paul Gessinger Date: Thu, 25 Jun 2026 16:16:44 +0200 Subject: [PATCH 2/6] refactor: DetrayGeometryConverter as a configurable class Replace the free-function namespace with a class holding a Config that takes a DetrayPayloadConverter instance, so payload conversion can be customized from the call site. convert() returns a combined DetrayGeometry type bundling the detray detector, name map, detray-to-surface map and the owning TrackingGeometry. Mirror the new C++ API in the Python bindings (no alternative signatures/names) and update the validation scripts. Drop the redundant 'Acts' prefix from names: unprefixed is ACTS by default, detray types are prefixed. --- .../Scripts/Python/geometry_validation.py | 33 +- .../Scripts/Python/propagation_validation.py | 30 +- .../Detray/DetrayGeometryConverter.hpp | 288 ++++++++++-------- Python/Core/src/Geometry.cpp | 2 + Python/Plugins/src/Detray.cpp | 195 ++++++++---- 5 files changed, 351 insertions(+), 197 deletions(-) diff --git a/Examples/Scripts/Python/geometry_validation.py b/Examples/Scripts/Python/geometry_validation.py index d4fb18ec478..3e692e3037a 100644 --- a/Examples/Scripts/Python/geometry_validation.py +++ b/Examples/Scripts/Python/geometry_validation.py @@ -122,24 +122,37 @@ def main(): if args.input != "": files = glob.glob(args.input.rstrip("/") + "/*.json") print(">>> Reading detray geometry from", args.input, "->", files) - detrayGeometry, detrayNames = acts.detray.readODD(__pmr, files) + detrayDetector, detrayNames = acts.detray.readODD(__pmr, files) else: - detrayGeometry, detrayNames = acts.detray.convertODD( - __pmr, - gContext, - trackingGeometry, - beampipeVolumeName="BeamPipe", - detectorName="odd", - logLevel=logLevel, + payloadConfig = acts.detray.DetrayPayloadConverter.Config() + payloadConfig.beampipeVolume = trackingGeometry.findVolumeByName( + "BeamPipe" + ) + payloadConverter = acts.detray.DetrayPayloadConverter( + payloadConfig, logLevel + ) + + converterConfig = acts.detray.DetrayGeometryConverter.Config() + converterConfig.payloadConverter = payloadConverter + converter = acts.detray.DetrayGeometryConverter( + converterConfig, logLevel + ) + + detrayGeometry = converter.convert( + __pmr, gContext, trackingGeometry, detectorName="odd" + ) + detrayDetector, detrayNames = ( + detrayGeometry.detector, + detrayGeometry.names, ) if args.detray_consistency_check: - detrayGeometry.checkConsistency() + detrayDetector.checkConsistency() if args.output_json: print(">>> Outputting the detray geometry to json file ...") detray_out = prfx + "detray/" - detrayGeometry.writeToJson(detrayNames, detray_out) + detrayDetector.writeToJson(detrayNames, detray_out) print(">>> Written to", detray_out) elif args.geo_mode == "geant4": diff --git a/Examples/Scripts/Python/propagation_validation.py b/Examples/Scripts/Python/propagation_validation.py index e0c3a5fe6e5..43dcf3c8aa2 100644 --- a/Examples/Scripts/Python/propagation_validation.py +++ b/Examples/Scripts/Python/propagation_validation.py @@ -195,19 +195,29 @@ def main(): if args.input != "": files = glob.glob(args.input.rstrip("/") + "/*.json") print(">>> Reading detray geometry from", args.input, "->", files) - detrayGeometry, _ = acts.detray.readODD(__pmr, files) + detrayDetector, _ = acts.detray.readODD(__pmr, files) else: - detrayGeometry, _ = acts.detray.convertODD( - __pmr, - gContext, - trackingGeometry, - beampipeVolumeName="BeamPipe", - logLevel=logLevel, - convertMaterial=True, - convertSurfaceGrids=True, + payloadConfig = acts.detray.DetrayPayloadConverter.Config() + payloadConfig.beampipeVolume = trackingGeometry.findVolumeByName( + "BeamPipe" ) + payloadConverter = acts.detray.DetrayPayloadConverter( + payloadConfig, logLevel + ) + + converterConfig = acts.detray.DetrayGeometryConverter.Config() + converterConfig.payloadConverter = payloadConverter + converterConfig.convertMaterial = True + converterConfig.convertSurfaceGrids = True + converter = acts.detray.DetrayGeometryConverter( + converterConfig, logLevel + ) + + detrayDetector = converter.convert( + __pmr, gContext, trackingGeometry + ).detector propagatorImpl = acts.examples.detray.StraightLinePropagatorODD( - detrayGeometry, + detrayDetector, __pmr, sterileRun, logLevel, diff --git a/Plugins/Detray/include/ActsPlugins/Detray/DetrayGeometryConverter.hpp b/Plugins/Detray/include/ActsPlugins/Detray/DetrayGeometryConverter.hpp index e6624958274..7734ba7b55b 100644 --- a/Plugins/Detray/include/ActsPlugins/Detray/DetrayGeometryConverter.hpp +++ b/Plugins/Detray/include/ActsPlugins/Detray/DetrayGeometryConverter.hpp @@ -12,151 +12,199 @@ #include "Acts/Geometry/GeometryIdentifier.hpp" #include "Acts/Geometry/TrackingGeometry.hpp" #include "Acts/Geometry/TrackingVolume.hpp" +#include "Acts/Surfaces/Surface.hpp" +#include "Acts/Utilities/Logger.hpp" #include "ActsPlugins/Detray/DetrayConversionUtils.hpp" #include "ActsPlugins/Detray/DetrayPayloadConverter.hpp" -#include -#include +#include +#include +#include #include +#include #include #include #include #include -#include -#include -#include -#include -#include +#include -namespace ActsPlugins::DetrayGeometryConverter { +namespace ActsPlugins { -/// @brief conversion method from ACTS TrackingGeometry to detray detector -/// @tparam metadata_t the detector metadata type +/// @ingroup detray_plugin +/// @brief Converter from an ACTS TrackingGeometry to a detray detector /// -/// @param mr the memory resource to use for the detray detector construction -/// @param gctx the geometry context -/// @param trackingGeometry the ACTS tracking geometry to convert -/// @param beampipeVolumeName the beampipe volume name -/// @param detectorName the name to set for the detray detector (optional, -/// if not set, it will be taken from the payloads or defaulted to empty) -/// @param logLevel the logging level to use for the conversion process -/// @param convertMaterial whether to convert material information from ACTS to detray -/// @param convertSurfaceGrids whether to convert surface grid information from ACTS to detray -/// -/// This method performs the following steps: -/// 1. It searches for the beampipe volume in the ACTS tracking geometry using -/// the provided beampipeVolumeName. If found, it sets this volume in the -/// DetrayPayloadConverter configuration. If not found, it logs a warning. -/// 2. It creates a DetrayPayloadConverter instance with the configuration and -/// converts the ACTS tracking geometry into Detray payloads. -/// 3. It builds a detray detector from the converted payloads using the -/// detray::detector_builder. -/// -/// @return A pair of the built detray detector and its volume name map. -template -std::pair>, detray::name_map> -toDetray(vecmem::memory_resource& mr, const Acts::GeometryContext& gctx, - const Acts::TrackingGeometry& trackingGeometry, - const std::string& beampipeVolumeName, - const std::string& detectorName = "", - Acts::Logging::Level logLevel = Acts::Logging::INFO, - bool convertMaterial = true, bool convertSurfaceGrids = true) { - auto localLogger = - Acts::getDefaultLogger("DetrayGeometryConverter", logLevel); - auto payloadLogger = localLogger->clone("DetrayPayloadConverter"); - ACTS_LOCAL_LOGGER(std::move(localLogger)); - - // ── Convert TrackingGeometry → detray payloads ────────────────────────── - DetrayPayloadConverter::Config convCfg; - - ACTS_INFO("Looking for beampipe volume: " << beampipeVolumeName); - - // Find beampipe volume - trackingGeometry.apply( - [&beampipeVolumeName, &convCfg](const Acts::TrackingVolume& volume) { - if (volume.volumeName() == beampipeVolumeName) { - convCfg.beampipeVolume = &volume; - } - }); - - if (convCfg.beampipeVolume == nullptr) { - ACTS_WARNING("DetrayGeometryProvider: beampipe volume '" - << beampipeVolumeName << "' not found"); +/// The geometry conversion is a two-step process: first the ACTS geometry is +/// converted into detray payloads by a @c DetrayPayloadConverter, then those +/// payloads are used to build the actual detray detector. This class drives +/// the second step and lets the call site fully customize the first step by +/// supplying its own configured @c DetrayPayloadConverter instance through the +/// @c Config. +class DetrayGeometryConverter { + public: + /// @brief Configuration for the geometry converter + struct Config { + /// The payload converter used to turn the ACTS geometry into detray + /// payloads. Supplying it here allows the call site to fully customize the + /// payload conversion (e.g. the beampipe volume, sensitive surface + /// strategy or the navigation/material dispatchers). + std::shared_ptr payloadConverter; + + /// Whether to convert material information from ACTS to detray + bool convertMaterial = true; + + /// Whether to convert surface grid information from ACTS to detray + bool convertSurfaceGrids = true; + }; + + /// @brief Combined result of a geometry conversion + /// + /// Bundles the built detray detector together with the bookkeeping that + /// relates it back to the tracking geometry: the detray volume/surface name + /// map and the map from detray surface identifiers to the source surfaces. + /// @tparam metadata_t the detector metadata type + template + struct DetrayGeometry { + /// The built detray detector + std::shared_ptr> detector; + + /// The detray volume and surface name map + detray::name_map names; + + /// Map from detray surface identifiers to the source surfaces for all + /// sensitive surfaces in the detector. The GeometryIdentifier can be + /// obtained from the surface via @c Surface::geometryId. + std::unordered_map + detrayToSurfaceMap; + + /// The tracking geometry the detector was converted from, retained to keep + /// the surfaces referenced by @c detrayToSurfaceMap alive + std::shared_ptr trackingGeometry; + }; + + /// Constructor + /// @param config Configuration object + /// @param logger Logger instance + explicit DetrayGeometryConverter( + Config config, + std::unique_ptr logger = Acts::getDefaultLogger( + "DetrayGeometryConverter", Acts::Logging::INFO)) + : m_cfg(std::move(config)), m_logger(std::move(logger)) { + if (m_cfg.payloadConverter == nullptr) { + throw std::invalid_argument( + "DetrayGeometryConverter: payloadConverter must be set"); + } } - DetrayPayloadConverter converter(convCfg, std::move(payloadLogger)); - - auto payloads = converter.convertTrackingGeometry(gctx, trackingGeometry); + /// @brief Convert an ACTS TrackingGeometry into a detray detector + /// @tparam metadata_t the detector metadata type to build + /// + /// @param mr the memory resource to use for the detray detector construction + /// @param gctx the geometry context + /// @param trackingGeometry the ACTS tracking geometry to convert + /// @param detectorName the name to set for the detray detector (optional, if + /// not set, it will be taken from the payloads or defaulted to empty) + /// + /// This method performs the following steps: + /// 1. It converts the ACTS tracking geometry into detray payloads using the + /// configured DetrayPayloadConverter. + /// 2. It builds a detray detector from the converted payloads using the + /// detray::detector_builder. + /// 3. It builds the map from detray surface identifiers back to the source + /// surfaces. + /// + /// @return The built detray detector together with its name map, the + /// detray->surface map and the source tracking geometry. + template + DetrayGeometry convert( + vecmem::memory_resource& mr, const Acts::GeometryContext& gctx, + std::shared_ptr trackingGeometry, + const std::string& detectorName = "") const { + using detector_t = detray::detector; + + if (trackingGeometry == nullptr) { + throw std::invalid_argument( + "DetrayGeometryConverter: trackingGeometry must not be null"); + } - // ── Build detray detector from payloads ────────────────────────────────── - using detector_t = detray::detector; + // ── Convert TrackingGeometry → detray payloads ──────────────────────── + auto payloads = m_cfg.payloadConverter->convertTrackingGeometry( + gctx, *trackingGeometry); - detray::detector_builder detectorBuilder{}; + // ── Build detray detector from payloads ─────────────────────────────── + detray::detector_builder detectorBuilder{}; - detray::io::geometry_reader::from_payload(detectorBuilder, - *payloads.detector); + detray::io::geometry_reader::from_payload(detectorBuilder, + *payloads.detector); - if (convertMaterial) { - detray::io::homogeneous_material_reader::from_payload( - detectorBuilder, *payloads.homogeneousMaterial); + if (m_cfg.convertMaterial) { + detray::io::homogeneous_material_reader::from_payload( + detectorBuilder, *payloads.homogeneousMaterial); - detray::io::material_map_reader>:: - from_payload(detectorBuilder, - std::move(*payloads.materialGrids)); - } + detray::io::material_map_reader>:: + from_payload(detectorBuilder, + std::move(*payloads.materialGrids)); + } - if (convertSurfaceGrids) { - detray::io::surface_grid_reader, - std::integral_constant>:: - template from_payload(detectorBuilder, - *payloads.surfaceGrids); - } + if (m_cfg.convertSurfaceGrids) { + detray::io::surface_grid_reader, + std::integral_constant>:: + template from_payload(detectorBuilder, + *payloads.surfaceGrids); + } - if (!detectorName.empty()) { - detectorBuilder.set_name(detectorName); - } else if (payloads.names.contains(0)) { - detectorBuilder.set_name(payloads.names.at(0)); - } + if (!detectorName.empty()) { + detectorBuilder.set_name(detectorName); + } else if (payloads.names.contains(0)) { + detectorBuilder.set_name(payloads.names.at(0)); + } - detray::name_map names{}; - auto det = std::make_shared(detectorBuilder.build(mr, names)); + DetrayGeometry result{}; + result.detector = + std::make_shared(detectorBuilder.build(mr, result.names)); + result.detrayToSurfaceMap = + buildDetrayToSurfaceMap(*result.detector, *trackingGeometry); + result.trackingGeometry = std::move(trackingGeometry); - return {std::move(det), std::move(names)}; -} + return result; + } -/// Build a mapping from detray surface identifiers to ACTS -/// GeometryIdentifiers for all sensitive surfaces in the detray detector. -/// @tparam detector_t the type of the detray detector -/// @param detrayDetector the detray detector to build the mapping for -/// @param logLevel the logging level to use for the mapping process -/// -/// @return an unordered map mapping detray surface identifiers to ACTS GeometryIdentifiers -template -std::unordered_map -buildDetrayToActsMap(const detector_t& detrayDetector, - Acts::Logging::Level logLevel = Acts::Logging::INFO) { - auto localLogger = - Acts::getDefaultLogger("DetrayGeometryConverter", logLevel); - ACTS_LOCAL_LOGGER(std::move(localLogger)); - // ── Build detray→Acts geometry ID map - // ─────────────────────────────────── - std::unordered_map - detrayToActsMap; - - for (const auto& surface : detrayDetector.surfaces()) { - // surface.source is the Acts GeometryIdentifier encoded as uint64 - const Acts::GeometryIdentifier actsId(surface.source); - if (actsId.sensitive() == 0) { - continue; // skip portals and passives + private: + /// Build a mapping from detray surface identifiers to the source surfaces + /// for all sensitive surfaces in the detray detector. + /// @tparam detector_t the type of the detray detector + /// @param detrayDetector the detray detector to build the mapping for + /// @param trackingGeometry the geometry used to resolve the surfaces + /// @return a map from detray surface identifiers to the source surfaces + template + std::unordered_map + buildDetrayToSurfaceMap( + const detector_t& detrayDetector, + const Acts::TrackingGeometry& trackingGeometry) const { + std::unordered_map + detrayToSurfaceMap; + + for (const auto& surface : detrayDetector.surfaces()) { + // surface.source is the GeometryIdentifier encoded as uint64 + const Acts::GeometryIdentifier geometryId(surface.source); + const Acts::Surface* surfacePtr = + trackingGeometry.findSurface(geometryId); + if (surfacePtr == nullptr || !surfacePtr->isSensitive()) { + continue; // skip portals and passives + } + detrayToSurfaceMap[surface.identifier()] = surfacePtr; } - detrayToActsMap[surface.identifier()] = actsId; + + ACTS_INFO("Built detray→surface map with " << detrayToSurfaceMap.size() + << " sensitive surfaces"); + return detrayToSurfaceMap; } - ACTS_INFO("DetrayGeometryProvider: built detray→Acts map with " - << detrayToActsMap.size() << " sensitive surfaces"); - return detrayToActsMap; -} + Config m_cfg; + + const Acts::Logger& logger() const { return *m_logger; } + std::unique_ptr m_logger; +}; -} // namespace ActsPlugins::DetrayGeometryConverter +} // namespace ActsPlugins diff --git a/Python/Core/src/Geometry.cpp b/Python/Core/src/Geometry.cpp index 08aae80d2e0..81395b93b91 100644 --- a/Python/Core/src/Geometry.cpp +++ b/Python/Core/src/Geometry.cpp @@ -227,6 +227,8 @@ void addGeometry(py::module_& m) { .def("geoIdSurfaceMap", &TrackingGeometry::geoIdSurfaceMap) .def("findPortal", &TrackingGeometry::findPortal, py::arg("tag"), py::return_value_policy::reference_internal) + .def("findVolumeByName", &TrackingGeometry::findVolumeByName, + py::arg("name"), py::return_value_policy::reference_internal) .def("extractMaterialSurfaces", [](TrackingGeometry& self) { MaterialSurfaceSelector selector; diff --git a/Python/Plugins/src/Detray.cpp b/Python/Plugins/src/Detray.cpp index 1142ef19786..5adb3f0bf98 100644 --- a/Python/Plugins/src/Detray.cpp +++ b/Python/Plugins/src/Detray.cpp @@ -6,7 +6,10 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. +#include "Acts/Geometry/TrackingGeometry.hpp" +#include "Acts/Geometry/TrackingVolume.hpp" #include "ActsPlugins/Detray/DetrayGeometryConverter.hpp" +#include "ActsPlugins/Detray/DetrayPayloadConverter.hpp" #include "ActsPython/Utilities/Helpers.hpp" #include "ActsPython/Utilities/Macros.hpp" @@ -16,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -31,61 +35,138 @@ using namespace pybind11::literals; PYBIND11_MODULE(ActsPluginsPythonBindingsDetray, detray) { using namespace ActsPlugins; - { - using DetrayMetaDataODD = detray::odd_metadata>; - using DetrayDetectorODD = detray::detector; - - py::class_(detray, "DetrayDetectorODDNameMap"); - - // Register the raw detector type so shared_ptr can be - // passed to functions in other pybind11 modules (e.g. - // StraightLinePropagatorODD). - py::class_>( - detray, "DetrayDetectorODD") - .def("volumes", [](DetrayDetectorODD& self) { return self.volumes(); }) - .def("surfaces", - [](DetrayDetectorODD& self) { return self.surfaces(); }) - .def("checkConsistency", - [](DetrayDetectorODD& self) { - detray::detail::check_consistency(self); - }) - .def("writeToJson", [](DetrayDetectorODD& self, - const DetrayDetectorODD::name_map& names, - const std::string& fname) { - auto cfg = detray::io::detector_writer_config{} - .format(detray::io::format::json) - .path(fname) - .replace_files(true); - detray::io::write_detector(self, names, cfg); - }); - - detray.def( - "readODD", - [](vecmem::memory_resource& mr, const std::vector& files) { - auto cfg = detray::io::detector_reader_config{}.do_check(false); - for (const auto& f : files) { - cfg.add_file(f); - } - return detray::io::read_detector(mr, cfg); - }, - "mr"_a, "files"_a); - - detray.def( - "convertODD", - [](vecmem::memory_resource& mr, const Acts::GeometryContext& gctx, - const Acts::TrackingGeometry& trackingGeometry, - const std::string& beampipeVolumeName, - const std::string& detectorName = "", - Acts::Logging::Level logLevel = Acts::Logging::INFO, - bool convertMaterial = true, bool convertSurfaceGrids = true) { - auto [det, names] = - DetrayGeometryConverter::toDetray( - mr, gctx, trackingGeometry, beampipeVolumeName, detectorName, - logLevel, convertMaterial, convertSurfaceGrids); - return std::make_pair(std::move(det), std::move(names)); - }, - "mr"_a, "gctx"_a, "trackingGeometry"_a, "beampipeVolumeName"_a, - "detectorName"_a = "", "logLevel"_a = Acts::Logging::INFO, - "convertMaterial"_a = true, "convertSurfaceGrids"_a = true); - } + using DetrayMetaDataODD = detray::odd_metadata>; + using DetrayDetectorODD = detray::detector; + + py::class_(detray, "DetrayDetectorODDNameMap"); + + // Register the raw detector type so shared_ptr can be + // passed to functions in other pybind11 modules (e.g. + // StraightLinePropagatorODD). + py::class_>( + detray, "DetrayDetectorODD") + .def("volumes", [](DetrayDetectorODD& self) { return self.volumes(); }) + .def("surfaces", [](DetrayDetectorODD& self) { return self.surfaces(); }) + .def("checkConsistency", + [](DetrayDetectorODD& self) { + detray::detail::check_consistency(self); + }) + .def("writeToJson", + [](DetrayDetectorODD& self, const DetrayDetectorODD::name_map& names, + const std::string& fname) { + auto cfg = detray::io::detector_writer_config{} + .format(detray::io::format::json) + .path(fname) + .replace_files(true); + detray::io::write_detector(self, names, cfg); + }); + + detray.def( + "readODD", + [](vecmem::memory_resource& mr, const std::vector& files) { + auto cfg = detray::io::detector_reader_config{}.do_check(false); + for (const auto& f : files) { + cfg.add_file(f); + } + return detray::io::read_detector(mr, cfg); + }, + "mr"_a, "files"_a); + + // Detray surface identifier (distinct from the ACTS GeometryIdentifier). + py::class_(detray, "DetrayGeometryIdentifier") + .def("value", &detray::geometry::identifier::value) + .def( + "__int__", + [](const detray::geometry::identifier& self) { return self.value(); }) + .def("__eq__", + [](const detray::geometry::identifier& self, + const detray::geometry::identifier& other) { + return self == other; + }) + .def("__hash__", + [](const detray::geometry::identifier& self) { + return static_cast(self.value()); + }) + .def("__repr__", [](const detray::geometry::identifier& self) { + return "DetrayGeometryIdentifier(" + std::to_string(self.value()) + ")"; + }); + + // ── Payload converter ────────────────────────────────────────────────── + auto payloadConverter = py::class_>( + detray, "DetrayPayloadConverter"); + + auto payloadConfig = + py::class_(payloadConverter, "Config") + .def(py::init<>()) + .def_readwrite("sensitiveStrategy", + &DetrayPayloadConverter::Config::sensitiveStrategy) + .def_property( + "beampipeVolume", + [](const DetrayPayloadConverter::Config& cfg) { + return cfg.beampipeVolume; + }, + [](DetrayPayloadConverter::Config& cfg, + const Acts::TrackingVolume* volume) { + cfg.beampipeVolume = volume; + }, + py::return_value_policy::reference); + + py::enum_( + payloadConfig, "SensitiveStrategy") + .value("Identifier", + DetrayPayloadConverter::Config::SensitiveStrategy::Identifier) + .value( + "DetectorElement", + DetrayPayloadConverter::Config::SensitiveStrategy::DetectorElement); + + payloadConverter.def( + py::init([](const DetrayPayloadConverter::Config& config, + Acts::Logging::Level level) { + return std::make_shared( + config, Acts::getDefaultLogger("DetrayPayloadConverter", level)); + }), + "config"_a, "level"_a = Acts::Logging::INFO); + + // ── Geometry converter ───────────────────────────────────────────────── + auto geometryConverter = py::class_>( + detray, "DetrayGeometryConverter"); + + py::class_(geometryConverter, "Config") + .def(py::init<>()) + .def_readwrite("payloadConverter", + &DetrayGeometryConverter::Config::payloadConverter) + .def_readwrite("convertMaterial", + &DetrayGeometryConverter::Config::convertMaterial) + .def_readwrite("convertSurfaceGrids", + &DetrayGeometryConverter::Config::convertSurfaceGrids); + + using DetrayGeometryODD = + DetrayGeometryConverter::DetrayGeometry; + py::class_(geometryConverter, "DetrayGeometry") + .def_readonly("detector", &DetrayGeometryODD::detector) + .def_readonly("names", &DetrayGeometryODD::names) + .def_readonly("detrayToSurfaceMap", + &DetrayGeometryODD::detrayToSurfaceMap) + .def_readonly("trackingGeometry", &DetrayGeometryODD::trackingGeometry); + + geometryConverter + .def(py::init([](DetrayGeometryConverter::Config config, + Acts::Logging::Level level) { + return std::make_shared( + std::move(config), + Acts::getDefaultLogger("DetrayGeometryConverter", level)); + }), + "config"_a, "level"_a = Acts::Logging::INFO) + .def( + "convert", + [](const DetrayGeometryConverter& self, vecmem::memory_resource& mr, + const Acts::GeometryContext& gctx, + std::shared_ptr trackingGeometry, + const std::string& detectorName) { + return self.convert( + mr, gctx, std::move(trackingGeometry), detectorName); + }, + "mr"_a, "gctx"_a, "trackingGeometry"_a, "detectorName"_a = ""); } From a31aa8e59d135d9ad60529d96f1c0485c171793b Mon Sep 17 00:00:00 2001 From: Paul Gessinger Date: Thu, 25 Jun 2026 16:42:13 +0200 Subject: [PATCH 3/6] refactor: Closed-set detray metadata with extern-template instantiation Centralize the closed set of detray metadata (Odd, Default) in DetrayMetadata.hpp and iterate it via ACTS_DETRAY_METADATA_FOR_EACH. Split the heavy convert() and detector IO (consistency check, JSON write, read) definitions into .ipp files and declare extern template instantiations so they compile once per metadata in dedicated TUs; experiment code can still instantiate custom metadata. Dispatch the Python bindings over the closed set with the metadata as the first argument, and replace readODD with a metadata-dispatched read. --- .../Scripts/Python/geometry_validation.py | 10 +- .../Scripts/Python/propagation_validation.py | 6 +- Plugins/Detray/CMakeLists.txt | 2 + .../ActsPlugins/Detray/DetrayDetectorIO.hpp | 74 +++++++++ .../ActsPlugins/Detray/DetrayDetectorIO.ipp | 53 +++++++ .../Detray/DetrayGeometryConverter.hpp | 109 +++++--------- .../Detray/DetrayGeometryConverter.ipp | 109 ++++++++++++++ .../ActsPlugins/Detray/DetrayMetadata.hpp | 41 +++++ Plugins/Detray/src/DetrayDetectorDefault.cpp | 20 +++ Plugins/Detray/src/DetrayDetectorOdd.cpp | 20 +++ Python/Plugins/src/Detray.cpp | 140 ++++++++++-------- 11 files changed, 447 insertions(+), 137 deletions(-) create mode 100644 Plugins/Detray/include/ActsPlugins/Detray/DetrayDetectorIO.hpp create mode 100644 Plugins/Detray/include/ActsPlugins/Detray/DetrayDetectorIO.ipp create mode 100644 Plugins/Detray/include/ActsPlugins/Detray/DetrayGeometryConverter.ipp create mode 100644 Plugins/Detray/include/ActsPlugins/Detray/DetrayMetadata.hpp create mode 100644 Plugins/Detray/src/DetrayDetectorDefault.cpp create mode 100644 Plugins/Detray/src/DetrayDetectorOdd.cpp diff --git a/Examples/Scripts/Python/geometry_validation.py b/Examples/Scripts/Python/geometry_validation.py index 3e692e3037a..0b85d8a2016 100644 --- a/Examples/Scripts/Python/geometry_validation.py +++ b/Examples/Scripts/Python/geometry_validation.py @@ -122,7 +122,9 @@ def main(): if args.input != "": files = glob.glob(args.input.rstrip("/") + "/*.json") print(">>> Reading detray geometry from", args.input, "->", files) - detrayDetector, detrayNames = acts.detray.readODD(__pmr, files) + detrayDetector, detrayNames = acts.detray.read( + acts.detray.OddMetadata, __pmr, files + ) else: payloadConfig = acts.detray.DetrayPayloadConverter.Config() payloadConfig.beampipeVolume = trackingGeometry.findVolumeByName( @@ -139,7 +141,11 @@ def main(): ) detrayGeometry = converter.convert( - __pmr, gContext, trackingGeometry, detectorName="odd" + acts.detray.OddMetadata, + __pmr, + gContext, + trackingGeometry, + detectorName="odd", ) detrayDetector, detrayNames = ( detrayGeometry.detector, diff --git a/Examples/Scripts/Python/propagation_validation.py b/Examples/Scripts/Python/propagation_validation.py index 43dcf3c8aa2..2a5b28663e8 100644 --- a/Examples/Scripts/Python/propagation_validation.py +++ b/Examples/Scripts/Python/propagation_validation.py @@ -195,7 +195,9 @@ def main(): if args.input != "": files = glob.glob(args.input.rstrip("/") + "/*.json") print(">>> Reading detray geometry from", args.input, "->", files) - detrayDetector, _ = acts.detray.readODD(__pmr, files) + detrayDetector, _ = acts.detray.read( + acts.detray.OddMetadata, __pmr, files + ) else: payloadConfig = acts.detray.DetrayPayloadConverter.Config() payloadConfig.beampipeVolume = trackingGeometry.findVolumeByName( @@ -214,7 +216,7 @@ def main(): ) detrayDetector = converter.convert( - __pmr, gContext, trackingGeometry + acts.detray.OddMetadata, __pmr, gContext, trackingGeometry ).detector propagatorImpl = acts.examples.detray.StraightLinePropagatorODD( detrayDetector, diff --git a/Plugins/Detray/CMakeLists.txt b/Plugins/Detray/CMakeLists.txt index cbe8ceaeabf..e9b551a4443 100644 --- a/Plugins/Detray/CMakeLists.txt +++ b/Plugins/Detray/CMakeLists.txt @@ -4,6 +4,8 @@ acts_add_library( src/DetrayPayloadConverter.cpp src/DetrayMaterial.cpp src/DetrayNavigation.cpp + src/DetrayDetectorOdd.cpp + src/DetrayDetectorDefault.cpp ACTS_INCLUDE_FOLDER include/ActsPlugins ) diff --git a/Plugins/Detray/include/ActsPlugins/Detray/DetrayDetectorIO.hpp b/Plugins/Detray/include/ActsPlugins/Detray/DetrayDetectorIO.hpp new file mode 100644 index 00000000000..2e1d131b864 --- /dev/null +++ b/Plugins/Detray/include/ActsPlugins/Detray/DetrayDetectorIO.hpp @@ -0,0 +1,74 @@ +// This file is part of the ACTS project. +// +// Copyright (C) 2016 CERN for the benefit of the ACTS project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#pragma once + +#include "ActsPlugins/Detray/DetrayMetadata.hpp" + +#include +#include +#include + +#include +#include + +namespace ActsPlugins { + +/// @ingroup detray_plugin +/// @brief Per-metadata detray detector operations +/// +/// These are thin wrappers around the heavy detray detector algorithms +/// (consistency checking and JSON I/O). They are member templates over the +/// detray metadata type and are explicitly instantiated (and declared +/// `extern template`) for the closed set of metadata types, so that the +/// expensive detray template trees are compiled only once per metadata in a +/// dedicated translation unit instead of in every consumer (Python bindings, +/// tests, …). The definitions live in @c DetrayDetectorIO.ipp; experiment code +/// may instantiate them for a custom metadata by including that header. + +/// Check the consistency of a detray detector (throws on inconsistency). +/// @param detector the detray detector to check +template +void checkDetrayConsistency(const detray::detector& detector); + +/// Write a detray detector to JSON file(s). +/// @param detector the detray detector to write +/// @param names the detray volume/surface name map +/// @param path the output path for the JSON file(s) +template +void writeDetrayJson(const detray::detector& detector, + const detray::name_map& names, const std::string& path); + +/// Read a detray detector and its name map from JSON file(s). +/// @param mr the memory resource to build the detector with +/// @param files the JSON file(s) to read +/// @return the built detector together with its name map +template +std::pair, detray::name_map> readDetrayDetector( + vecmem::memory_resource& mr, const std::vector& files); + +/// Explicit instantiation declarators for the operations of one metadata. +/// @p PREFIX is empty for an instantiation definition or `extern` for a +/// declaration. +#define ACTS_DETRAY_IO_INSTANTIATION(PREFIX, META) \ + PREFIX template void checkDetrayConsistency( \ + const detray::detector&); \ + PREFIX template void writeDetrayJson(const detray::detector&, \ + const detray::name_map&, \ + const std::string&); \ + PREFIX template std::pair, detray::name_map> \ + readDetrayDetector(vecmem::memory_resource&, \ + const std::vector&); + +// Suppress implicit instantiation of the operations for the closed set; the +// definitions are emitted in dedicated translation units (see src/). +#define ACTS_DETRAY_EXTERN_IO(META) ACTS_DETRAY_IO_INSTANTIATION(extern, META) +ACTS_DETRAY_METADATA_FOR_EACH(ACTS_DETRAY_EXTERN_IO) +#undef ACTS_DETRAY_EXTERN_IO + +} // namespace ActsPlugins diff --git a/Plugins/Detray/include/ActsPlugins/Detray/DetrayDetectorIO.ipp b/Plugins/Detray/include/ActsPlugins/Detray/DetrayDetectorIO.ipp new file mode 100644 index 00000000000..55b8a1515a5 --- /dev/null +++ b/Plugins/Detray/include/ActsPlugins/Detray/DetrayDetectorIO.ipp @@ -0,0 +1,53 @@ +// This file is part of the ACTS project. +// +// Copyright (C) 2016 CERN for the benefit of the ACTS project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#pragma once + +// Implementation of the detray detector operations. Include this header +// (instead of DetrayDetectorIO.hpp) when instantiating the operations for a +// metadata type that is not part of the closed set declared in +// DetrayMetadata.hpp. + +#include "ActsPlugins/Detray/DetrayDetectorIO.hpp" + +#include + +#include +#include +#include +#include +#include + +namespace ActsPlugins { + +template +void checkDetrayConsistency(const detray::detector& detector) { + detray::detail::check_consistency(detector); +} + +template +void writeDetrayJson(const detray::detector& detector, + const detray::name_map& names, const std::string& path) { + auto cfg = detray::io::detector_writer_config{} + .format(detray::io::format::json) + .path(path) + .replace_files(true); + detray::io::write_detector(detector, names, cfg); +} + +template +std::pair, detray::name_map> readDetrayDetector( + vecmem::memory_resource& mr, const std::vector& files) { + auto cfg = detray::io::detector_reader_config{}.do_check(false); + for (const auto& file : files) { + cfg.add_file(file); + } + return detray::io::read_detector>(mr, cfg); +} + +} // namespace ActsPlugins diff --git a/Plugins/Detray/include/ActsPlugins/Detray/DetrayGeometryConverter.hpp b/Plugins/Detray/include/ActsPlugins/Detray/DetrayGeometryConverter.hpp index 7734ba7b55b..acc1932f0ac 100644 --- a/Plugins/Detray/include/ActsPlugins/Detray/DetrayGeometryConverter.hpp +++ b/Plugins/Detray/include/ActsPlugins/Detray/DetrayGeometryConverter.hpp @@ -11,22 +11,19 @@ #include "Acts/Geometry/GeometryContext.hpp" #include "Acts/Geometry/GeometryIdentifier.hpp" #include "Acts/Geometry/TrackingGeometry.hpp" -#include "Acts/Geometry/TrackingVolume.hpp" #include "Acts/Surfaces/Surface.hpp" #include "Acts/Utilities/Logger.hpp" #include "ActsPlugins/Detray/DetrayConversionUtils.hpp" +#include "ActsPlugins/Detray/DetrayMetadata.hpp" #include "ActsPlugins/Detray/DetrayPayloadConverter.hpp" #include +#include #include #include -#include +#include #include -#include -#include -#include -#include #include namespace ActsPlugins { @@ -40,6 +37,14 @@ namespace ActsPlugins { /// the second step and lets the call site fully customize the first step by /// supplying its own configured @c DetrayPayloadConverter instance through the /// @c Config. +/// +/// @c convert is a member template over the detray metadata type. It is +/// explicitly instantiated (and declared `extern template`) for the closed set +/// of supported metadata types listed in @ref DetrayMetadata.hpp, so that the +/// heavy detray detector-building code is compiled only once per metadata in a +/// dedicated translation unit. Experiment code may still convert to a custom +/// metadata by including @c DetrayGeometryConverter.ipp and instantiating +/// @c convert with the desired metadata type. class DetrayGeometryConverter { public: /// @brief Configuration for the geometry converter @@ -113,62 +118,17 @@ class DetrayGeometryConverter { /// 3. It builds the map from detray surface identifiers back to the source /// surfaces. /// + /// @note The definition lives in @c DetrayGeometryConverter.ipp; for the + /// closed set of metadata types it is `extern template` declared here and + /// instantiated in a dedicated translation unit. + /// /// @return The built detray detector together with its name map, the /// detray->surface map and the source tracking geometry. template DetrayGeometry convert( vecmem::memory_resource& mr, const Acts::GeometryContext& gctx, std::shared_ptr trackingGeometry, - const std::string& detectorName = "") const { - using detector_t = detray::detector; - - if (trackingGeometry == nullptr) { - throw std::invalid_argument( - "DetrayGeometryConverter: trackingGeometry must not be null"); - } - - // ── Convert TrackingGeometry → detray payloads ──────────────────────── - auto payloads = m_cfg.payloadConverter->convertTrackingGeometry( - gctx, *trackingGeometry); - - // ── Build detray detector from payloads ─────────────────────────────── - detray::detector_builder detectorBuilder{}; - - detray::io::geometry_reader::from_payload(detectorBuilder, - *payloads.detector); - - if (m_cfg.convertMaterial) { - detray::io::homogeneous_material_reader::from_payload( - detectorBuilder, *payloads.homogeneousMaterial); - - detray::io::material_map_reader>:: - from_payload(detectorBuilder, - std::move(*payloads.materialGrids)); - } - - if (m_cfg.convertSurfaceGrids) { - detray::io::surface_grid_reader, - std::integral_constant>:: - template from_payload(detectorBuilder, - *payloads.surfaceGrids); - } - - if (!detectorName.empty()) { - detectorBuilder.set_name(detectorName); - } else if (payloads.names.contains(0)) { - detectorBuilder.set_name(payloads.names.at(0)); - } - - DetrayGeometry result{}; - result.detector = - std::make_shared(detectorBuilder.build(mr, result.names)); - result.detrayToSurfaceMap = - buildDetrayToSurfaceMap(*result.detector, *trackingGeometry); - result.trackingGeometry = std::move(trackingGeometry); - - return result; - } + const std::string& detectorName = "") const; private: /// Build a mapping from detray surface identifiers to the source surfaces @@ -181,25 +141,7 @@ class DetrayGeometryConverter { std::unordered_map buildDetrayToSurfaceMap( const detector_t& detrayDetector, - const Acts::TrackingGeometry& trackingGeometry) const { - std::unordered_map - detrayToSurfaceMap; - - for (const auto& surface : detrayDetector.surfaces()) { - // surface.source is the GeometryIdentifier encoded as uint64 - const Acts::GeometryIdentifier geometryId(surface.source); - const Acts::Surface* surfacePtr = - trackingGeometry.findSurface(geometryId); - if (surfacePtr == nullptr || !surfacePtr->isSensitive()) { - continue; // skip portals and passives - } - detrayToSurfaceMap[surface.identifier()] = surfacePtr; - } - - ACTS_INFO("Built detray→surface map with " << detrayToSurfaceMap.size() - << " sensitive surfaces"); - return detrayToSurfaceMap; - } + const Acts::TrackingGeometry& trackingGeometry) const; Config m_cfg; @@ -207,4 +149,21 @@ class DetrayGeometryConverter { std::unique_ptr m_logger; }; +/// Declarator for an explicit (extern) instantiation of @c convert for a +/// given metadata. The leading `template` keyword makes it an explicit +/// instantiation definition; prefix with `extern` for a declaration. +#define ACTS_DETRAY_CONVERT_INSTANTIATION(META) \ + template DetrayGeometryConverter::DetrayGeometry \ + DetrayGeometryConverter::convert( \ + vecmem::memory_resource&, const Acts::GeometryContext&, \ + std::shared_ptr, const std::string&) \ + const + +// Suppress implicit instantiation of `convert` for the closed set; the +// definitions are emitted in dedicated translation units (see src/). +#define ACTS_DETRAY_EXTERN_CONVERT(META) \ + extern ACTS_DETRAY_CONVERT_INSTANTIATION(META); +ACTS_DETRAY_METADATA_FOR_EACH(ACTS_DETRAY_EXTERN_CONVERT) +#undef ACTS_DETRAY_EXTERN_CONVERT + } // namespace ActsPlugins diff --git a/Plugins/Detray/include/ActsPlugins/Detray/DetrayGeometryConverter.ipp b/Plugins/Detray/include/ActsPlugins/Detray/DetrayGeometryConverter.ipp new file mode 100644 index 00000000000..cabc0e69033 --- /dev/null +++ b/Plugins/Detray/include/ActsPlugins/Detray/DetrayGeometryConverter.ipp @@ -0,0 +1,109 @@ +// This file is part of the ACTS project. +// +// Copyright (C) 2016 CERN for the benefit of the ACTS project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#pragma once + +// Implementation of the DetrayGeometryConverter::convert member template. +// +// Include this header (instead of DetrayGeometryConverter.hpp) when you need to +// instantiate `convert` for a metadata type that is not part of the closed set +// declared in DetrayMetadata.hpp. + +#include "Acts/Geometry/TrackingVolume.hpp" +#include "ActsPlugins/Detray/DetrayGeometryConverter.hpp" + +#include + +#include +#include +#include +#include +#include + +namespace ActsPlugins { + +template +DetrayGeometryConverter::DetrayGeometry +DetrayGeometryConverter::convert( + vecmem::memory_resource& mr, const Acts::GeometryContext& gctx, + std::shared_ptr trackingGeometry, + const std::string& detectorName) const { + using detector_t = detray::detector; + + if (trackingGeometry == nullptr) { + throw std::invalid_argument( + "DetrayGeometryConverter: trackingGeometry must not be null"); + } + + // ── Convert TrackingGeometry → detray payloads ────────────────────────── + auto payloads = + m_cfg.payloadConverter->convertTrackingGeometry(gctx, *trackingGeometry); + + // ── Build detray detector from payloads ───────────────────────────────── + detray::detector_builder detectorBuilder{}; + + detray::io::geometry_reader::from_payload(detectorBuilder, + *payloads.detector); + + if (m_cfg.convertMaterial) { + detray::io::homogeneous_material_reader::from_payload( + detectorBuilder, *payloads.homogeneousMaterial); + + detray::io::material_map_reader>:: + from_payload(detectorBuilder, + std::move(*payloads.materialGrids)); + } + + if (m_cfg.convertSurfaceGrids) { + detray::io::surface_grid_reader, + std::integral_constant>:: + template from_payload(detectorBuilder, + *payloads.surfaceGrids); + } + + if (!detectorName.empty()) { + detectorBuilder.set_name(detectorName); + } else if (payloads.names.contains(0)) { + detectorBuilder.set_name(payloads.names.at(0)); + } + + DetrayGeometry result{}; + result.detector = + std::make_shared(detectorBuilder.build(mr, result.names)); + result.detrayToSurfaceMap = + buildDetrayToSurfaceMap(*result.detector, *trackingGeometry); + result.trackingGeometry = std::move(trackingGeometry); + + return result; +} + +template +std::unordered_map +DetrayGeometryConverter::buildDetrayToSurfaceMap( + const detector_t& detrayDetector, + const Acts::TrackingGeometry& trackingGeometry) const { + std::unordered_map + detrayToSurfaceMap; + + for (const auto& surface : detrayDetector.surfaces()) { + // surface.source is the GeometryIdentifier encoded as uint64 + const Acts::GeometryIdentifier geometryId(surface.source); + const Acts::Surface* surfacePtr = trackingGeometry.findSurface(geometryId); + if (surfacePtr == nullptr || !surfacePtr->isSensitive()) { + continue; // skip portals and passives + } + detrayToSurfaceMap[surface.identifier()] = surfacePtr; + } + + ACTS_INFO("Built detray→surface map with " << detrayToSurfaceMap.size() + << " sensitive surfaces"); + return detrayToSurfaceMap; +} + +} // namespace ActsPlugins diff --git a/Plugins/Detray/include/ActsPlugins/Detray/DetrayMetadata.hpp b/Plugins/Detray/include/ActsPlugins/Detray/DetrayMetadata.hpp new file mode 100644 index 00000000000..a0719c6a206 --- /dev/null +++ b/Plugins/Detray/include/ActsPlugins/Detray/DetrayMetadata.hpp @@ -0,0 +1,41 @@ +// This file is part of the ACTS project. +// +// Copyright (C) 2016 CERN for the benefit of the ACTS project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#pragma once + +#include +#include +#include + +namespace ActsPlugins::DetrayMetadata { + +/// @addtogroup detray_plugin +/// @{ + +/// Metadata for the Open Data Detector +using Odd = detray::odd_metadata>; + +/// Detray's generic default metadata +using Default = detray::default_metadata>; + +/// @} + +} // namespace ActsPlugins::DetrayMetadata + +/// X-macro over the closed set of supported detray metadata types. +/// +/// Invoke with a single-argument macro; it is expanded once per metadata. This +/// is the single source of truth for the closed set and is used to generate the +/// `extern template` declarations of @c DetrayGeometryConverter::convert and the +/// corresponding explicit instantiations (one translation unit per metadata). +/// +/// To add a metadata type, add the alias above and one line here, then create +/// the matching instantiation translation unit. +#define ACTS_DETRAY_METADATA_FOR_EACH(MACRO) \ + MACRO(::ActsPlugins::DetrayMetadata::Odd) \ + MACRO(::ActsPlugins::DetrayMetadata::Default) diff --git a/Plugins/Detray/src/DetrayDetectorDefault.cpp b/Plugins/Detray/src/DetrayDetectorDefault.cpp new file mode 100644 index 00000000000..7fad866ba8c --- /dev/null +++ b/Plugins/Detray/src/DetrayDetectorDefault.cpp @@ -0,0 +1,20 @@ +// This file is part of the ACTS project. +// +// Copyright (C) 2016 CERN for the benefit of the ACTS project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +// Per-metadata instantiation of the heavy detray detector code (geometry +// conversion and detector I/O) for the default metadata. + +#include "ActsPlugins/Detray/DetrayDetectorIO.ipp" +#include "ActsPlugins/Detray/DetrayGeometryConverter.ipp" + +namespace ActsPlugins { + +ACTS_DETRAY_CONVERT_INSTANTIATION(DetrayMetadata::Default); +ACTS_DETRAY_IO_INSTANTIATION(, DetrayMetadata::Default) + +} // namespace ActsPlugins diff --git a/Plugins/Detray/src/DetrayDetectorOdd.cpp b/Plugins/Detray/src/DetrayDetectorOdd.cpp new file mode 100644 index 00000000000..488e6f53bb3 --- /dev/null +++ b/Plugins/Detray/src/DetrayDetectorOdd.cpp @@ -0,0 +1,20 @@ +// This file is part of the ACTS project. +// +// Copyright (C) 2016 CERN for the benefit of the ACTS project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +// Per-metadata instantiation of the heavy detray detector code (geometry +// conversion and detector I/O) for the ODD metadata. + +#include "ActsPlugins/Detray/DetrayDetectorIO.ipp" +#include "ActsPlugins/Detray/DetrayGeometryConverter.ipp" + +namespace ActsPlugins { + +ACTS_DETRAY_CONVERT_INSTANTIATION(DetrayMetadata::Odd); +ACTS_DETRAY_IO_INSTANTIATION(, DetrayMetadata::Odd) + +} // namespace ActsPlugins diff --git a/Python/Plugins/src/Detray.cpp b/Python/Plugins/src/Detray.cpp index 5adb3f0bf98..f6091c294dc 100644 --- a/Python/Plugins/src/Detray.cpp +++ b/Python/Plugins/src/Detray.cpp @@ -8,22 +8,20 @@ #include "Acts/Geometry/TrackingGeometry.hpp" #include "Acts/Geometry/TrackingVolume.hpp" +#include "ActsPlugins/Detray/DetrayDetectorIO.hpp" #include "ActsPlugins/Detray/DetrayGeometryConverter.hpp" +#include "ActsPlugins/Detray/DetrayMetadata.hpp" #include "ActsPlugins/Detray/DetrayPayloadConverter.hpp" #include "ActsPython/Utilities/Helpers.hpp" #include "ActsPython/Utilities/Macros.hpp" #include +#include #include +#include -#include -#include -#include +#include #include -#include -#include -#include -#include #include #include #include @@ -35,42 +33,9 @@ using namespace pybind11::literals; PYBIND11_MODULE(ActsPluginsPythonBindingsDetray, detray) { using namespace ActsPlugins; - using DetrayMetaDataODD = detray::odd_metadata>; - using DetrayDetectorODD = detray::detector; - - py::class_(detray, "DetrayDetectorODDNameMap"); - - // Register the raw detector type so shared_ptr can be - // passed to functions in other pybind11 modules (e.g. - // StraightLinePropagatorODD). - py::class_>( - detray, "DetrayDetectorODD") - .def("volumes", [](DetrayDetectorODD& self) { return self.volumes(); }) - .def("surfaces", [](DetrayDetectorODD& self) { return self.surfaces(); }) - .def("checkConsistency", - [](DetrayDetectorODD& self) { - detray::detail::check_consistency(self); - }) - .def("writeToJson", - [](DetrayDetectorODD& self, const DetrayDetectorODD::name_map& names, - const std::string& fname) { - auto cfg = detray::io::detector_writer_config{} - .format(detray::io::format::json) - .path(fname) - .replace_files(true); - detray::io::write_detector(self, names, cfg); - }); - - detray.def( - "readODD", - [](vecmem::memory_resource& mr, const std::vector& files) { - auto cfg = detray::io::detector_reader_config{}.do_check(false); - for (const auto& f : files) { - cfg.add_file(f); - } - return detray::io::read_detector(mr, cfg); - }, - "mr"_a, "files"_a); + // The detray volume/surface name map is the same type for every metadata, so + // it is registered exactly once. + py::class_(detray, "DetrayNameMap"); // Detray surface identifier (distinct from the ACTS GeometryIdentifier). py::class_(detray, "DetrayGeometryIdentifier") @@ -91,6 +56,34 @@ PYBIND11_MODULE(ActsPluginsPythonBindingsDetray, detray) { return "DetrayGeometryIdentifier(" + std::to_string(self.value()) + ")"; }); + // Metadata markers for the closed set. These empty classes are passed (as the + // class object) to DetrayGeometryConverter.convert to select the metadata, + // mirroring the C++ template argument convert. + auto oddMetadata = py::class_(detray, "OddMetadata"); + auto defaultMetadata = + py::class_(detray, "DefaultMetadata"); + + // Read a pre-built detray detector from JSON file(s). The metadata is + // selected by passing one of the metadata markers, mirroring convert. + detray.def( + "read", + [oddType = py::object(oddMetadata), + defaultType = py::object(defaultMetadata)]( + py::object metadata, vecmem::memory_resource& mr, + const std::vector& files) -> py::object { + if (metadata.is(oddType)) { + return py::cast(readDetrayDetector(mr, files)); + } + if (metadata.is(defaultType)) { + return py::cast( + readDetrayDetector(mr, files)); + } + throw std::invalid_argument( + "detray.read: unsupported metadata; pass one of the metadata " + "markers (e.g. acts.detray.OddMetadata)"); + }, + "metadata"_a, "mr"_a, "files"_a); + // ── Payload converter ────────────────────────────────────────────────── auto payloadConverter = py::class_>( @@ -142,14 +135,33 @@ PYBIND11_MODULE(ActsPluginsPythonBindingsDetray, detray) { .def_readwrite("convertSurfaceGrids", &DetrayGeometryConverter::Config::convertSurfaceGrids); - using DetrayGeometryODD = - DetrayGeometryConverter::DetrayGeometry; - py::class_(geometryConverter, "DetrayGeometry") - .def_readonly("detector", &DetrayGeometryODD::detector) - .def_readonly("names", &DetrayGeometryODD::names) - .def_readonly("detrayToSurfaceMap", - &DetrayGeometryODD::detrayToSurfaceMap) - .def_readonly("trackingGeometry", &DetrayGeometryODD::trackingGeometry); + // Register the per-metadata detector and conversion-result types. + auto registerMetadata = [&](auto metadataTag, const std::string& suffix) { + using Metadata = typename decltype(metadataTag)::type; + using Detector = detray::detector; + using Geometry = DetrayGeometryConverter::DetrayGeometry; + + py::class_>( + detray, ("DetrayDetector" + suffix).c_str()) + .def("volumes", [](Detector& self) { return self.volumes(); }) + .def("surfaces", [](Detector& self) { return self.surfaces(); }) + .def("checkConsistency", + [](Detector& self) { checkDetrayConsistency(self); }) + .def("writeToJson", + [](Detector& self, const detray::name_map& names, + const std::string& fname) { + writeDetrayJson(self, names, fname); + }); + + py::class_(geometryConverter, ("DetrayGeometry" + suffix).c_str()) + .def_readonly("detector", &Geometry::detector) + .def_readonly("names", &Geometry::names) + .def_readonly("detrayToSurfaceMap", &Geometry::detrayToSurfaceMap) + .def_readonly("trackingGeometry", &Geometry::trackingGeometry); + }; + + registerMetadata(std::type_identity{}, "ODD"); + registerMetadata(std::type_identity{}, "Default"); geometryConverter .def(py::init([](DetrayGeometryConverter::Config config, @@ -161,12 +173,24 @@ PYBIND11_MODULE(ActsPluginsPythonBindingsDetray, detray) { "config"_a, "level"_a = Acts::Logging::INFO) .def( "convert", - [](const DetrayGeometryConverter& self, vecmem::memory_resource& mr, - const Acts::GeometryContext& gctx, - std::shared_ptr trackingGeometry, - const std::string& detectorName) { - return self.convert( - mr, gctx, std::move(trackingGeometry), detectorName); + [oddType = py::object(oddMetadata), + defaultType = py::object(defaultMetadata)]( + const DetrayGeometryConverter& self, py::object metadata, + vecmem::memory_resource& mr, const Acts::GeometryContext& gctx, + std::shared_ptr trackingGeometry, + const std::string& detectorName) -> py::object { + if (metadata.is(oddType)) { + return py::cast(self.convert( + mr, gctx, std::move(trackingGeometry), detectorName)); + } + if (metadata.is(defaultType)) { + return py::cast(self.convert( + mr, gctx, std::move(trackingGeometry), detectorName)); + } + throw std::invalid_argument( + "DetrayGeometryConverter.convert: unsupported metadata; pass " + "one of the metadata markers (e.g. acts.detray.OddMetadata)"); }, - "mr"_a, "gctx"_a, "trackingGeometry"_a, "detectorName"_a = ""); + "metadata"_a, "mr"_a, "gctx"_a, "trackingGeometry"_a, + "detectorName"_a = ""); } From 08157286551640069e924215cba9119dd372975d Mon Sep 17 00:00:00 2001 From: Paul Gessinger Date: Thu, 25 Jun 2026 17:14:47 +0200 Subject: [PATCH 4/6] build: Generate per-operation detray instantiation TUs from CMake Split each per-metadata instantiation into per-operation translation units (convert, consistency check, JSON write, read) to cut peak compile memory, and generate them from CMake via configure_file (gainmatrix pattern) from .cpp.in templates. Reduce the leaking macros to a single ACTS_DETRAY_METADATA_FOR_EACH and move internal-only helpers into a detail namespace. --- Plugins/Detray/CMakeLists.txt | 41 ++++++++++++++++++- .../ActsPlugins/Detray/DetrayDetectorIO.hpp | 38 ++++++++--------- .../ActsPlugins/Detray/DetrayDetectorIO.ipp | 4 +- .../Detray/DetrayGeometryConverter.hpp | 16 +++----- ...rOdd.cpp => DetrayCheckConsistency.cpp.in} | 13 +++--- ...tectorDefault.cpp => DetrayConvert.cpp.in} | 11 ++--- Plugins/Detray/src/DetrayReadDetector.cpp.in | 20 +++++++++ Plugins/Detray/src/DetrayWriteJson.cpp.in | 20 +++++++++ Python/Plugins/src/Detray.cpp | 9 ++-- 9 files changed, 120 insertions(+), 52 deletions(-) rename Plugins/Detray/src/{DetrayDetectorOdd.cpp => DetrayCheckConsistency.cpp.in} (51%) rename Plugins/Detray/src/{DetrayDetectorDefault.cpp => DetrayConvert.cpp.in} (51%) create mode 100644 Plugins/Detray/src/DetrayReadDetector.cpp.in create mode 100644 Plugins/Detray/src/DetrayWriteJson.cpp.in diff --git a/Plugins/Detray/CMakeLists.txt b/Plugins/Detray/CMakeLists.txt index e9b551a4443..85a499d7383 100644 --- a/Plugins/Detray/CMakeLists.txt +++ b/Plugins/Detray/CMakeLists.txt @@ -4,11 +4,48 @@ acts_add_library( src/DetrayPayloadConverter.cpp src/DetrayMaterial.cpp src/DetrayNavigation.cpp - src/DetrayDetectorOdd.cpp - src/DetrayDetectorDefault.cpp ACTS_INCLUDE_FOLDER include/ActsPlugins ) +# ── Per-(metadata, operation) explicit-instantiation translation units ────── +# +# The heavy detray detector operations (convert, consistency check, JSON +# read/write) are explicitly instantiated for the closed set of metadata types, +# one operation per generated translation unit, so that each TU builds a single +# `detector` and stays small and parallel-compilable. Consumers see +# the matching `extern template` declarations and only link these TUs. +# +# Adding a metadata type: add the alias + ACTS_DETRAY_METADATA_FOR_EACH entry in +# include/ActsPlugins/Detray/DetrayMetadata.hpp, then one +# detray_add_metadata_instantiations() call below. +# Adding an operation: add a src/.cpp.in template and its extern-template +# declaration, then list here. +set(_detray_instantiation_operations + DetrayConvert + DetrayCheckConsistency + DetrayWriteJson + DetrayReadDetector +) + +function(detray_add_metadata_instantiations META_NAME META_TYPE) + foreach(op IN LISTS _detray_instantiation_operations) + set(_generated + ${CMAKE_CURRENT_BINARY_DIR}/generated/${op}${META_NAME}.cpp + ) + # @DETRAY_METADATA_TYPE@ is substituted into the template. + set(DETRAY_METADATA_TYPE ${META_TYPE}) + configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/src/${op}.cpp.in + ${_generated} + @ONLY + ) + target_sources(ActsPluginDetray PRIVATE ${_generated}) + endforeach() +endfunction() + +detray_add_metadata_instantiations(Odd ActsPlugins::DetrayMetadata::Odd) +detray_add_metadata_instantiations(Default ActsPlugins::DetrayMetadata::Default) + add_dependencies(ActsPluginDetray detray::core covfie::core vecmem::core) target_include_directories( diff --git a/Plugins/Detray/include/ActsPlugins/Detray/DetrayDetectorIO.hpp b/Plugins/Detray/include/ActsPlugins/Detray/DetrayDetectorIO.hpp index 2e1d131b864..26328ad7b65 100644 --- a/Plugins/Detray/include/ActsPlugins/Detray/DetrayDetectorIO.hpp +++ b/Plugins/Detray/include/ActsPlugins/Detray/DetrayDetectorIO.hpp @@ -17,14 +17,14 @@ #include #include -namespace ActsPlugins { +namespace ActsPlugins::detail { /// @ingroup detray_plugin -/// @brief Per-metadata detray detector operations +/// @brief Per-metadata detray detector operations (internal) /// -/// These are thin wrappers around the heavy detray detector algorithms -/// (consistency checking and JSON I/O). They are member templates over the -/// detray metadata type and are explicitly instantiated (and declared +/// These are thin, internal wrappers around the heavy detray detector +/// algorithms (consistency checking and JSON I/O). They are function templates +/// over the detray metadata type and are explicitly instantiated (and declared /// `extern template`) for the closed set of metadata types, so that the /// expensive detray template trees are compiled only once per metadata in a /// dedicated translation unit instead of in every consumer (Python bindings, @@ -52,23 +52,19 @@ template std::pair, detray::name_map> readDetrayDetector( vecmem::memory_resource& mr, const std::vector& files); -/// Explicit instantiation declarators for the operations of one metadata. -/// @p PREFIX is empty for an instantiation definition or `extern` for a -/// declaration. -#define ACTS_DETRAY_IO_INSTANTIATION(PREFIX, META) \ - PREFIX template void checkDetrayConsistency( \ - const detray::detector&); \ - PREFIX template void writeDetrayJson(const detray::detector&, \ - const detray::name_map&, \ - const std::string&); \ - PREFIX template std::pair, detray::name_map> \ - readDetrayDetector(vecmem::memory_resource&, \ - const std::vector&); - // Suppress implicit instantiation of the operations for the closed set; the -// definitions are emitted in dedicated translation units (see src/). -#define ACTS_DETRAY_EXTERN_IO(META) ACTS_DETRAY_IO_INSTANTIATION(extern, META) +// matching definitions are emitted in generated translation units (see +// CMakeLists.txt). +#define ACTS_DETRAY_EXTERN_IO(META) \ + extern template void checkDetrayConsistency( \ + const detray::detector&); \ + extern template void writeDetrayJson(const detray::detector&, \ + const detray::name_map&, \ + const std::string&); \ + extern template std::pair, detray::name_map> \ + readDetrayDetector(vecmem::memory_resource&, \ + const std::vector&); ACTS_DETRAY_METADATA_FOR_EACH(ACTS_DETRAY_EXTERN_IO) #undef ACTS_DETRAY_EXTERN_IO -} // namespace ActsPlugins +} // namespace ActsPlugins::detail diff --git a/Plugins/Detray/include/ActsPlugins/Detray/DetrayDetectorIO.ipp b/Plugins/Detray/include/ActsPlugins/Detray/DetrayDetectorIO.ipp index 55b8a1515a5..1873a35340c 100644 --- a/Plugins/Detray/include/ActsPlugins/Detray/DetrayDetectorIO.ipp +++ b/Plugins/Detray/include/ActsPlugins/Detray/DetrayDetectorIO.ipp @@ -23,7 +23,7 @@ #include #include -namespace ActsPlugins { +namespace ActsPlugins::detail { template void checkDetrayConsistency(const detray::detector& detector) { @@ -50,4 +50,4 @@ std::pair, detray::name_map> readDetrayDetector( return detray::io::read_detector>(mr, cfg); } -} // namespace ActsPlugins +} // namespace ActsPlugins::detail diff --git a/Plugins/Detray/include/ActsPlugins/Detray/DetrayGeometryConverter.hpp b/Plugins/Detray/include/ActsPlugins/Detray/DetrayGeometryConverter.hpp index acc1932f0ac..f4902abcfaa 100644 --- a/Plugins/Detray/include/ActsPlugins/Detray/DetrayGeometryConverter.hpp +++ b/Plugins/Detray/include/ActsPlugins/Detray/DetrayGeometryConverter.hpp @@ -149,20 +149,14 @@ class DetrayGeometryConverter { std::unique_ptr m_logger; }; -/// Declarator for an explicit (extern) instantiation of @c convert for a -/// given metadata. The leading `template` keyword makes it an explicit -/// instantiation definition; prefix with `extern` for a declaration. -#define ACTS_DETRAY_CONVERT_INSTANTIATION(META) \ - template DetrayGeometryConverter::DetrayGeometry \ +// Suppress implicit instantiation of `convert` for the closed set; the matching +// definitions are emitted in generated translation units (see CMakeLists.txt). +#define ACTS_DETRAY_EXTERN_CONVERT(META) \ + extern template DetrayGeometryConverter::DetrayGeometry \ DetrayGeometryConverter::convert( \ vecmem::memory_resource&, const Acts::GeometryContext&, \ std::shared_ptr, const std::string&) \ - const - -// Suppress implicit instantiation of `convert` for the closed set; the -// definitions are emitted in dedicated translation units (see src/). -#define ACTS_DETRAY_EXTERN_CONVERT(META) \ - extern ACTS_DETRAY_CONVERT_INSTANTIATION(META); + const; ACTS_DETRAY_METADATA_FOR_EACH(ACTS_DETRAY_EXTERN_CONVERT) #undef ACTS_DETRAY_EXTERN_CONVERT diff --git a/Plugins/Detray/src/DetrayDetectorOdd.cpp b/Plugins/Detray/src/DetrayCheckConsistency.cpp.in similarity index 51% rename from Plugins/Detray/src/DetrayDetectorOdd.cpp rename to Plugins/Detray/src/DetrayCheckConsistency.cpp.in index 488e6f53bb3..e4a81c8bf50 100644 --- a/Plugins/Detray/src/DetrayDetectorOdd.cpp +++ b/Plugins/Detray/src/DetrayCheckConsistency.cpp.in @@ -6,15 +6,14 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. -// Per-metadata instantiation of the heavy detray detector code (geometry -// conversion and detector I/O) for the ODD metadata. +// Generated from DetrayCheckConsistency.cpp.in by CMake — do not edit. +// Instantiates checkDetrayConsistency for a single metadata type. #include "ActsPlugins/Detray/DetrayDetectorIO.ipp" -#include "ActsPlugins/Detray/DetrayGeometryConverter.ipp" -namespace ActsPlugins { +namespace ActsPlugins::detail { -ACTS_DETRAY_CONVERT_INSTANTIATION(DetrayMetadata::Odd); -ACTS_DETRAY_IO_INSTANTIATION(, DetrayMetadata::Odd) +template void checkDetrayConsistency<@DETRAY_METADATA_TYPE@>( + const detray::detector<@DETRAY_METADATA_TYPE@>&); -} // namespace ActsPlugins +} // namespace ActsPlugins::detail diff --git a/Plugins/Detray/src/DetrayDetectorDefault.cpp b/Plugins/Detray/src/DetrayConvert.cpp.in similarity index 51% rename from Plugins/Detray/src/DetrayDetectorDefault.cpp rename to Plugins/Detray/src/DetrayConvert.cpp.in index 7fad866ba8c..60067b3ee43 100644 --- a/Plugins/Detray/src/DetrayDetectorDefault.cpp +++ b/Plugins/Detray/src/DetrayConvert.cpp.in @@ -6,15 +6,16 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. -// Per-metadata instantiation of the heavy detray detector code (geometry -// conversion and detector I/O) for the default metadata. +// Generated from DetrayConvert.cpp.in by CMake — do not edit. +// Instantiates DetrayGeometryConverter::convert for a single metadata type. -#include "ActsPlugins/Detray/DetrayDetectorIO.ipp" #include "ActsPlugins/Detray/DetrayGeometryConverter.ipp" namespace ActsPlugins { -ACTS_DETRAY_CONVERT_INSTANTIATION(DetrayMetadata::Default); -ACTS_DETRAY_IO_INSTANTIATION(, DetrayMetadata::Default) +template DetrayGeometryConverter::DetrayGeometry<@DETRAY_METADATA_TYPE@> +DetrayGeometryConverter::convert<@DETRAY_METADATA_TYPE@>( + vecmem::memory_resource&, const Acts::GeometryContext&, + std::shared_ptr, const std::string&) const; } // namespace ActsPlugins diff --git a/Plugins/Detray/src/DetrayReadDetector.cpp.in b/Plugins/Detray/src/DetrayReadDetector.cpp.in new file mode 100644 index 00000000000..e993139cc8b --- /dev/null +++ b/Plugins/Detray/src/DetrayReadDetector.cpp.in @@ -0,0 +1,20 @@ +// This file is part of the ACTS project. +// +// Copyright (C) 2016 CERN for the benefit of the ACTS project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +// Generated from DetrayReadDetector.cpp.in by CMake — do not edit. +// Instantiates readDetrayDetector for a single metadata type. + +#include "ActsPlugins/Detray/DetrayDetectorIO.ipp" + +namespace ActsPlugins::detail { + +template std::pair, detray::name_map> +readDetrayDetector<@DETRAY_METADATA_TYPE@>(vecmem::memory_resource&, + const std::vector&); + +} // namespace ActsPlugins::detail diff --git a/Plugins/Detray/src/DetrayWriteJson.cpp.in b/Plugins/Detray/src/DetrayWriteJson.cpp.in new file mode 100644 index 00000000000..cd21c7fc512 --- /dev/null +++ b/Plugins/Detray/src/DetrayWriteJson.cpp.in @@ -0,0 +1,20 @@ +// This file is part of the ACTS project. +// +// Copyright (C) 2016 CERN for the benefit of the ACTS project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +// Generated from DetrayWriteJson.cpp.in by CMake — do not edit. +// Instantiates writeDetrayJson for a single metadata type. + +#include "ActsPlugins/Detray/DetrayDetectorIO.ipp" + +namespace ActsPlugins::detail { + +template void writeDetrayJson<@DETRAY_METADATA_TYPE@>( + const detray::detector<@DETRAY_METADATA_TYPE@>&, const detray::name_map&, + const std::string&); + +} // namespace ActsPlugins::detail diff --git a/Python/Plugins/src/Detray.cpp b/Python/Plugins/src/Detray.cpp index f6091c294dc..ae103b20b93 100644 --- a/Python/Plugins/src/Detray.cpp +++ b/Python/Plugins/src/Detray.cpp @@ -72,11 +72,12 @@ PYBIND11_MODULE(ActsPluginsPythonBindingsDetray, detray) { py::object metadata, vecmem::memory_resource& mr, const std::vector& files) -> py::object { if (metadata.is(oddType)) { - return py::cast(readDetrayDetector(mr, files)); + return py::cast( + detail::readDetrayDetector(mr, files)); } if (metadata.is(defaultType)) { return py::cast( - readDetrayDetector(mr, files)); + detail::readDetrayDetector(mr, files)); } throw std::invalid_argument( "detray.read: unsupported metadata; pass one of the metadata " @@ -146,11 +147,11 @@ PYBIND11_MODULE(ActsPluginsPythonBindingsDetray, detray) { .def("volumes", [](Detector& self) { return self.volumes(); }) .def("surfaces", [](Detector& self) { return self.surfaces(); }) .def("checkConsistency", - [](Detector& self) { checkDetrayConsistency(self); }) + [](Detector& self) { detail::checkDetrayConsistency(self); }) .def("writeToJson", [](Detector& self, const detray::name_map& names, const std::string& fname) { - writeDetrayJson(self, names, fname); + detail::writeDetrayJson(self, names, fname); }); py::class_(geometryConverter, ("DetrayGeometry" + suffix).c_str()) From cafdae2626207b3778cb89522923a039b77275cf Mon Sep 17 00:00:00 2001 From: Paul Gessinger Date: Thu, 25 Jun 2026 17:36:33 +0200 Subject: [PATCH 5/6] test: Use closed-set metadata in the Detray payload converter test Switch the test to the same closed-set metadata types so it links the extern template definitions instead of instantiating the heavy detray algorithms locally, and drop the svgtools instantiation. --- .../Detray/DetrayPayloadConverterTests.cpp | 89 ++++--------------- 1 file changed, 18 insertions(+), 71 deletions(-) diff --git a/Tests/UnitTests/Plugins/Detray/DetrayPayloadConverterTests.cpp b/Tests/UnitTests/Plugins/Detray/DetrayPayloadConverterTests.cpp index b6f1d935a1c..c0617fbe716 100644 --- a/Tests/UnitTests/Plugins/Detray/DetrayPayloadConverterTests.cpp +++ b/Tests/UnitTests/Plugins/Detray/DetrayPayloadConverterTests.cpp @@ -30,28 +30,23 @@ #include "Acts/Utilities/Logger.hpp" #include "Acts/Visualization/ObjVisualization3D.hpp" #include "ActsPlugins/Detray/DetrayConversionUtils.hpp" +#include "ActsPlugins/Detray/DetrayDetectorIO.hpp" +#include "ActsPlugins/Detray/DetrayGeometryConverter.hpp" +#include "ActsPlugins/Detray/DetrayMetadata.hpp" #include "ActsPlugins/Detray/DetrayPayloadConverter.hpp" #include "ActsTests/CommonHelpers/CylindricalTrackingGeometry.hpp" #include "ActsTests/CommonHelpers/DetectorElementStub.hpp" #include "ActsTests/CommonHelpers/FloatComparisons.hpp" +#include #include #include -#include #include -#include #include -#include -#include #include -#include -#include #include #include -#include -#include -#include #include #include #include @@ -715,72 +710,24 @@ BOOST_AUTO_TEST_CASE(DetrayTrackingGeometryConversionTests) { ofs << out_json.dump(2) << std::endl; } - // Payloads DONE, let's actually build a detray detector from them. + // Payloads DONE, let's actually build a detray detector. We go through the + // geometry converter so this translation unit links the explicitly + // instantiated `convert` for the closed-set Default metadata instead of + // instantiating the detray detector builder/readers here. + DetrayGeometryConverter geoConverter(DetrayGeometryConverter::Config{ + std::make_shared(cfg)}); - using detector_t = - detray::detector>>; + auto detrayGeometry = + geoConverter.convert(mr, gctx, tGeometry); - // build detector - detray::detector_builder detectorBuilder{}; - // (1) geometry - detray::io::geometry_reader::from_payload(detectorBuilder, - detector); + auto& detrayDetector = *detrayGeometry.detector; + const auto& detrayNames = detrayGeometry.names; - detray::io::homogeneous_material_reader::from_payload( - detectorBuilder, homogeneousMaterial); + // Consistency check (explicitly instantiated for the closed set). + ActsPlugins::detail::checkDetrayConsistency(detrayDetector); - detray::io::material_map_reader>:: - from_payload(detectorBuilder, std::move(materialGrids)); - - detray::io::surface_grid_reader, - std::integral_constant>:: - from_payload(detectorBuilder, surfaceGrids); - - detector_t detrayDetector(detectorBuilder.build(mr)); - - // Checks and print - detray::detail::check_consistency(detrayDetector); - - // Helper to convert std::map to detray::name_map - auto toDetrayNameMap = [](const std::map& src) { - detray::name_map result; - for (const auto& [idx, name] : src) { - result.emplace(static_cast(idx), name); - } - return result; - }; - - auto detrayNames = toDetrayNameMap(payloads.names); - - detray::svgtools::illustrator illustrator(detrayDetector, detrayNames); - illustrator.hide_eta_lines(true); - illustrator.show_info(true); - - const auto svg_zr = illustrator.draw_detector(actsvg::views::z_r{}); - actsvg::style::stroke stroke_black = actsvg::style::stroke(); - auto zr_axis = actsvg::draw::x_y_axes("axes", {-250, 250}, {-250, 250}, - stroke_black, "z", "r"); - detray::svgtools::write_svg( - "test_svgtools_detector_zr", - std::initializer_list{zr_axis, svg_zr}); - - const auto svg_xy = illustrator.draw_detector(actsvg::views::x_y{}); - auto xy_axis = actsvg::draw::x_y_axes("axes", {-250, 250}, {-250, 250}, - stroke_black, "x", "y"); - detray::svgtools::write_svg("test_svgtools_detector_xy", { - xy_axis, - svg_xy, - }); - - auto writer_cfg = detray::io::detector_writer_config{} - .format(detray::io::format::json) - .replace_files(true); - - // std::cout << detray::utils::print_detector(detrayDetector, payloads.names) - // << std::endl; - - detray::io::write_detector(detrayDetector, detrayNames, writer_cfg); + // Write the detector to JSON (explicitly instantiated for the closed set). + ActsPlugins::detail::writeDetrayJson(detrayDetector, detrayNames, ""); } BOOST_AUTO_TEST_SUITE_END() From 48a4d11025c2307b76d52c20977370f8de3e7c60 Mon Sep 17 00:00:00 2001 From: Paul Gessinger Date: Mon, 6 Jul 2026 17:25:57 +0200 Subject: [PATCH 6/6] refactor: Move pre-instantiation to Detray itself --- Detray/detectors/CMakeLists.txt | 57 +++++++++ .../detail/detector_io_instantiations.hpp | 29 +++++ .../detray/detectors/detector_io_array.hpp | 80 +++++++++++++ .../detectors/src/DetrayIoInstantiate.cpp.in | 63 ++++++++++ .../detray/io/frontend/detector_assembler.hpp | 89 ++++++++++++++ .../detray/io/frontend/detector_reader.hpp | 5 +- Plugins/Detray/CMakeLists.txt | 44 +------ .../ActsPlugins/Detray/DetrayDetectorIO.hpp | 70 ----------- .../ActsPlugins/Detray/DetrayDetectorIO.ipp | 53 --------- .../Detray/DetrayGeometryConverter.hpp | 103 +++++++++++++---- .../Detray/DetrayGeometryConverter.ipp | 109 ------------------ .../ActsPlugins/Detray/DetrayMetadata.hpp | 41 ------- .../Detray/src/DetrayCheckConsistency.cpp.in | 19 --- Plugins/Detray/src/DetrayConvert.cpp.in | 21 ---- Plugins/Detray/src/DetrayReadDetector.cpp.in | 20 ---- Plugins/Detray/src/DetrayWriteJson.cpp.in | 20 ---- Python/Plugins/src/Detray.cpp | 49 +++++--- .../Detray/DetrayPayloadConverterTests.cpp | 22 ++-- 18 files changed, 449 insertions(+), 445 deletions(-) create mode 100644 Detray/detectors/include/detray/detectors/detail/detector_io_instantiations.hpp create mode 100644 Detray/detectors/include/detray/detectors/detector_io_array.hpp create mode 100644 Detray/detectors/src/DetrayIoInstantiate.cpp.in create mode 100644 Detray/io/include/detray/io/frontend/detector_assembler.hpp delete mode 100644 Plugins/Detray/include/ActsPlugins/Detray/DetrayDetectorIO.hpp delete mode 100644 Plugins/Detray/include/ActsPlugins/Detray/DetrayDetectorIO.ipp delete mode 100644 Plugins/Detray/include/ActsPlugins/Detray/DetrayGeometryConverter.ipp delete mode 100644 Plugins/Detray/include/ActsPlugins/Detray/DetrayMetadata.hpp delete mode 100644 Plugins/Detray/src/DetrayCheckConsistency.cpp.in delete mode 100644 Plugins/Detray/src/DetrayConvert.cpp.in delete mode 100644 Plugins/Detray/src/DetrayReadDetector.cpp.in delete mode 100644 Plugins/Detray/src/DetrayWriteJson.cpp.in diff --git a/Detray/detectors/CMakeLists.txt b/Detray/detectors/CMakeLists.txt index 42fbca5005a..bc624b569c2 100644 --- a/Detray/detectors/CMakeLists.txt +++ b/Detray/detectors/CMakeLists.txt @@ -82,3 +82,60 @@ if(NOT "${DETRAY_GENERATE_METADATA}" STREQUAL "") message(STATUS "Creating metadata: ${GENERATOR}") endforeach() endif() + +# ── Explicit IO instantiations for the array-algebra detectors ────────────── +# +# The heavy detray IO operations (write / read / consistency check / payload +# assembly) are explicitly instantiated for the closed set of shipped metadata +# types bound to the array algebra, one translation unit per metadata, so that +# each `detector>` template tree is compiled exactly once here +# instead of in every consumer. Consumers include detector_io_array.hpp for the +# matching `extern template` declarations and link detray::detector_io_array. +# +# The metadata list mirrors DETRAY_IO_METADATA_FOR_EACH in +# include/detray/detectors/detail/detector_io_instantiations.hpp. +include(detray-compiler-options-cpp) + +set(_detray_io_instantiation_metadata + default_metadata + odd_metadata + toy_metadata + telescope_metadata + wire_chamber_metadata +) + +set(_detray_io_instantiation_sources) +foreach(META IN LISTS _detray_io_instantiation_metadata) + set(DETRAY_META ${META}) + set(_generated + "${CMAKE_CURRENT_BINARY_DIR}/generated/DetrayIoInstantiate_${META}.cpp" + ) + configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/src/DetrayIoInstantiate.cpp.in" + "${_generated}" + @ONLY + ) + list(APPEND _detray_io_instantiation_sources "${_generated}") +endforeach() + +add_library(detray_detector_io_array STATIC ${_detray_io_instantiation_sources}) +add_library(detray::detector_io_array ALIAS detray_detector_io_array) +set_target_properties( + detray_detector_io_array + PROPERTIES EXPORT_NAME detector_io_array +) +target_link_libraries( + detray_detector_io_array + PUBLIC + detray::detectors + detray::io + detray::core_array + detray::algebra_array + vecmem::core +) +add_dependencies(detray_detector_io_array detray_detectors) + +install(TARGETS detray_detector_io_array EXPORT detray-exports) + +unset(_detray_io_instantiation_metadata) +unset(_detray_io_instantiation_sources) diff --git a/Detray/detectors/include/detray/detectors/detail/detector_io_instantiations.hpp b/Detray/detectors/include/detray/detectors/detail/detector_io_instantiations.hpp new file mode 100644 index 00000000000..0876a6bc6fb --- /dev/null +++ b/Detray/detectors/include/detray/detectors/detail/detector_io_instantiations.hpp @@ -0,0 +1,29 @@ +// This file is part of the ACTS project. +// +// Copyright (C) 2016 CERN for the benefit of the ACTS project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#pragma once + +/// X-macro over the closed set of shipped detray metadata types for which the +/// heavy IO operations (write / read / consistency check / payload assembly) +/// are explicitly instantiated. +/// +/// Invoke with a single-argument macro; it is expanded once per metadata name. +/// This is the single source of truth for the closed set and is used both to +/// generate the `extern template` declarations (see @c detector_io_array.hpp) +/// and the matching explicit instantiations (one translation unit per metadata, +/// see detectors/CMakeLists.txt). The algebra plugin is supplied by the +/// including header, so the same list serves every algebra variant. +/// +/// To add a metadata type: add its header and one line here, then add the same +/// name to the CMake instantiation list. +#define DETRAY_IO_METADATA_FOR_EACH(MACRO) \ + MACRO(default_metadata) \ + MACRO(odd_metadata) \ + MACRO(toy_metadata) \ + MACRO(telescope_metadata) \ + MACRO(wire_chamber_metadata) diff --git a/Detray/detectors/include/detray/detectors/detector_io_array.hpp b/Detray/detectors/include/detray/detectors/detector_io_array.hpp new file mode 100644 index 00000000000..2c72c11b56f --- /dev/null +++ b/Detray/detectors/include/detray/detectors/detector_io_array.hpp @@ -0,0 +1,80 @@ +// This file is part of the ACTS project. +// +// Copyright (C) 2016 CERN for the benefit of the ACTS project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#pragma once + +// Extern-template facade for the array-algebra detray detectors. +// +// Including this header opts every shipped `detector>>` into +// the pre-built IO operations: the heavy `write_detector`, `read_detector`, +// `check_consistency` and `assemble_detector` template trees are compiled once +// in the `detray::detector_io_array` library and merely linked here, instead of +// being instantiated in every consumer. +// +// This is the array counterpart of the `detray::io` vs `detray::io_array` +// split: the frontend/core headers cannot carry these declarations themselves +// because they live below the `detectors` layer and cannot name the concrete +// metadata types. Consumers that need a non-shipped metadata or a different +// algebra simply include the frontend headers directly and instantiate on use. + +// Project include(s) +#include "detray/core/detector.hpp" +#include "detray/definitions/algebra.hpp" +#include "detray/detectors/default_metadata.hpp" +#include "detray/detectors/detail/detector_io_instantiations.hpp" +#include "detray/detectors/odd_metadata.hpp" +#include "detray/detectors/telescope_metadata.hpp" +#include "detray/detectors/toy_metadata.hpp" +#include "detray/detectors/wire_chamber_metadata.hpp" +#include "detray/io/frontend/definitions.hpp" +#include "detray/io/frontend/detector_assembler.hpp" +#include "detray/io/frontend/detector_reader.hpp" +#include "detray/io/frontend/detector_writer.hpp" +#include "detray/io/frontend/payloads.hpp" +#include "detray/utils/consistency_checker.hpp" + +// Vecmem include(s) +#include + +// System include(s) +#include +#include + +// clang-format off +#define DETRAY_DETECTOR_IO_EXTERN(META) \ + extern template void detray::io::write_detector< \ + detray::detector>>>( \ + detray::detector>>&, \ + const detray::detector>>::name_map&, \ + detray::io::detector_writer_config&); \ + extern template std::pair< \ + detray::detector>>, \ + detray::detector>>::name_map> \ + detray::io::read_detector< \ + detray::detector>>>( \ + vecmem::memory_resource&, const detray::io::detector_reader_config&); \ + extern template bool detray::detail::check_consistency< \ + detray::detector>>>( \ + const detray::detector>>&, bool, \ + const detray::detector>>::name_map&); \ + extern template detray::detector>> \ + detray::io::assemble_detector< \ + detray::detector>>>( \ + vecmem::memory_resource&, const detray::io::detector_payload&, \ + const detray::io::detector_homogeneous_material_payload*, \ + detray::io::detector_grids_payload< \ + detray::io::surface_material_payload, detray::io::material_id>*, \ + const detray::io::detector_grids_payload*, \ + std::string_view, \ + detray::detector>>::name_map&); +// clang-format on + +DETRAY_IO_METADATA_FOR_EACH(DETRAY_DETECTOR_IO_EXTERN) + +#undef DETRAY_DETECTOR_IO_EXTERN diff --git a/Detray/detectors/src/DetrayIoInstantiate.cpp.in b/Detray/detectors/src/DetrayIoInstantiate.cpp.in new file mode 100644 index 00000000000..ef78cb832f8 --- /dev/null +++ b/Detray/detectors/src/DetrayIoInstantiate.cpp.in @@ -0,0 +1,63 @@ +// This file is part of the ACTS project. +// +// Copyright (C) 2016 CERN for the benefit of the ACTS project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +// Generated from DetrayIoInstantiate.cpp.in by CMake — do not edit. +// +// Explicit instantiation of the heavy detray IO operations for a single +// (metadata, array-algebra) detector. One such translation unit is compiled per +// shipped metadata into the detray::detector_io_array library; consumers see +// the matching `extern template` declarations via detector_io_array.hpp. + +// Project include(s) +#include "detray/core/detector.hpp" +#include "detray/definitions/algebra.hpp" +#include "detray/detectors/@DETRAY_META@.hpp" +#include "detray/io/frontend/definitions.hpp" +#include "detray/io/frontend/detector_assembler.hpp" +#include "detray/io/frontend/detector_reader.hpp" +#include "detray/io/frontend/detector_writer.hpp" +#include "detray/io/frontend/payloads.hpp" +#include "detray/utils/consistency_checker.hpp" + +// Vecmem include(s) +#include + +// System include(s) +#include +#include + +namespace detray { + +using io_detector_t = detector<@DETRAY_META@>>; + +namespace io { + +template void write_detector( + io_detector_t&, const io_detector_t::name_map&, detector_writer_config&); + +template std::pair +read_detector(vecmem::memory_resource&, + const detector_reader_config&); + +template io_detector_t assemble_detector( + vecmem::memory_resource&, const detector_payload&, + const detector_homogeneous_material_payload*, + detector_grids_payload*, + const detector_grids_payload*, std::string_view, + io_detector_t::name_map&); + +} // namespace io + +namespace detail { + +template bool check_consistency(const io_detector_t&, bool, + const io_detector_t::name_map&); + +} // namespace detail + +} // namespace detray diff --git a/Detray/io/include/detray/io/frontend/detector_assembler.hpp b/Detray/io/include/detray/io/frontend/detector_assembler.hpp new file mode 100644 index 00000000000..0d833382a12 --- /dev/null +++ b/Detray/io/include/detray/io/frontend/detector_assembler.hpp @@ -0,0 +1,89 @@ +// This file is part of the ACTS project. +// +// Copyright (C) 2016 CERN for the benefit of the ACTS project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#pragma once + +// Project include(s) +#include "detray/builders/detector_builder.hpp" +#include "detray/io/backend/geometry_reader.hpp" +#include "detray/io/backend/homogeneous_material_reader.hpp" +#include "detray/io/backend/material_map_reader.hpp" +#include "detray/io/backend/surface_grid_reader.hpp" +#include "detray/io/frontend/definitions.hpp" +#include "detray/io/frontend/payloads.hpp" + +// Vecmem include(s) +#include + +// System include(s) +#include +#include +#include +#include + +namespace detray::io { + +/// @brief Assemble a detray detector from its individual IO payloads. +/// +/// This is the payload-driven counterpart of @c read_detector: instead of +/// reading the components from files, it consumes payloads that a client (e.g. +/// the ACTS geometry converter) has produced in memory and drives the detray +/// @c detector_builder to construct the detector. It is a single, extern-able +/// entry point for the otherwise heavy detector-building template tree. +/// +/// @tparam detector_t the type of detector to be built +/// +/// @param mr the memory resource used for the detector container allocations +/// @param geometry the geometry payload (always required) +/// @param homogeneous_material homogeneous material payload, or @c nullptr to +/// skip homogeneous material +/// @param material_grids material map payload (moved-from), or @c nullptr to +/// skip material maps +/// @param surface_grids surface grid payload, or @c nullptr to skip surface +/// grids +/// @param name detector name to set, or empty to leave the builder default +/// @param names filled with the volume/surface name map during the build +/// +/// @returns the assembled detector +template +detector_t assemble_detector( + vecmem::memory_resource& mr, const detector_payload& geometry, + const detector_homogeneous_material_payload* homogeneous_material, + detector_grids_payload* + material_grids, + const detector_grids_payload* surface_grids, + std::string_view name, typename detector_t::name_map& names) { + detector_builder det_builder{}; + + geometry_reader::from_payload(det_builder, geometry); + + if (homogeneous_material != nullptr) { + homogeneous_material_reader::from_payload( + det_builder, *homogeneous_material); + } + + if (material_grids != nullptr) { + material_map_reader>::from_payload< + detector_t>(det_builder, std::move(*material_grids)); + } + + if (surface_grids != nullptr) { + surface_grid_reader, + std::integral_constant>:: + template from_payload(det_builder, *surface_grids); + } + + if (!name.empty()) { + det_builder.set_name(std::string{name}); + } + + return det_builder.build(mr, names); +} + +} // namespace detray::io diff --git a/Detray/io/include/detray/io/frontend/detector_reader.hpp b/Detray/io/include/detray/io/frontend/detector_reader.hpp index 0e4c7319811..338b4f10e79 100644 --- a/Detray/io/include/detray/io/frontend/detector_reader.hpp +++ b/Detray/io/include/detray/io/frontend/detector_reader.hpp @@ -71,8 +71,9 @@ void read_components_from_file(const std::vector& file_names, /// @returns a complete detector object + a map that contains the volume names template class volume_builder_t = volume_builder> -auto read_detector(vecmem::memory_resource& resc, - const detector_reader_config& cfg) noexcept(false) { +std::pair read_detector( + vecmem::memory_resource& resc, + const detector_reader_config& cfg) noexcept(false) { // Map the volume names to their indices typename detector_t::name_map names{}; diff --git a/Plugins/Detray/CMakeLists.txt b/Plugins/Detray/CMakeLists.txt index 85a499d7383..74945d661a5 100644 --- a/Plugins/Detray/CMakeLists.txt +++ b/Plugins/Detray/CMakeLists.txt @@ -7,44 +7,11 @@ acts_add_library( ACTS_INCLUDE_FOLDER include/ActsPlugins ) -# ── Per-(metadata, operation) explicit-instantiation translation units ────── -# -# The heavy detray detector operations (convert, consistency check, JSON -# read/write) are explicitly instantiated for the closed set of metadata types, -# one operation per generated translation unit, so that each TU builds a single -# `detector` and stays small and parallel-compilable. Consumers see -# the matching `extern template` declarations and only link these TUs. -# -# Adding a metadata type: add the alias + ACTS_DETRAY_METADATA_FOR_EACH entry in -# include/ActsPlugins/Detray/DetrayMetadata.hpp, then one -# detray_add_metadata_instantiations() call below. -# Adding an operation: add a src/.cpp.in template and its extern-template -# declaration, then list here. -set(_detray_instantiation_operations - DetrayConvert - DetrayCheckConsistency - DetrayWriteJson - DetrayReadDetector -) - -function(detray_add_metadata_instantiations META_NAME META_TYPE) - foreach(op IN LISTS _detray_instantiation_operations) - set(_generated - ${CMAKE_CURRENT_BINARY_DIR}/generated/${op}${META_NAME}.cpp - ) - # @DETRAY_METADATA_TYPE@ is substituted into the template. - set(DETRAY_METADATA_TYPE ${META_TYPE}) - configure_file( - ${CMAKE_CURRENT_SOURCE_DIR}/src/${op}.cpp.in - ${_generated} - @ONLY - ) - target_sources(ActsPluginDetray PRIVATE ${_generated}) - endforeach() -endfunction() - -detray_add_metadata_instantiations(Odd ActsPlugins::DetrayMetadata::Odd) -detray_add_metadata_instantiations(Default ActsPlugins::DetrayMetadata::Default) +# The heavy detray detector operations (detector assembly, consistency check, +# JSON read/write) are explicitly instantiated for the closed set of shipped +# metadata types inside detray itself (see detray::detector_io_array); this +# plugin only links the pre-built symbols and sees the matching `extern +# template` declarations via detray's detector_io_array.hpp. add_dependencies(ActsPluginDetray detray::core covfie::core vecmem::core) @@ -63,6 +30,7 @@ target_link_libraries( detray::core_array detray::io detray::detectors + detray::detector_io_array detray::svgtools detray::test_utils vecmem::core diff --git a/Plugins/Detray/include/ActsPlugins/Detray/DetrayDetectorIO.hpp b/Plugins/Detray/include/ActsPlugins/Detray/DetrayDetectorIO.hpp deleted file mode 100644 index 26328ad7b65..00000000000 --- a/Plugins/Detray/include/ActsPlugins/Detray/DetrayDetectorIO.hpp +++ /dev/null @@ -1,70 +0,0 @@ -// This file is part of the ACTS project. -// -// Copyright (C) 2016 CERN for the benefit of the ACTS project -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at https://mozilla.org/MPL/2.0/. - -#pragma once - -#include "ActsPlugins/Detray/DetrayMetadata.hpp" - -#include -#include -#include - -#include -#include - -namespace ActsPlugins::detail { - -/// @ingroup detray_plugin -/// @brief Per-metadata detray detector operations (internal) -/// -/// These are thin, internal wrappers around the heavy detray detector -/// algorithms (consistency checking and JSON I/O). They are function templates -/// over the detray metadata type and are explicitly instantiated (and declared -/// `extern template`) for the closed set of metadata types, so that the -/// expensive detray template trees are compiled only once per metadata in a -/// dedicated translation unit instead of in every consumer (Python bindings, -/// tests, …). The definitions live in @c DetrayDetectorIO.ipp; experiment code -/// may instantiate them for a custom metadata by including that header. - -/// Check the consistency of a detray detector (throws on inconsistency). -/// @param detector the detray detector to check -template -void checkDetrayConsistency(const detray::detector& detector); - -/// Write a detray detector to JSON file(s). -/// @param detector the detray detector to write -/// @param names the detray volume/surface name map -/// @param path the output path for the JSON file(s) -template -void writeDetrayJson(const detray::detector& detector, - const detray::name_map& names, const std::string& path); - -/// Read a detray detector and its name map from JSON file(s). -/// @param mr the memory resource to build the detector with -/// @param files the JSON file(s) to read -/// @return the built detector together with its name map -template -std::pair, detray::name_map> readDetrayDetector( - vecmem::memory_resource& mr, const std::vector& files); - -// Suppress implicit instantiation of the operations for the closed set; the -// matching definitions are emitted in generated translation units (see -// CMakeLists.txt). -#define ACTS_DETRAY_EXTERN_IO(META) \ - extern template void checkDetrayConsistency( \ - const detray::detector&); \ - extern template void writeDetrayJson(const detray::detector&, \ - const detray::name_map&, \ - const std::string&); \ - extern template std::pair, detray::name_map> \ - readDetrayDetector(vecmem::memory_resource&, \ - const std::vector&); -ACTS_DETRAY_METADATA_FOR_EACH(ACTS_DETRAY_EXTERN_IO) -#undef ACTS_DETRAY_EXTERN_IO - -} // namespace ActsPlugins::detail diff --git a/Plugins/Detray/include/ActsPlugins/Detray/DetrayDetectorIO.ipp b/Plugins/Detray/include/ActsPlugins/Detray/DetrayDetectorIO.ipp deleted file mode 100644 index 1873a35340c..00000000000 --- a/Plugins/Detray/include/ActsPlugins/Detray/DetrayDetectorIO.ipp +++ /dev/null @@ -1,53 +0,0 @@ -// This file is part of the ACTS project. -// -// Copyright (C) 2016 CERN for the benefit of the ACTS project -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at https://mozilla.org/MPL/2.0/. - -#pragma once - -// Implementation of the detray detector operations. Include this header -// (instead of DetrayDetectorIO.hpp) when instantiating the operations for a -// metadata type that is not part of the closed set declared in -// DetrayMetadata.hpp. - -#include "ActsPlugins/Detray/DetrayDetectorIO.hpp" - -#include - -#include -#include -#include -#include -#include - -namespace ActsPlugins::detail { - -template -void checkDetrayConsistency(const detray::detector& detector) { - detray::detail::check_consistency(detector); -} - -template -void writeDetrayJson(const detray::detector& detector, - const detray::name_map& names, const std::string& path) { - auto cfg = detray::io::detector_writer_config{} - .format(detray::io::format::json) - .path(path) - .replace_files(true); - detray::io::write_detector(detector, names, cfg); -} - -template -std::pair, detray::name_map> readDetrayDetector( - vecmem::memory_resource& mr, const std::vector& files) { - auto cfg = detray::io::detector_reader_config{}.do_check(false); - for (const auto& file : files) { - cfg.add_file(file); - } - return detray::io::read_detector>(mr, cfg); -} - -} // namespace ActsPlugins::detail diff --git a/Plugins/Detray/include/ActsPlugins/Detray/DetrayGeometryConverter.hpp b/Plugins/Detray/include/ActsPlugins/Detray/DetrayGeometryConverter.hpp index f4902abcfaa..9e260c75114 100644 --- a/Plugins/Detray/include/ActsPlugins/Detray/DetrayGeometryConverter.hpp +++ b/Plugins/Detray/include/ActsPlugins/Detray/DetrayGeometryConverter.hpp @@ -11,19 +11,22 @@ #include "Acts/Geometry/GeometryContext.hpp" #include "Acts/Geometry/GeometryIdentifier.hpp" #include "Acts/Geometry/TrackingGeometry.hpp" +#include "Acts/Geometry/TrackingVolume.hpp" #include "Acts/Surfaces/Surface.hpp" #include "Acts/Utilities/Logger.hpp" #include "ActsPlugins/Detray/DetrayConversionUtils.hpp" -#include "ActsPlugins/Detray/DetrayMetadata.hpp" #include "ActsPlugins/Detray/DetrayPayloadConverter.hpp" #include #include #include #include +#include #include +#include #include +#include #include namespace ActsPlugins { @@ -38,13 +41,13 @@ namespace ActsPlugins { /// supplying its own configured @c DetrayPayloadConverter instance through the /// @c Config. /// -/// @c convert is a member template over the detray metadata type. It is -/// explicitly instantiated (and declared `extern template`) for the closed set -/// of supported metadata types listed in @ref DetrayMetadata.hpp, so that the -/// heavy detray detector-building code is compiled only once per metadata in a -/// dedicated translation unit. Experiment code may still convert to a custom -/// metadata by including @c DetrayGeometryConverter.ipp and instantiating -/// @c convert with the desired metadata type. +/// @c convert is a member template over the detray metadata type. Its heavy +/// detector-building core lives in detray as @c detray::io::assemble_detector, +/// which is pre-compiled for the shipped metadata types (see detray's +/// @c detector_io_array.hpp), so @c convert itself is thin glue that instantiates +/// cheaply. Experiment code may convert to a custom metadata simply by calling +/// @c convert with the desired metadata type; the detray assembly then +/// instantiates on demand. class DetrayGeometryConverter { public: /// @brief Configuration for the geometry converter @@ -118,10 +121,6 @@ class DetrayGeometryConverter { /// 3. It builds the map from detray surface identifiers back to the source /// surfaces. /// - /// @note The definition lives in @c DetrayGeometryConverter.ipp; for the - /// closed set of metadata types it is `extern template` declared here and - /// instantiated in a dedicated translation unit. - /// /// @return The built detray detector together with its name map, the /// detray->surface map and the source tracking geometry. template @@ -139,9 +138,8 @@ class DetrayGeometryConverter { /// @return a map from detray surface identifiers to the source surfaces template std::unordered_map - buildDetrayToSurfaceMap( - const detector_t& detrayDetector, - const Acts::TrackingGeometry& trackingGeometry) const; + buildDetrayToSurfaceMap(const detector_t& detrayDetector, + const Acts::TrackingGeometry& trackingGeometry) const; Config m_cfg; @@ -149,15 +147,70 @@ class DetrayGeometryConverter { std::unique_ptr m_logger; }; -// Suppress implicit instantiation of `convert` for the closed set; the matching -// definitions are emitted in generated translation units (see CMakeLists.txt). -#define ACTS_DETRAY_EXTERN_CONVERT(META) \ - extern template DetrayGeometryConverter::DetrayGeometry \ - DetrayGeometryConverter::convert( \ - vecmem::memory_resource&, const Acts::GeometryContext&, \ - std::shared_ptr, const std::string&) \ - const; -ACTS_DETRAY_METADATA_FOR_EACH(ACTS_DETRAY_EXTERN_CONVERT) -#undef ACTS_DETRAY_EXTERN_CONVERT +template +DetrayGeometryConverter::DetrayGeometry +DetrayGeometryConverter::convert( + vecmem::memory_resource& mr, const Acts::GeometryContext& gctx, + std::shared_ptr trackingGeometry, + const std::string& detectorName) const { + using detector_t = detray::detector; + + if (trackingGeometry == nullptr) { + throw std::invalid_argument( + "DetrayGeometryConverter: trackingGeometry must not be null"); + } + + // ── Convert TrackingGeometry → detray payloads ────────────────────────── + auto payloads = + m_cfg.payloadConverter->convertTrackingGeometry(gctx, *trackingGeometry); + + // Resolve the detector name (explicit argument wins, else the payload name). + std::string name = detectorName; + if (name.empty() && payloads.names.contains(0)) { + name = payloads.names.at(0); + } + + // ── Build the detray detector from the payloads ───────────────────────── + // The heavy detector-building template tree lives in detray and is + // pre-instantiated for the shipped metadata types (see + // detector_io_array.hpp). + DetrayGeometry result{}; + result.detector = + std::make_shared(detray::io::assemble_detector( + mr, *payloads.detector, + m_cfg.convertMaterial ? payloads.homogeneousMaterial.get() : nullptr, + m_cfg.convertMaterial ? payloads.materialGrids.get() : nullptr, + m_cfg.convertSurfaceGrids ? payloads.surfaceGrids.get() : nullptr, + name, result.names)); + + result.detrayToSurfaceMap = + buildDetrayToSurfaceMap(*result.detector, *trackingGeometry); + result.trackingGeometry = std::move(trackingGeometry); + + return result; +} + +template +std::unordered_map +DetrayGeometryConverter::buildDetrayToSurfaceMap( + const detector_t& detrayDetector, + const Acts::TrackingGeometry& trackingGeometry) const { + std::unordered_map + detrayToSurfaceMap; + + for (const auto& surface : detrayDetector.surfaces()) { + // surface.source is the GeometryIdentifier encoded as uint64 + const Acts::GeometryIdentifier geometryId(surface.source); + const Acts::Surface* surfacePtr = trackingGeometry.findSurface(geometryId); + if (surfacePtr == nullptr || !surfacePtr->isSensitive()) { + continue; // skip portals and passives + } + detrayToSurfaceMap[surface.identifier()] = surfacePtr; + } + + ACTS_INFO("Built detray→surface map with " << detrayToSurfaceMap.size() + << " sensitive surfaces"); + return detrayToSurfaceMap; +} } // namespace ActsPlugins diff --git a/Plugins/Detray/include/ActsPlugins/Detray/DetrayGeometryConverter.ipp b/Plugins/Detray/include/ActsPlugins/Detray/DetrayGeometryConverter.ipp deleted file mode 100644 index cabc0e69033..00000000000 --- a/Plugins/Detray/include/ActsPlugins/Detray/DetrayGeometryConverter.ipp +++ /dev/null @@ -1,109 +0,0 @@ -// This file is part of the ACTS project. -// -// Copyright (C) 2016 CERN for the benefit of the ACTS project -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at https://mozilla.org/MPL/2.0/. - -#pragma once - -// Implementation of the DetrayGeometryConverter::convert member template. -// -// Include this header (instead of DetrayGeometryConverter.hpp) when you need to -// instantiate `convert` for a metadata type that is not part of the closed set -// declared in DetrayMetadata.hpp. - -#include "Acts/Geometry/TrackingVolume.hpp" -#include "ActsPlugins/Detray/DetrayGeometryConverter.hpp" - -#include - -#include -#include -#include -#include -#include - -namespace ActsPlugins { - -template -DetrayGeometryConverter::DetrayGeometry -DetrayGeometryConverter::convert( - vecmem::memory_resource& mr, const Acts::GeometryContext& gctx, - std::shared_ptr trackingGeometry, - const std::string& detectorName) const { - using detector_t = detray::detector; - - if (trackingGeometry == nullptr) { - throw std::invalid_argument( - "DetrayGeometryConverter: trackingGeometry must not be null"); - } - - // ── Convert TrackingGeometry → detray payloads ────────────────────────── - auto payloads = - m_cfg.payloadConverter->convertTrackingGeometry(gctx, *trackingGeometry); - - // ── Build detray detector from payloads ───────────────────────────────── - detray::detector_builder detectorBuilder{}; - - detray::io::geometry_reader::from_payload(detectorBuilder, - *payloads.detector); - - if (m_cfg.convertMaterial) { - detray::io::homogeneous_material_reader::from_payload( - detectorBuilder, *payloads.homogeneousMaterial); - - detray::io::material_map_reader>:: - from_payload(detectorBuilder, - std::move(*payloads.materialGrids)); - } - - if (m_cfg.convertSurfaceGrids) { - detray::io::surface_grid_reader, - std::integral_constant>:: - template from_payload(detectorBuilder, - *payloads.surfaceGrids); - } - - if (!detectorName.empty()) { - detectorBuilder.set_name(detectorName); - } else if (payloads.names.contains(0)) { - detectorBuilder.set_name(payloads.names.at(0)); - } - - DetrayGeometry result{}; - result.detector = - std::make_shared(detectorBuilder.build(mr, result.names)); - result.detrayToSurfaceMap = - buildDetrayToSurfaceMap(*result.detector, *trackingGeometry); - result.trackingGeometry = std::move(trackingGeometry); - - return result; -} - -template -std::unordered_map -DetrayGeometryConverter::buildDetrayToSurfaceMap( - const detector_t& detrayDetector, - const Acts::TrackingGeometry& trackingGeometry) const { - std::unordered_map - detrayToSurfaceMap; - - for (const auto& surface : detrayDetector.surfaces()) { - // surface.source is the GeometryIdentifier encoded as uint64 - const Acts::GeometryIdentifier geometryId(surface.source); - const Acts::Surface* surfacePtr = trackingGeometry.findSurface(geometryId); - if (surfacePtr == nullptr || !surfacePtr->isSensitive()) { - continue; // skip portals and passives - } - detrayToSurfaceMap[surface.identifier()] = surfacePtr; - } - - ACTS_INFO("Built detray→surface map with " << detrayToSurfaceMap.size() - << " sensitive surfaces"); - return detrayToSurfaceMap; -} - -} // namespace ActsPlugins diff --git a/Plugins/Detray/include/ActsPlugins/Detray/DetrayMetadata.hpp b/Plugins/Detray/include/ActsPlugins/Detray/DetrayMetadata.hpp deleted file mode 100644 index a0719c6a206..00000000000 --- a/Plugins/Detray/include/ActsPlugins/Detray/DetrayMetadata.hpp +++ /dev/null @@ -1,41 +0,0 @@ -// This file is part of the ACTS project. -// -// Copyright (C) 2016 CERN for the benefit of the ACTS project -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at https://mozilla.org/MPL/2.0/. - -#pragma once - -#include -#include -#include - -namespace ActsPlugins::DetrayMetadata { - -/// @addtogroup detray_plugin -/// @{ - -/// Metadata for the Open Data Detector -using Odd = detray::odd_metadata>; - -/// Detray's generic default metadata -using Default = detray::default_metadata>; - -/// @} - -} // namespace ActsPlugins::DetrayMetadata - -/// X-macro over the closed set of supported detray metadata types. -/// -/// Invoke with a single-argument macro; it is expanded once per metadata. This -/// is the single source of truth for the closed set and is used to generate the -/// `extern template` declarations of @c DetrayGeometryConverter::convert and the -/// corresponding explicit instantiations (one translation unit per metadata). -/// -/// To add a metadata type, add the alias above and one line here, then create -/// the matching instantiation translation unit. -#define ACTS_DETRAY_METADATA_FOR_EACH(MACRO) \ - MACRO(::ActsPlugins::DetrayMetadata::Odd) \ - MACRO(::ActsPlugins::DetrayMetadata::Default) diff --git a/Plugins/Detray/src/DetrayCheckConsistency.cpp.in b/Plugins/Detray/src/DetrayCheckConsistency.cpp.in deleted file mode 100644 index e4a81c8bf50..00000000000 --- a/Plugins/Detray/src/DetrayCheckConsistency.cpp.in +++ /dev/null @@ -1,19 +0,0 @@ -// This file is part of the ACTS project. -// -// Copyright (C) 2016 CERN for the benefit of the ACTS project -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at https://mozilla.org/MPL/2.0/. - -// Generated from DetrayCheckConsistency.cpp.in by CMake — do not edit. -// Instantiates checkDetrayConsistency for a single metadata type. - -#include "ActsPlugins/Detray/DetrayDetectorIO.ipp" - -namespace ActsPlugins::detail { - -template void checkDetrayConsistency<@DETRAY_METADATA_TYPE@>( - const detray::detector<@DETRAY_METADATA_TYPE@>&); - -} // namespace ActsPlugins::detail diff --git a/Plugins/Detray/src/DetrayConvert.cpp.in b/Plugins/Detray/src/DetrayConvert.cpp.in deleted file mode 100644 index 60067b3ee43..00000000000 --- a/Plugins/Detray/src/DetrayConvert.cpp.in +++ /dev/null @@ -1,21 +0,0 @@ -// This file is part of the ACTS project. -// -// Copyright (C) 2016 CERN for the benefit of the ACTS project -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at https://mozilla.org/MPL/2.0/. - -// Generated from DetrayConvert.cpp.in by CMake — do not edit. -// Instantiates DetrayGeometryConverter::convert for a single metadata type. - -#include "ActsPlugins/Detray/DetrayGeometryConverter.ipp" - -namespace ActsPlugins { - -template DetrayGeometryConverter::DetrayGeometry<@DETRAY_METADATA_TYPE@> -DetrayGeometryConverter::convert<@DETRAY_METADATA_TYPE@>( - vecmem::memory_resource&, const Acts::GeometryContext&, - std::shared_ptr, const std::string&) const; - -} // namespace ActsPlugins diff --git a/Plugins/Detray/src/DetrayReadDetector.cpp.in b/Plugins/Detray/src/DetrayReadDetector.cpp.in deleted file mode 100644 index e993139cc8b..00000000000 --- a/Plugins/Detray/src/DetrayReadDetector.cpp.in +++ /dev/null @@ -1,20 +0,0 @@ -// This file is part of the ACTS project. -// -// Copyright (C) 2016 CERN for the benefit of the ACTS project -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at https://mozilla.org/MPL/2.0/. - -// Generated from DetrayReadDetector.cpp.in by CMake — do not edit. -// Instantiates readDetrayDetector for a single metadata type. - -#include "ActsPlugins/Detray/DetrayDetectorIO.ipp" - -namespace ActsPlugins::detail { - -template std::pair, detray::name_map> -readDetrayDetector<@DETRAY_METADATA_TYPE@>(vecmem::memory_resource&, - const std::vector&); - -} // namespace ActsPlugins::detail diff --git a/Plugins/Detray/src/DetrayWriteJson.cpp.in b/Plugins/Detray/src/DetrayWriteJson.cpp.in deleted file mode 100644 index cd21c7fc512..00000000000 --- a/Plugins/Detray/src/DetrayWriteJson.cpp.in +++ /dev/null @@ -1,20 +0,0 @@ -// This file is part of the ACTS project. -// -// Copyright (C) 2016 CERN for the benefit of the ACTS project -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at https://mozilla.org/MPL/2.0/. - -// Generated from DetrayWriteJson.cpp.in by CMake — do not edit. -// Instantiates writeDetrayJson for a single metadata type. - -#include "ActsPlugins/Detray/DetrayDetectorIO.ipp" - -namespace ActsPlugins::detail { - -template void writeDetrayJson<@DETRAY_METADATA_TYPE@>( - const detray::detector<@DETRAY_METADATA_TYPE@>&, const detray::name_map&, - const std::string&); - -} // namespace ActsPlugins::detail diff --git a/Python/Plugins/src/Detray.cpp b/Python/Plugins/src/Detray.cpp index ae103b20b93..c7274e7e3ff 100644 --- a/Python/Plugins/src/Detray.cpp +++ b/Python/Plugins/src/Detray.cpp @@ -8,9 +8,7 @@ #include "Acts/Geometry/TrackingGeometry.hpp" #include "Acts/Geometry/TrackingVolume.hpp" -#include "ActsPlugins/Detray/DetrayDetectorIO.hpp" #include "ActsPlugins/Detray/DetrayGeometryConverter.hpp" -#include "ActsPlugins/Detray/DetrayMetadata.hpp" #include "ActsPlugins/Detray/DetrayPayloadConverter.hpp" #include "ActsPython/Utilities/Helpers.hpp" #include "ActsPython/Utilities/Macros.hpp" @@ -21,6 +19,8 @@ #include #include +#include +#include #include #include #include @@ -33,6 +33,13 @@ using namespace pybind11::literals; PYBIND11_MODULE(ActsPluginsPythonBindingsDetray, detray) { using namespace ActsPlugins; + // The metadata types the Python bindings expose. These name detray's shipped + // metadata directly; the heavy IO/assembly operations are pre-instantiated + // for them in detray::detector_io_array (pulled in via + // detector_io_array.hpp). + using OddMetadata = detray::odd_metadata>; + using DefaultMetadata = detray::default_metadata>; + // The detray volume/surface name map is the same type for every metadata, so // it is registered exactly once. py::class_(detray, "DetrayNameMap"); @@ -59,9 +66,8 @@ PYBIND11_MODULE(ActsPluginsPythonBindingsDetray, detray) { // Metadata markers for the closed set. These empty classes are passed (as the // class object) to DetrayGeometryConverter.convert to select the metadata, // mirroring the C++ template argument convert. - auto oddMetadata = py::class_(detray, "OddMetadata"); - auto defaultMetadata = - py::class_(detray, "DefaultMetadata"); + auto oddMetadata = py::class_(detray, "OddMetadata"); + auto defaultMetadata = py::class_(detray, "DefaultMetadata"); // Read a pre-built detray detector from JSON file(s). The metadata is // selected by passing one of the metadata markers, mirroring convert. @@ -71,13 +77,19 @@ PYBIND11_MODULE(ActsPluginsPythonBindingsDetray, detray) { defaultType = py::object(defaultMetadata)]( py::object metadata, vecmem::memory_resource& mr, const std::vector& files) -> py::object { + auto cfg = detray::io::detector_reader_config{}.do_check(false); + for (const auto& file : files) { + cfg.add_file(file); + } if (metadata.is(oddType)) { return py::cast( - detail::readDetrayDetector(mr, files)); + detray::io::read_detector>(mr, + cfg)); } if (metadata.is(defaultType)) { return py::cast( - detail::readDetrayDetector(mr, files)); + detray::io::read_detector>( + mr, cfg)); } throw std::invalid_argument( "detray.read: unsupported metadata; pass one of the metadata " @@ -147,12 +159,15 @@ PYBIND11_MODULE(ActsPluginsPythonBindingsDetray, detray) { .def("volumes", [](Detector& self) { return self.volumes(); }) .def("surfaces", [](Detector& self) { return self.surfaces(); }) .def("checkConsistency", - [](Detector& self) { detail::checkDetrayConsistency(self); }) - .def("writeToJson", - [](Detector& self, const detray::name_map& names, - const std::string& fname) { - detail::writeDetrayJson(self, names, fname); - }); + [](Detector& self) { detray::detail::check_consistency(self); }) + .def("writeToJson", [](Detector& self, const detray::name_map& names, + const std::string& fname) { + auto cfg = detray::io::detector_writer_config{} + .format(detray::io::format::json) + .path(fname) + .replace_files(true); + detray::io::write_detector(self, names, cfg); + }); py::class_(geometryConverter, ("DetrayGeometry" + suffix).c_str()) .def_readonly("detector", &Geometry::detector) @@ -161,8 +176,8 @@ PYBIND11_MODULE(ActsPluginsPythonBindingsDetray, detray) { .def_readonly("trackingGeometry", &Geometry::trackingGeometry); }; - registerMetadata(std::type_identity{}, "ODD"); - registerMetadata(std::type_identity{}, "Default"); + registerMetadata(std::type_identity{}, "ODD"); + registerMetadata(std::type_identity{}, "Default"); geometryConverter .def(py::init([](DetrayGeometryConverter::Config config, @@ -181,11 +196,11 @@ PYBIND11_MODULE(ActsPluginsPythonBindingsDetray, detray) { std::shared_ptr trackingGeometry, const std::string& detectorName) -> py::object { if (metadata.is(oddType)) { - return py::cast(self.convert( + return py::cast(self.convert( mr, gctx, std::move(trackingGeometry), detectorName)); } if (metadata.is(defaultType)) { - return py::cast(self.convert( + return py::cast(self.convert( mr, gctx, std::move(trackingGeometry), detectorName)); } throw std::invalid_argument( diff --git a/Tests/UnitTests/Plugins/Detray/DetrayPayloadConverterTests.cpp b/Tests/UnitTests/Plugins/Detray/DetrayPayloadConverterTests.cpp index c0617fbe716..95f88b115e4 100644 --- a/Tests/UnitTests/Plugins/Detray/DetrayPayloadConverterTests.cpp +++ b/Tests/UnitTests/Plugins/Detray/DetrayPayloadConverterTests.cpp @@ -30,9 +30,7 @@ #include "Acts/Utilities/Logger.hpp" #include "Acts/Visualization/ObjVisualization3D.hpp" #include "ActsPlugins/Detray/DetrayConversionUtils.hpp" -#include "ActsPlugins/Detray/DetrayDetectorIO.hpp" #include "ActsPlugins/Detray/DetrayGeometryConverter.hpp" -#include "ActsPlugins/Detray/DetrayMetadata.hpp" #include "ActsPlugins/Detray/DetrayPayloadConverter.hpp" #include "ActsTests/CommonHelpers/CylindricalTrackingGeometry.hpp" #include "ActsTests/CommonHelpers/DetectorElementStub.hpp" @@ -711,23 +709,27 @@ BOOST_AUTO_TEST_CASE(DetrayTrackingGeometryConversionTests) { } // Payloads DONE, let's actually build a detray detector. We go through the - // geometry converter so this translation unit links the explicitly - // instantiated `convert` for the closed-set Default metadata instead of - // instantiating the detray detector builder/readers here. + // geometry converter, whose heavy detector-building core is pre-instantiated + // in detray::detector_io_array for the Default metadata. + using DefaultMetadata = detray::default_metadata>; DetrayGeometryConverter geoConverter(DetrayGeometryConverter::Config{ std::make_shared(cfg)}); auto detrayGeometry = - geoConverter.convert(mr, gctx, tGeometry); + geoConverter.convert(mr, gctx, tGeometry); auto& detrayDetector = *detrayGeometry.detector; const auto& detrayNames = detrayGeometry.names; - // Consistency check (explicitly instantiated for the closed set). - ActsPlugins::detail::checkDetrayConsistency(detrayDetector); + // Consistency check (pre-instantiated in detray::detector_io_array). + detray::detail::check_consistency(detrayDetector); - // Write the detector to JSON (explicitly instantiated for the closed set). - ActsPlugins::detail::writeDetrayJson(detrayDetector, detrayNames, ""); + // Write the detector to JSON (pre-instantiated in detray::detector_io_array). + auto writerCfg = detray::io::detector_writer_config{} + .format(detray::io::format::json) + .path("") + .replace_files(true); + detray::io::write_detector(detrayDetector, detrayNames, writerCfg); } BOOST_AUTO_TEST_SUITE_END()