Skip to content
Merged
Show file tree
Hide file tree
Changes from 61 commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
adb9874
feat: First draft for partial DD4hep Gen3 support
paulgessinger Dec 1, 2025
a201866
feat: Test Gen3 DD4hep code on ODD
paulgessinger Dec 1, 2025
8049c2e
fix: Add missing symbol
paulgessinger Dec 2, 2025
71277c4
fix: dd4hep -> DD4hep on disk
paulgessinger Dec 2, 2025
025fd22
layer helper API and use it
paulgessinger Dec 2, 2025
5d3e065
(sort of) auto detect layer transform if axes are specified
paulgessinger Dec 2, 2025
06252f9
feat: Beampipe maker for blueprint builder
paulgessinger Dec 3, 2025
be303d4
rename addLayer -> makeLayer
paulgessinger Dec 3, 2025
c14bfe3
add flag to LayerHelper whether empty is ok or not
paulgessinger Dec 3, 2025
4d614a7
remove artifact
paulgessinger Dec 3, 2025
9495910
fix beampipe builder and make it build to r=0
paulgessinger Dec 3, 2025
72eca14
fix: Check if cylinder conversion failed
paulgessinger Dec 3, 2025
0886998
Make the layer names use the full path name
tmadlener Dec 4, 2025
5099f94
Use boost join
tmadlener Dec 4, 2025
fccf7cc
api exploration
paulgessinger Dec 3, 2025
889ae13
customizer MUST return shared pointer
paulgessinger Dec 3, 2025
7a07915
Make string separator configurable
tmadlener Dec 12, 2025
cc871fd
Add a very generic makeLayer overload from sensitives
tmadlener Dec 12, 2025
41febbd
api work
paulgessinger Dec 3, 2025
435e175
fixes after rebase
paulgessinger Feb 18, 2026
1730e06
forward format args
paulgessinger Feb 18, 2026
5d63c4c
refactor to tgeo axes
paulgessinger Feb 18, 2026
36d0074
api drafting
paulgessinger Mar 2, 2026
5897123
lots of api drafting
paulgessinger Mar 2, 2026
dc0837c
split into impl file
paulgessinger Mar 3, 2026
0717713
reduce backend concept and api surface
paulgessinger Mar 3, 2026
ca65122
make some useful methods public
paulgessinger Mar 3, 2026
9943cd7
add nodiscard to builder interface methods
paulgessinger Mar 4, 2026
f36755f
api refactor splitting up the multi-duty assemblers into separate ones
paulgessinger Mar 4, 2026
b800850
cc docs update
paulgessinger Mar 5, 2026
32c8902
improve ODD for illustrative purposes
paulgessinger Mar 5, 2026
1d61ef5
centralize constant lookup
paulgessinger Mar 5, 2026
50509e6
clean up: add plane layer helper
Dec 11, 2025
3db5273
layerType check
Dec 12, 2025
8782d98
Make customizers more generic
tmadlener Mar 9, 2026
da66d9e
Add first facilities for handling Plane Layers
tmadlener Mar 9, 2026
7f0f981
Remove old code from original API design
tmadlener Mar 9, 2026
6b93d84
Remove some unnecessary / leftover changes
tmadlener Mar 10, 2026
3d55aef
blueprintbuilder impl tuning
paulgessinger Mar 16, 2026
a22d0cc
move odd construction to free funcs in core
paulgessinger Mar 11, 2026
d47bf1f
docs update
paulgessinger Mar 16, 2026
03400e2
lint
paulgessinger Mar 18, 2026
8ad5eab
feat(DD4hep/Root): add initial TGeo blueprint backend and ODD harness
paulgessinger Mar 18, 2026
18369ff
refactor(Root): make the TGeo blueprint backend lazy and path-derived
paulgessinger Mar 18, 2026
6da9887
refactor(DD4hep/TGeo): move beampipe handling to DD4hep and simplify …
paulgessinger Mar 18, 2026
8f3ea24
refactor(Blueprint): make barrel-endcap classification optional for b…
paulgessinger Mar 18, 2026
9c07ddc
fix(DD4hep): use stable grouped layer names and align Gen3 geometry c…
paulgessinger Mar 20, 2026
5b71e0b
fix(TGeo ODD): expose volume metadata in Python and match Gen3 counts
paulgessinger Mar 20, 2026
dd813f3
dd4hep: make TGeo layer customization self-contained
paulgessinger Mar 20, 2026
436497e
prepare for tgeo backend
paulgessinger Mar 20, 2026
91da175
include tuning, namespaces
paulgessinger Mar 20, 2026
0f8d33b
drop tgeo related constants
paulgessinger Mar 27, 2026
f5a5d1a
format
paulgessinger Mar 27, 2026
45bdb2f
add doc comments
paulgessinger Mar 27, 2026
415df04
fix compiler warnings
paulgessinger Mar 27, 2026
8bfd6a8
another clang-tidy fix
paulgessinger Mar 27, 2026
cc30da3
fix test expectations
paulgessinger Mar 28, 2026
43a807c
lint
paulgessinger Mar 30, 2026
4b8519f
clang-format is drunk
paulgessinger Mar 30, 2026
e45963f
even more drunk?
paulgessinger Mar 31, 2026
9b3d65c
PR feedback
paulgessinger Apr 13, 2026
9ebb193
fix alias for gcc
paulgessinger Apr 13, 2026
acc0103
sonar lints
paulgessinger Apr 14, 2026
30250ef
another sonar fix
paulgessinger Apr 14, 2026
e637a74
Merge branch 'main' into feat/dd4hep-gen3
kodiakhq[bot] Apr 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,198 changes: 1,198 additions & 0 deletions Core/include/Acts/Geometry/BlueprintBuilder.hpp

