Skip to content

Commit ef061c7

Browse files
committed
Clean
1 parent 3a414d3 commit ef061c7

3 files changed

Lines changed: 292 additions & 77 deletions

File tree

‎Detectors/Upgrades/ALICE3/ACTS/include/ALICE3ACTS/Gen3BlueprintBuilder.h‎

Lines changed: 0 additions & 77 deletions
This file was deleted.
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Copyright 2019-2026 CERN and copyright holders of ALICE O2.
2+
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3+
// All rights not expressly granted are reserved.
4+
//
5+
// This software is distributed under the terms of the GNU General Public
6+
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7+
//
8+
// In applying this license CERN does not waive the privileges and immunities
9+
// granted to it by virtue of its status as an Intergovernmental Organization
10+
// or submit itself to any jurisdiction.
11+
12+
///
13+
/// \file TrkTGeoBlueprintBuilder.h
14+
/// \brief Build an ACTS TRK tracking geometry from the TGeo geometry already loaded by O2
15+
///
16+
17+
#ifndef ALICEO2_ALICE3_TRKTGEOBLUEPRINTBUILDER_H
18+
#define ALICEO2_ALICE3_TRKTGEOBLUEPRINTBUILDER_H
19+
20+
#include <string>
21+
22+
#include "Acts/Utilities/Logger.hpp"
23+
#include "ACTSInterface/ITrackingGeometryBuilder.h"
24+
25+
namespace o2::alice3
26+
{
27+
28+
/// First-step automatic ALICE3 builder: TRK sensitive barrel only, no material.
29+
/// The TGeo volume name is a detector-specific selection rule, not a geometry
30+
/// configuration. Positions, shapes, and layer extents come from the live TGeo.
31+
class TrkTGeoBlueprintBuilder : public o2::acts::ITrackingGeometryBuilder
32+
{
33+
public:
34+
struct Config {
35+
std::string graphvizFile;
36+
Acts::Logging::Level logLevel = Acts::Logging::INFO;
37+
};
38+
39+
TrkTGeoBlueprintBuilder();
40+
explicit TrkTGeoBlueprintBuilder(Config config);
41+
o2::acts::TrackingGeometryOutput build(TGeoManager& tgeo,
42+
const Acts::GeometryContext& gctx) override;
43+
const char* getName() const override { return "alice3-trk-tgeo"; }
44+
45+
private:
46+
Config mConfig;
47+
};
48+
49+
} // namespace o2::alice3
50+
51+
#endif // ALICEO2_ALICE3_TRKTGEOBLUEPRINTBUILDER_H
Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
// Copyright 2019-2026 CERN and copyright holders of ALICE O2.
2+
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3+
// All rights not expressly granted are reserved.
4+
//
5+
// This software is distributed under the terms of the GNU General Public
6+
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7+
//
8+
// In applying this license CERN does not waive the privileges and immunities
9+
// granted to it by virtue of its status as an Intergovernmental Organization
10+
// or submit itself to any jurisdiction.
11+
12+
///
13+
/// \file TrkTGeoBlueprintBuilder.cxx
14+
/// \brief Minimal, material-free TRK-only geometry builder using O2's live TGeo
15+
///
16+
17+
#include "ALICE3ACTS/TrkTGeoBlueprintBuilder.h"
18+
19+
#include "Acts/Definitions/Units.hpp"
20+
#include "Acts/Geometry/Blueprint.hpp"
21+
#include "Acts/Geometry/BlueprintOptions.hpp"
22+
#include "Acts/Geometry/ContainerBlueprintNode.hpp"
23+
#include "Acts/Geometry/CylinderVolumeBounds.hpp"
24+
#include "Acts/Geometry/GeometryIdentifierBlueprintNode.hpp"
25+
#include "Acts/Geometry/LayerBlueprintNode.hpp"
26+
#include "Acts/Geometry/TrackingVolume.hpp"
27+
#include "Acts/Geometry/VolumeAttachmentStrategy.hpp"
28+
#include "Acts/Geometry/VolumeResizeStrategy.hpp"
29+
#include "Acts/Surfaces/CylinderBounds.hpp"
30+
#include "Acts/Surfaces/Surface.hpp"
31+
#include "ActsPlugins/Root/TGeoAxes.hpp"
32+
#include "ActsPlugins/Root/TGeoDetectorElement.hpp"
33+
#include "ActsPlugins/Root/TGeoLayerBuilder.hpp"
34+
#include "ActsPlugins/Root/TGeoParser.hpp"
35+
36+
#include <algorithm>
37+
#include <cmath>
38+
#include <fstream>
39+
#include <memory>
40+
#include <string>
41+
#include <ranges>
42+
#include <stdexcept>
43+
#include <string_view>
44+
#include <utility>
45+
#include <vector>
46+
47+
#include "TGeoManager.h"
48+
#include "TGeoMatrix.h"
49+
#include "TGeoNode.h"
50+
#include "TGeoVolume.h"
51+
52+
namespace o2::alice3
53+
{
54+
using namespace Acts;
55+
using namespace Acts::Experimental;
56+
using namespace Acts::UnitLiterals;
57+
58+
namespace
59+
{
60+
constexpr double kTGeoToActs = 10.; // cm -> mm
61+
constexpr double kVertexLayerTolerance = 5. * 1_mm;
62+
constexpr double kBarrelLayerTolerance = 15. * 1_mm;
63+
constexpr double kLayerEnvelopeWidth = 2. * 1_mm;
64+
65+
using ElementPtr = std::shared_ptr<ActsPlugins::TGeoDetectorElement>;
66+
using KeyedSurface = std::pair<double, std::shared_ptr<Surface>>;
67+
68+
struct LayerGroup {
69+
double radius = 0.;
70+
std::vector<std::shared_ptr<Surface>> surfaces;
71+
};
72+
73+
std::vector<LayerGroup> clusterLayers(std::vector<KeyedSurface> elements, double tolerance)
74+
{
75+
std::vector<LayerGroup> layers;
76+
if (elements.empty()) {
77+
return layers;
78+
}
79+
80+
std::ranges::sort(elements, {}, &KeyedSurface::first);
81+
LayerGroup group;
82+
double previous = elements.front().first;
83+
double sum = 0.;
84+
85+
for (const auto& [radius, surface] : elements) {
86+
if (!group.surfaces.empty() && radius - previous > tolerance) {
87+
group.radius = sum / group.surfaces.size();
88+
layers.push_back(std::move(group));
89+
group = LayerGroup{};
90+
sum = 0.;
91+
}
92+
group.surfaces.push_back(surface);
93+
sum += radius;
94+
previous = radius;
95+
}
96+
group.radius = sum / group.surfaces.size();
97+
layers.push_back(std::move(group));
98+
return layers;
99+
}
100+
101+
} // namespace
102+
103+
TrkTGeoBlueprintBuilder::TrkTGeoBlueprintBuilder() : TrkTGeoBlueprintBuilder(Config{}) {}
104+
105+
TrkTGeoBlueprintBuilder::TrkTGeoBlueprintBuilder(Config config) : mConfig(std::move(config)) {}
106+
107+
o2::acts::TrackingGeometryOutput TrkTGeoBlueprintBuilder::build(TGeoManager& tgeo,
108+
const Acts::GeometryContext& gctx)
109+
{
110+
ACTS_LOCAL_LOGGER(getDefaultLogger("ALICE3TRKAuto", mConfig.logLevel));
111+
ACTS_INFO("Building ACTS TRK geometry from the live TGeo '" << tgeo.GetName() << "'");
112+
113+
auto* topVolume = tgeo.GetTopVolume();
114+
if (!topVolume) {
115+
throw std::runtime_error("ALICE3 TRK: no top volume in the loaded TGeo geometry");
116+
}
117+
118+
// TGeoParser selects the placed TRK sensitive nodes, including the VD
119+
// PETALCASE surfaces. Avoid parsing every support/passive simulation volume.
120+
ActsPlugins::TGeoParser::Options options;
121+
options.volumeNames = {topVolume->GetName()};
122+
options.targetNames = {"*TRKSensor*"};
123+
options.unit = kTGeoToActs;
124+
125+
ActsPlugins::TGeoParser::State state;
126+
state.volume = topVolume;
127+
state.onBranch = true;
128+
TGeoHMatrix transform = TGeoIdentity(topVolume->GetName());
129+
ActsPlugins::TGeoParser::select(state, options, transform);
130+
131+
if (state.selectedNodes.empty()) {
132+
throw std::runtime_error("ALICE3 TRK: no TRK sensitive TGeo nodes found (*TRKSensor*)");
133+
}
134+
135+
const auto thinY = ActsPlugins::TGeoAxes::parse("ZXY");
136+
const auto thinZ = ActsPlugins::TGeoAxes::parse("XYZ");
137+
std::vector<ElementPtr> elements;
138+
std::vector<KeyedSurface> vertexSurfaces;
139+
std::vector<KeyedSurface> barrelSurfaces;
140+
elements.reserve(state.selectedNodes.size());
141+
142+
for (const auto& snode : state.selectedNodes) {
143+
const std::string_view name = snode.node->GetVolume()->GetName();
144+
const bool vertex = name.find("PETALCASE") != std::string_view::npos;
145+
const auto axes = vertex ? thinZ : thinY;
146+
147+
auto element = ActsPlugins::TGeoLayerBuilder::defaultElementFactory(
148+
ActsPlugins::TGeoDetectorElement::Identifier{}, *snode.node,
149+
*snode.transform, axes, kTGeoToActs, nullptr);
150+
auto surface = element->surface().getSharedPtr();
151+
152+
if (vertex && surface->type() != Surface::SurfaceType::Cylinder) {
153+
throw std::runtime_error("ALICE3 TRK: expected a cylindrical vertex-detector sensor: " + std::string(name));
154+
}
155+
// TRK is a barrel detector. A misidentified forward surface must not
156+
// silently enter a cylindrical layer and break ACTS navigation.
157+
const auto center = surface->center(gctx);
158+
const double radius = (surface->type() == Surface::SurfaceType::Cylinder)
159+
? surface->bounds().values()[CylinderBounds::eR]
160+
: std::hypot(center.x(), center.y());
161+
if (!vertex) {
162+
const auto normal = surface->normal(gctx, center, Vector3::UnitZ());
163+
if (std::abs(normal.z()) > 0.7) {
164+
throw std::runtime_error("ALICE3 TRK: a non-barrel surface matched *TRKSensor*: " + std::string(name));
165+
}
166+
}
167+
168+
(vertex ? vertexSurfaces : barrelSurfaces).emplace_back(radius, std::move(surface));
169+
elements.push_back(std::move(element));
170+
}
171+
172+
auto layers = clusterLayers(std::move(vertexSurfaces), kVertexLayerTolerance);
173+
auto barrelLayers = clusterLayers(std::move(barrelSurfaces), kBarrelLayerTolerance);
174+
for (auto& layer : barrelLayers) {
175+
layers.push_back(std::move(layer));
176+
}
177+
std::ranges::sort(layers, {}, &LayerGroup::radius);
178+
179+
if (layers.empty()) {
180+
throw std::runtime_error("ALICE3 TRK: no barrel layers found in the loaded TGeo");
181+
}
182+
ACTS_INFO("Found " << elements.size() << " sensors in " << layers.size() << " TRK layers");
183+
for (std::size_t i = 0; i < layers.size(); ++i) {
184+
ACTS_INFO(" TRK layer " << i << ": R=" << layers[i].radius / 1_mm
185+
<< " mm, sensors=" << layers[i].surfaces.size());
186+
}
187+
188+
Blueprint::Config config;
189+
// Enlarge the inner world radius to include the beamline (r = 0).
190+
const double innerEnvelope = layers.front().radius + 20. * 1_mm;
191+
config.envelope = ExtentEnvelope{{.z = {20. * 1_mm, 20. * 1_mm},
192+
.r = {innerEnvelope, 20. * 1_mm}}};
193+
Blueprint root{config};
194+
auto& ids = root.withGeometryIdentifier();
195+
const auto byRadius = [](const TrackingVolume& a, const TrackingVolume& b) {
196+
const auto midRadius = [](const TrackingVolume& volume) {
197+
const auto& bounds = dynamic_cast<const CylinderVolumeBounds&>(volume.volumeBounds());
198+
return 0.5 * (bounds.get(CylinderVolumeBounds::eMinR) + bounds.get(CylinderVolumeBounds::eMaxR));
199+
};
200+
return midRadius(a) < midRadius(b);
201+
};
202+
// One self-contained TRK region. IDs are deterministic within this builder,
203+
// but they are NOT compatible with the full-detector geometry/material map.
204+
ids.setAllVolumeIdsTo(40).incrementLayerIds(1).sortBy(byRadius);
205+
auto& barrel = ids.addCylinderContainer("TRKBarrel", AxisDirection::AxisR);
206+
barrel.setAttachmentStrategy(VolumeAttachmentStrategy::Gap);
207+
barrel.setResizeStrategies(VolumeResizeStrategy::Gap, VolumeResizeStrategy::Gap);
208+
209+
const ExtentEnvelope layerEnvelope = ExtentEnvelope{{.z = {kLayerEnvelopeWidth, kLayerEnvelopeWidth},
210+
.r = {kLayerEnvelopeWidth, kLayerEnvelopeWidth}}};
211+
for (std::size_t i = 0; i < layers.size(); ++i) {
212+
barrel.addLayer("TRKBarrel_L" + std::to_string(i), [&layers, &layerEnvelope, i](LayerBlueprintNode& node) {
213+
node.setSurfaces(layers[i].surfaces);
214+
node.setLayerType(LayerBlueprintNode::LayerType::Cylinder);
215+
node.setEnvelope(layerEnvelope);
216+
node.setUseCenterOfGravity(false, false, true);
217+
});
218+
}
219+
220+
if (!mConfig.graphvizFile.empty()) {
221+
std::ofstream out(mConfig.graphvizFile);
222+
if (!out) {
223+
throw std::runtime_error("ALICE3 TRK: cannot write Graphviz file: " + mConfig.graphvizFile);
224+
}
225+
root.graphviz(out);
226+
}
227+
228+
BlueprintOptions opts;
229+
auto trackingGeometry = root.construct(opts, gctx, logger());
230+
231+
o2::acts::TrackingGeometryOutput output;
232+
output.elementStore.reserve(elements.size());
233+
for (const auto& element : elements) {
234+
output.elementStore.push_back(element);
235+
}
236+
output.geometry = std::shared_ptr<Acts::TrackingGeometry>(std::move(trackingGeometry));
237+
ACTS_INFO("ACTS TRK geometry constructed from the loaded TGeo");
238+
return output;
239+
}
240+
241+
} // namespace o2::alice3

0 commit comments

Comments
 (0)