108 const Acts::GeometryContext& gctx)
110 ACTS_LOCAL_LOGGER(getDefaultLogger(
"ALICE3TRKAuto", mConfig.
logLevel));
111 ACTS_INFO(
"Building ACTS TRK geometry from the live TGeo '" << tgeo.GetName() <<
"'");
113 auto* topVolume = tgeo.GetTopVolume();
115 throw std::runtime_error(
"ALICE3 TRK: no top volume in the loaded TGeo geometry");
120 ActsPlugins::TGeoParser::Options options;
121 options.volumeNames = {topVolume->GetName()};
122 options.targetNames = {
"*TRKSensor*"};
123 options.unit = kTGeoToActs;
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);
131 if (
state.selectedNodes.empty()) {
132 throw std::runtime_error(
"ALICE3 TRK: no TRK sensitive TGeo nodes found (*TRKSensor*)");
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());
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;
147 auto element = ActsPlugins::TGeoLayerBuilder::defaultElementFactory(
148 ActsPlugins::TGeoDetectorElement::Identifier{}, *snode.node,
149 *snode.transform, axes, kTGeoToActs,
nullptr);
152 if (
vertex &&
surface->type() != Surface::SurfaceType::Cylinder) {
153 throw std::runtime_error(
"ALICE3 TRK: expected a cylindrical vertex-detector sensor: " + std::string(
name));
158 const double radius = (
surface->type() == Surface::SurfaceType::Cylinder)
159 ?
surface->bounds().values()[CylinderBounds::eR]
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));
169 elements.push_back(std::move(
element));
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));
177 std::ranges::sort(layers, {}, &LayerGroup::radius);
179 if (layers.empty()) {
180 throw std::runtime_error(
"ALICE3 TRK: no barrel layers found in the loaded TGeo");
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());
188 Blueprint::Config config;
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));
200 return midRadius(
a) < midRadius(
b);
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);
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) {
214 node.setLayerType(LayerBlueprintNode::LayerType::Cylinder);
215 node.setEnvelope(layerEnvelope);
216 node.setUseCenterOfGravity(
false,
false,
true);
223 throw std::runtime_error(
"ALICE3 TRK: cannot write Graphviz file: " + mConfig.
graphvizFile);
228 BlueprintOptions opts;
229 auto trackingGeometry = root.construct(opts, gctx, logger());
233 for (
const auto&
element : elements) {
236 output.geometry = std::shared_ptr<Acts::TrackingGeometry>(std::move(trackingGeometry));
237 ACTS_INFO(
"ACTS TRK geometry constructed from the loaded TGeo");