Large diffs are not rendered by default.

881 changes: 881 additions & 0 deletions Core/include/Acts/Geometry/detail/BlueprintBuilder_impl.hpp

Large diffs are not rendered by default.

61 changes: 61 additions & 0 deletions Core/include/Acts/Utilities/FunctionComposition.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// 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 <functional>
#include <utility>

namespace Acts {

namespace detail {

/// @brief Base case: apply a single function to a value.
/// @param x The input value
/// @param f The function to apply
/// @return The result of invoking @p f with @p x
template <typename T, typename F>
decltype(auto) applyRight(T&& x, const F& f) {
return std::invoke(f, std::forward<T>(x));
}

/// @brief Recursive case: apply the last function first, then fold right.
/// @param x The input value
/// @param f The outermost function to apply last
/// @param rest The remaining functions, applied right-to-left
/// @return The result of the right-to-left function chain
template <typename T, typename F, typename... Rest>
decltype(auto) applyRight(T&& x, const F& f, const Rest&... rest) {
return std::invoke(f, applyRight(std::forward<T>(x), rest...));
}

} // namespace detail

/// @brief Compose multiple callables into a single callable, applied
/// right-to-left (mathematical convention).
///
/// Given `compose(f, g, h)`, the returned callable computes `f(g(h(x)))`.
/// All callables are stored exactly once in a tuple, avoiding the nested-copy
/// overhead of a recursive lambda approach.
///
/// @tparam Fs The callable types
/// @param fs The callables to compose
/// @return A callable that applies @p fs right-to-left
template <typename... Fs>
auto compose(Fs&&... fs) {
return [tup = std::make_tuple(std::forward<Fs>(fs)...)]<typename T>(
T&& x) -> decltype(auto) {
return std::apply(
[&](const auto&... fns) -> decltype(auto) {
return detail::applyRight(std::forward<T>(x), fns...);
},
tup);
};
}

} // namespace Acts
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,55 @@

#pragma once

#include "Acts/Geometry/Extent.hpp"
#include "Acts/Utilities/AxisDefinitions.hpp"
#include "ActsExamples/DD4hepDetector/DD4hepDetector.hpp"

namespace Acts {
class GeometryContext;
}

namespace ActsPlugins {
class DD4hepDetectorElement;
}

