File indexing completed on 2026-05-15 07:39:01
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "ActsExamples/TGeoDetector/TGeoDetector.hpp"
0010
0011 #include "Acts/Geometry/CylinderVolumeBuilder.hpp"
0012 #include "Acts/Geometry/CylinderVolumeHelper.hpp"
0013 #include "Acts/Geometry/GeometryContext.hpp"
0014 #include "Acts/Geometry/ITrackingVolumeBuilder.hpp"
0015 #include "Acts/Geometry/LayerArrayCreator.hpp"
0016 #include "Acts/Geometry/LayerCreator.hpp"
0017 #include "Acts/Geometry/PassiveLayerBuilder.hpp"
0018 #include "Acts/Geometry/ProtoLayerHelper.hpp"
0019 #include "Acts/Geometry/SurfaceArrayCreator.hpp"
0020 #include "Acts/Geometry/SurfaceBinningMatcher.hpp"
0021 #include "Acts/Geometry/TrackingGeometry.hpp"
0022 #include "Acts/Geometry/TrackingGeometryBuilder.hpp"
0023 #include "Acts/Geometry/TrackingVolumeArrayCreator.hpp"
0024 #include "Acts/Surfaces/SurfacePlacementBase.hpp"
0025 #include "Acts/Utilities/Logger.hpp"
0026 #include "ActsExamples/TGeoDetector/JsonTGeoDetectorConfig.hpp"
0027 #include "ActsExamples/TGeoDetector/TGeoITkModuleSplitter.hpp"
0028 #include "ActsPlugins/Root/TGeoCylinderDiscSplitter.hpp"
0029 #include "ActsPlugins/Root/TGeoLayerBuilder.hpp"
0030
0031 #include <algorithm>
0032 #include <array>
0033 #include <fstream>
0034 #include <limits>
0035 #include <list>
0036 #include <optional>
0037 #include <utility>
0038
0039 #include <boost/program_options.hpp>
0040 #include <nlohmann/json.hpp>
0041
0042 #include "TGeoManager.h"
0043
0044 using namespace Acts;
0045 using namespace ActsPlugins;
0046
0047 namespace ActsExamples {
0048
0049 namespace {
0050
0051
0052
0053
0054
0055
0056 std::vector<ActsPlugins::TGeoLayerBuilder::Config> makeLayerBuilderConfigs(
0057 const TGeoDetector::Config& config, const Logger& logger) {
0058 std::vector<ActsPlugins::TGeoLayerBuilder::Config> detLayerConfigs;
0059
0060
0061 for (const auto& volume : config.volumes) {
0062 ActsPlugins::TGeoLayerBuilder::Config layerBuilderConfig;
0063 layerBuilderConfig.configurationName = volume.name;
0064 layerBuilderConfig.unit = config.unitScalor;
0065 layerBuilderConfig.detectorElementFactory = config.detectorElementFactory;
0066
0067
0068 std::vector<std::pair<double, double>> binTolerances(numAxisDirections(),
0069 {0., 0.});
0070 binTolerances[toUnderlying(AxisDirection::AxisR)] = {
0071 volume.binToleranceR.lower.value_or(0.),
0072 volume.binToleranceR.upper.value_or(0.)};
0073 binTolerances[toUnderlying(AxisDirection::AxisZ)] = {
0074 volume.binToleranceZ.lower.value_or(0.),
0075 volume.binToleranceZ.upper.value_or(0.)};
0076 binTolerances[toUnderlying(AxisDirection::AxisPhi)] = {
0077 volume.binTolerancePhi.lower.value_or(0.),
0078 volume.binTolerancePhi.upper.value_or(0.)};
0079
0080 layerBuilderConfig.autoSurfaceBinning = true;
0081 layerBuilderConfig.surfaceBinMatcher = SurfaceBinningMatcher(binTolerances);
0082
0083
0084 for (auto ncp : {
0085 TGeoDetector::Config::Negative,
0086 TGeoDetector::Config::Central,
0087 TGeoDetector::Config::Positive,
0088 }) {
0089 if (!volume.layers.at(ncp)) {
0090 continue;
0091 }
0092
0093 ActsPlugins::TGeoLayerBuilder::LayerConfig lConfig;
0094 lConfig.volumeName = volume.subVolumeName.at(ncp);
0095 lConfig.sensorNames = volume.sensitiveNames.at(ncp);
0096 lConfig.localAxes =
0097 ActsPlugins::TGeoAxes::parse(volume.sensitiveAxes.at(ncp));
0098 lConfig.envelope = {config.layerEnvelopeR, config.layerEnvelopeR};
0099
0100 auto rR = volume.rRange.at(ncp);
0101 auto rMin = rR.lower.value_or(0.);
0102 auto rMax = rR.upper.value_or(std::numeric_limits<double>::max());
0103 auto zR = volume.zRange.at(ncp);
0104 auto zMin = zR.lower.value_or(-std::numeric_limits<double>::max());
0105 auto zMax = zR.upper.value_or(std::numeric_limits<double>::max());
0106 lConfig.parseRanges = {
0107 {AxisDirection::AxisR, {rMin, rMax}},
0108 {AxisDirection::AxisZ, {zMin, zMax}},
0109 };
0110
0111
0112 auto str = volume.splitTolR.at(ncp);
0113 auto stz = volume.splitTolZ.at(ncp);
0114 if (0 < str) {
0115 lConfig.splitConfigs.emplace_back(AxisDirection::AxisR, str);
0116 }
0117 if (0 < stz) {
0118 lConfig.splitConfigs.emplace_back(AxisDirection::AxisZ, stz);
0119 }
0120 lConfig.binning0 = volume.binning0.at(ncp);
0121 lConfig.binning1 = volume.binning1.at(ncp);
0122
0123 layerBuilderConfig.layerConfigurations[ncp].push_back(lConfig);
0124 }
0125
0126
0127 if (volume.cylinderDiscSplit) {
0128 TGeoCylinderDiscSplitter::Config cdsConfig;
0129 cdsConfig.cylinderPhiSegments = volume.cylinderNPhiSegments;
0130 cdsConfig.cylinderLongitudinalSegments = volume.cylinderNZSegments;
0131 cdsConfig.discPhiSegments = volume.discNPhiSegments;
0132 cdsConfig.discRadialSegments = volume.discNRSegments;
0133 layerBuilderConfig.detectorElementSplitter =
0134 std::make_shared<const TGeoCylinderDiscSplitter>(
0135 cdsConfig,
0136 logger.clone("TGeoCylinderDiscSplitter", config.layerLogLevel));
0137 } else if (volume.itkModuleSplit) {
0138 TGeoITkModuleSplitter::Config itkConfig;
0139 itkConfig.barrelMap = volume.barrelMap;
0140 itkConfig.discMap = volume.discMap;
0141 itkConfig.splitPatterns = volume.splitPatterns;
0142 layerBuilderConfig.detectorElementSplitter =
0143 std::make_shared<TGeoITkModuleSplitter>(
0144 itkConfig,
0145 logger.clone("TGeoITkModuleSplitter", config.layerLogLevel));
0146 }
0147
0148 detLayerConfigs.push_back(layerBuilderConfig);
0149 }
0150
0151 return detLayerConfigs;
0152 }
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163 std::shared_ptr<const TrackingGeometry> buildTGeoDetector(
0164 const TGeoDetector::Config& config, const GeometryContext& context,
0165 std::vector<std::shared_ptr<const SurfacePlacementBase>>& detElementStore,
0166 std::shared_ptr<const IMaterialDecorator> materialDecorator,
0167 const Logger& logger) {
0168
0169 SurfaceArrayCreator::Config sacConfig;
0170 auto surfaceArrayCreator = std::make_shared<const SurfaceArrayCreator>(
0171 sacConfig, logger.clone("SurfaceArrayCreator", config.surfaceLogLevel));
0172
0173 ProtoLayerHelper::Config plhConfig;
0174 auto protoLayerHelper = std::make_shared<const ProtoLayerHelper>(
0175 plhConfig, logger.clone("ProtoLayerHelper", config.layerLogLevel));
0176
0177 LayerCreator::Config lcConfig;
0178 lcConfig.surfaceArrayCreator = surfaceArrayCreator;
0179 auto layerCreator = std::make_shared<const LayerCreator>(
0180 lcConfig, logger.clone("LayerCreator", config.layerLogLevel));
0181
0182 LayerArrayCreator::Config lacConfig;
0183 auto layerArrayCreator = std::make_shared<const LayerArrayCreator>(
0184 lacConfig, logger.clone("LayerArrayCreator", config.layerLogLevel));
0185
0186 TrackingVolumeArrayCreator::Config tvacConfig;
0187 auto tVolumeArrayCreator = std::make_shared<const TrackingVolumeArrayCreator>(
0188 tvacConfig,
0189 logger.clone("TrackingVolumeArrayCreator", config.volumeLogLevel));
0190
0191 CylinderVolumeHelper::Config cvhConfig;
0192 cvhConfig.layerArrayCreator = layerArrayCreator;
0193 cvhConfig.trackingVolumeArrayCreator = tVolumeArrayCreator;
0194 auto cylinderVolumeHelper = std::make_shared<const CylinderVolumeHelper>(
0195 cvhConfig, logger.clone("CylinderVolumeHelper", config.volumeLogLevel));
0196
0197
0198
0199 std::list<std::shared_ptr<const ITrackingVolumeBuilder>> volumeBuilders;
0200
0201
0202 if (config.buildBeamPipe) {
0203
0204 PassiveLayerBuilder::Config bplConfig;
0205 bplConfig.layerIdentification = "BeamPipe";
0206 bplConfig.centralLayerRadii = {config.beamPipeRadius};
0207 bplConfig.centralLayerHalflengthZ = {config.beamPipeHalflengthZ};
0208 bplConfig.centralLayerThickness = {config.beamPipeLayerThickness};
0209 auto beamPipeBuilder = std::make_shared<const PassiveLayerBuilder>(
0210 bplConfig, logger.clone("BeamPipeLayerBuilder", config.layerLogLevel));
0211
0212 CylinderVolumeBuilder::Config bpvConfig;
0213 bpvConfig.trackingVolumeHelper = cylinderVolumeHelper;
0214 bpvConfig.volumeName = "BeamPipe";
0215 bpvConfig.layerBuilder = beamPipeBuilder;
0216 bpvConfig.layerEnvelopeR = {config.beamPipeEnvelopeR,
0217 config.beamPipeEnvelopeR};
0218 bpvConfig.buildToRadiusZero = true;
0219 auto beamPipeVolumeBuilder = std::make_shared<const CylinderVolumeBuilder>(
0220 bpvConfig,
0221 logger.clone("BeamPipeVolumeBuilder", config.volumeLogLevel));
0222
0223 volumeBuilders.push_back(beamPipeVolumeBuilder);
0224 }
0225
0226
0227 TGeoManager::Import(config.fileName.c_str());
0228
0229 auto layerBuilderConfigs = makeLayerBuilderConfigs(config, logger);
0230
0231
0232 std::vector<std::shared_ptr<const ActsPlugins::TGeoLayerBuilder>>
0233 tgLayerBuilders;
0234
0235 for (auto& lbc : layerBuilderConfigs) {
0236 std::shared_ptr<const LayerCreator> layerCreatorLB = nullptr;
0237
0238 if (lbc.autoSurfaceBinning) {
0239
0240
0241 SurfaceArrayCreator::Config sacConfigLB;
0242 sacConfigLB.surfaceMatcher = lbc.surfaceBinMatcher;
0243 auto surfaceArrayCreatorLB = std::make_shared<const SurfaceArrayCreator>(
0244 sacConfigLB,
0245 logger.clone(lbc.configurationName + "SurfaceArrayCreator",
0246 config.surfaceLogLevel));
0247
0248 LayerCreator::Config lcConfigLB;
0249 lcConfigLB.surfaceArrayCreator = surfaceArrayCreatorLB;
0250 layerCreatorLB = std::make_shared<const LayerCreator>(
0251 lcConfigLB, logger.clone(lbc.configurationName + "LayerCreator",
0252 config.layerLogLevel));
0253 }
0254
0255
0256 ProtoLayerHelper::Config plhConfigLB;
0257 auto protoLayerHelperLB = std::make_shared<const ProtoLayerHelper>(
0258 plhConfigLB, logger.clone(lbc.configurationName + "ProtoLayerHelper",
0259 config.layerLogLevel));
0260
0261
0262 lbc.layerCreator =
0263 (layerCreatorLB != nullptr) ? layerCreatorLB : layerCreator;
0264 lbc.protoLayerHelper =
0265 (protoLayerHelperLB != nullptr) ? protoLayerHelperLB : protoLayerHelper;
0266
0267 auto layerBuilder = std::make_shared<const ActsPlugins::TGeoLayerBuilder>(
0268 lbc, logger.clone(lbc.configurationName + "LayerBuilder",
0269 config.layerLogLevel));
0270
0271 tgLayerBuilders.push_back(layerBuilder);
0272
0273
0274 CylinderVolumeBuilder::Config volumeConfig;
0275 volumeConfig.trackingVolumeHelper = cylinderVolumeHelper;
0276 volumeConfig.volumeName = lbc.configurationName;
0277 volumeConfig.buildToRadiusZero = volumeBuilders.empty();
0278 volumeConfig.layerEnvelopeR = {config.layerEnvelopeR,
0279 config.layerEnvelopeR};
0280 auto ringLayoutConfiguration =
0281 [&](const std::vector<ActsPlugins::TGeoLayerBuilder::LayerConfig>&
0282 lConfigs) {
0283 for (const auto& lcfg : lConfigs) {
0284 for (const auto& scfg : lcfg.splitConfigs) {
0285 if (scfg.first == AxisDirection::AxisR && scfg.second > 0.) {
0286 volumeConfig.ringTolerance =
0287 std::max(volumeConfig.ringTolerance, scfg.second);
0288 volumeConfig.checkRingLayout = true;
0289 }
0290 }
0291 }
0292 };
0293 ringLayoutConfiguration(lbc.layerConfigurations[0]);
0294 ringLayoutConfiguration(lbc.layerConfigurations[2]);
0295 volumeConfig.layerBuilder = layerBuilder;
0296 auto volumeBuilder = std::make_shared<const CylinderVolumeBuilder>(
0297 volumeConfig, logger.clone(lbc.configurationName + "VolumeBuilder",
0298 config.volumeLogLevel));
0299
0300 volumeBuilders.push_back(volumeBuilder);
0301 }
0302
0303
0304
0305 TrackingGeometryBuilder::Config tgConfig;
0306
0307 tgConfig.materialDecorator = std::move(materialDecorator);
0308 tgConfig.geometryIdentifierHook = config.geometryIdentifierHook;
0309
0310 for (auto& vb : volumeBuilders) {
0311 tgConfig.trackingVolumeBuilders.push_back(
0312 [=](const auto& gcontext, const auto& inner, const auto&) {
0313 return vb->trackingVolume(gcontext, inner);
0314 });
0315 }
0316
0317 tgConfig.trackingVolumeHelper = cylinderVolumeHelper;
0318 auto cylinderGeometryBuilder =
0319 std::make_shared<const TrackingGeometryBuilder>(
0320 tgConfig,
0321 logger.clone("TrackerGeometryBuilder", config.volumeLogLevel));
0322
0323 auto trackingGeometry = cylinderGeometryBuilder->trackingGeometry(context);
0324
0325 for (auto& lBuilder : tgLayerBuilders) {
0326 auto detElements = lBuilder->detectorElements();
0327 detElementStore.insert(detElementStore.begin(), detElements.begin(),
0328 detElements.end());
0329 }
0330
0331
0332 return trackingGeometry;
0333 }
0334
0335 }
0336
0337
0338 void TGeoDetector::readTGeoLayerBuilderConfigsFile(const std::string& path,
0339 Config& config) {
0340 if (path.empty()) {
0341 return;
0342 }
0343 nlohmann::json djson;
0344 std::ifstream infile(path, std::ifstream::in | std::ifstream::binary);
0345 infile >> djson;
0346
0347 config.unitScalor = djson["geo-tgeo-unit-scalor"];
0348
0349 config.buildBeamPipe = djson["geo-tgeo-build-beampipe"];
0350 if (config.buildBeamPipe) {
0351 const auto beamPipeParameters =
0352 djson["geo-tgeo-beampipe-parameters"].get<std::array<double, 3>>();
0353 config.beamPipeRadius = beamPipeParameters[0];
0354 config.beamPipeHalflengthZ = beamPipeParameters[1];
0355 config.beamPipeLayerThickness = beamPipeParameters[2];
0356 }
0357
0358
0359 for (const auto& volume : djson["Volumes"]) {
0360 auto& vol = config.volumes.emplace_back();
0361 vol = volume;
0362 }
0363 }
0364
0365 TGeoDetector::TGeoDetector(const Config& cfg)
0366 : Detector(getDefaultLogger("TGeoDetector", cfg.logLevel)), m_cfg(cfg) {
0367 m_nominalGeometryContext = GeometryContext::dangerouslyDefaultConstruct();
0368
0369 m_trackingGeometry =
0370 buildTGeoDetector(m_cfg, m_nominalGeometryContext, m_detectorStore,
0371 m_cfg.materialDecorator, logger());
0372 }
0373
0374 void TGeoDetector::Config::readJson(const std::string& jsonFile) {
0375 readTGeoLayerBuilderConfigsFile(jsonFile, *this);
0376 }
0377 std::shared_ptr<const TrackingGeometry> buildTGeoDetectorWrapper(
0378 const TGeoDetector::Config& config, const GeometryContext& context,
0379 std::vector<std::shared_ptr<const SurfacePlacementBase>>& detElementStore,
0380 std::shared_ptr<const IMaterialDecorator> materialDecorator,
0381 const Logger& logger) {
0382 std::vector<std::shared_ptr<const SurfacePlacementBase>> tmpStore{};
0383 tmpStore.insert(tmpStore.begin(), detElementStore.begin(),
0384 detElementStore.end());
0385 return buildTGeoDetector(config, context, tmpStore,
0386 std::move(materialDecorator), logger);
0387 }
0388 }