namespace ActsExamples {

class OpenDataDetector final : public DD4hepDetectorBase {
public:
struct Config : public DD4hepDetectorBase::Config {};
struct Config : public DD4hepDetectorBase::Config {
enum class ConstructionMethod {
BarrelEndcap,
DirectLayer,
DirectLayerGrouped
};

using ElementFactory =
std::function<std::shared_ptr<ActsPlugins::DD4hepDetectorElement>(
const dd4hep::DetElement& element, ActsPlugins::TGeoAxes axes,
double scale)>;

ElementFactory detectorElementFactory = defaultDetectorElementFactory;

/// Select the conversion style used to construct the Gen3 ODD geometry.
ConstructionMethod constructionMethod = ConstructionMethod::BarrelEndcap;

/// Envelope for the blueprint root (world volume). Values in mm.
Acts::ExtentEnvelope blueprintEnvelope =
Acts::ExtentEnvelope::Zero()
.set(Acts::AxisDirection::AxisZ, {20., 20.})
.set(Acts::AxisDirection::AxisR, {0., 20.});

/// Envelope for layer volumes. Values in mm.
Acts::ExtentEnvelope layerEnvelope =
Acts::ExtentEnvelope::Zero()
.set(Acts::AxisDirection::AxisZ, {2., 2.})
.set(Acts::AxisDirection::AxisR, {2., 2.});
};

static std::shared_ptr<ActsPlugins::DD4hepDetectorElement>
defaultDetectorElementFactory(const dd4hep::DetElement& element,
ActsPlugins::TGeoAxes axes, double scale);

explicit OpenDataDetector(const Config& cfg,
const Acts::GeometryContext& gctx);
Expand All @@ -28,6 +66,18 @@ class OpenDataDetector final : public DD4hepDetectorBase {
private:
void construct(const Acts::GeometryContext& gctx);

/// Construction path using BarrelEndcapAssembler (wraps
/// ElementLayerAssembler).
void constructBarrelEndcap(const Acts::GeometryContext& gctx);

/// Construction path using ElementLayerAssembler directly. For illustration.
void constructDirectLayer(const Acts::GeometryContext& gctx);

/// Construction path using SensorLayerAssembler with groupBy. For
/// illustration: sensors are collected directly and grouped by walking the
/// parent chain to find the enclosing layer element.
void constructDirectLayerGrouped(const Acts::GeometryContext& gctx);

Config m_cfg;
};

Expand Down
51 changes: 28 additions & 23 deletions Examples/Detectors/DD4hepDetector/src/OpenDataDetector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,42 +8,47 @@

#include "ActsExamples/DD4hepDetector/OpenDataDetector.hpp"

#include "Acts/Geometry/Blueprint.hpp"
#include "Acts/Geometry/BlueprintOptions.hpp"
#include "Acts/Geometry/CylinderVolumeBounds.hpp"
#include "ActsPlugins/DD4hep/DD4hepDetectorElement.hpp"
#include "ActsPlugins/DD4hep/OpenDataDetectorBuilder.hpp"
#include "ActsPlugins/Root/TGeoAxes.hpp"

#include <memory>

namespace ActsExamples {

OpenDataDetector::OpenDataDetector(const Config& cfg,
const Acts::GeometryContext& gctx)
: DD4hepDetectorBase{cfg}, m_cfg{cfg} {
ACTS_INFO("OpenDataDetector construct");
construct(gctx);
switch (m_cfg.constructionMethod) {
case Config::ConstructionMethod::BarrelEndcap:
m_trackingGeometry =
ActsPlugins::DD4hep::buildOpenDataDetectorBarrelEndcap(
dd4hepDetector(), gctx, logger());
break;
case Config::ConstructionMethod::DirectLayer:
m_trackingGeometry =
ActsPlugins::DD4hep::buildOpenDataDetectorDirectLayer(
dd4hepDetector(), gctx, logger());
break;
case Config::ConstructionMethod::DirectLayerGrouped:
m_trackingGeometry =
ActsPlugins::DD4hep::buildOpenDataDetectorDirectLayerGrouped(
dd4hepDetector(), gctx, logger());
break;
}
}

auto OpenDataDetector::config() const -> const Config& {
return m_cfg;
}

void OpenDataDetector::construct(const Acts::GeometryContext& gctx) {
using namespace Acts::Experimental;
using namespace Acts;
using namespace Acts::UnitLiterals;

Blueprint::Config cfg;
cfg.envelope[AxisDirection::AxisZ] = {20_mm, 20_mm};
cfg.envelope[AxisDirection::AxisR] = {0_mm, 20_mm};
Blueprint root{cfg};

auto volBounds = std::make_shared<CylinderVolumeBounds>(0_mm, 100_mm, 1_m);
auto vol =
std::make_unique<TrackingVolume>(Transform3::Identity(), volBounds);

root.addStaticVolume(std::move(vol));

BlueprintOptions options;

m_trackingGeometry = root.construct(options, gctx, logger());
std::shared_ptr<ActsPlugins::DD4hepDetectorElement>
OpenDataDetector::defaultDetectorElementFactory(
const dd4hep::DetElement& element, ActsPlugins::TGeoAxes axes,
double scale) {
return std::make_shared<ActsPlugins::DD4hepDetectorElement>(element, axes,
scale);
}

} // namespace ActsExamples
11 changes: 8 additions & 3 deletions Examples/Scripts/Python/geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,15 @@ def runGeometry(
writer.write(context)

if outputObj:
writer = ObjTrackingGeometryWriter(
level=acts.logging.INFO, outputDir=outputDir / "obj"
vis = acts.ObjVisualization3D()
trackingGeometry.visualize(
vis,
context.geoContext,
portalViewConfig=acts.ViewConfig(visible=False),
sensitiveViewConfig=acts.ViewConfig(visible=True),
viewConfig=acts.ViewConfig(visible=False),
)
writer.write(context, trackingGeometry)
vis.write(outputDir / "obj" / "geometry.obj")

if outputJson:
# if not os.path.isdir(outputDir / "json"):
Expand Down
2 changes: 2 additions & 0 deletions Plugins/DD4hep/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ acts_add_library(
src/DD4hepLayerBuilder.cpp
src/DD4hepVolumeBuilder.cpp
src/DD4hepFieldAdapter.cpp
src/BlueprintBuilder.cpp
src/OpenDataDetectorBuilder.cpp
ACTS_INCLUDE_FOLDER include/ActsPlugins
)

Expand Down
Loading
Loading