File indexing completed on 2025-10-17 07:59:24
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/DetectorElementBase.hpp"
0014 #include "Acts/Geometry/GeometryContext.hpp"
0015 #include "Acts/Geometry/ITrackingVolumeBuilder.hpp"
0016 #include "Acts/Geometry/LayerArrayCreator.hpp"
0017 #include "Acts/Geometry/LayerCreator.hpp"
0018 #include "Acts/Geometry/PassiveLayerBuilder.hpp"
0019 #include "Acts/Geometry/ProtoLayerHelper.hpp"
0020 #include "Acts/Geometry/SurfaceArrayCreator.hpp"
0021 #include "Acts/Geometry/SurfaceBinningMatcher.hpp"
0022 #include "Acts/Geometry/TrackingGeometry.hpp"
0023 #include "Acts/Geometry/TrackingGeometryBuilder.hpp"
0024 #include "Acts/Geometry/TrackingVolumeArrayCreator.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 = volume.sensitiveAxes.at(ncp);
0097 lConfig.envelope = {config.layerEnvelopeR, config.layerEnvelopeR};
0098
0099 auto rR = volume.rRange.at(ncp);
0100 auto rMin = rR.lower.value_or(0.);
0101 auto rMax = rR.upper.value_or(std::numeric_limits<double>::max());
0102 auto zR = volume.zRange.at(ncp);
0103 auto zMin = zR.lower.value_or(-std::numeric_limits<double>::max());
0104 auto zMax = zR.upper.value_or(std::numeric_limits<double>::max());
0105 lConfig.parseRanges = {
0106 {AxisDirection::AxisR, {rMin, rMax}},
0107 {AxisDirection::AxisZ, {zMin, zMax}},
0108 };
0109
0110
0111 auto str = volume.splitTolR.at(ncp);
0112 auto stz = volume.splitTolZ.at(ncp);
0113 if (0 < str) {
0114 lConfig.splitConfigs.emplace_back(AxisDirection::AxisR, str);
0115 }
0116 if (0 < stz) {
0117 lConfig.splitConfigs.emplace_back(AxisDirection::AxisZ, stz);
0118 }
0119 lConfig.binning0 = volume.binning0.at(ncp);
0120 lConfig.binning1 = volume.binning1.at(ncp);
0121
0122 layerBuilderConfig.layerConfigurations[ncp].push_back(lConfig);
0123 }
0124
0125
0126 if (volume.cylinderDiscSplit) {
0127 TGeoCylinderDiscSplitter::Config cdsConfig;
0128 cdsConfig.cylinderPhiSegments = volume.cylinderNPhiSegments;
0129 cdsConfig.cylinderLongitudinalSegments = volume.cylinderNZSegments;
0130 cdsConfig.discPhiSegments = volume.discNPhiSegments;
0131 cdsConfig.discRadialSegments = volume.discNRSegments;
0132 layerBuilderConfig.detectorElementSplitter =
0133 std::make_shared<const TGeoCylinderDiscSplitter>(
0134 cdsConfig,
0135 logger.clone("TGeoCylinderDiscSplitter", config.layerLogLevel));
0136 } else if (volume.itkModuleSplit) {
0137 TGeoITkModuleSplitter::Config itkConfig;
0138 itkConfig.barrelMap = volume.barrelMap;
0139 itkConfig.discMap = volume.discMap;
0140 itkConfig.splitPatterns = volume.splitPatterns;
0141 layerBuilderConfig.detectorElementSplitter =
0142 std::make_shared<TGeoITkModuleSplitter>(
0143 itkConfig,
0144 logger.clone("TGeoITkModuleSplitter", config.layerLogLevel));
0145 }
0146
0147 detLayerConfigs.push_back(layerBuilderConfig);
0148 }
0149
0150 return detLayerConfigs;
0151 }
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162 std::shared_ptr<const TrackingGeometry> buildTGeoDetector(
0163 const TGeoDetector::Config& config, const GeometryContext& context,
0164 std::vector<std::shared_ptr<const DetectorElementBase>>& detElementStore,
0165 std::shared_ptr<const IMaterialDecorator> materialDecorator,
0166 const Logger& logger) {
0167
0168 SurfaceArrayCreator::Config sacConfig;
0169 auto surfaceArrayCreator = std::make_shared<const SurfaceArrayCreator>(
0170 sacConfig, logger.clone("SurfaceArrayCreator", config.surfaceLogLevel));
0171
0172 ProtoLayerHelper::Config plhConfig;
0173 auto protoLayerHelper = std::make_shared<const ProtoLayerHelper>(
0174 plhConfig, logger.clone("ProtoLayerHelper", config.layerLogLevel));
0175
0176 LayerCreator::Config lcConfig;
0177 lcConfig.surfaceArrayCreator = surfaceArrayCreator;
0178 auto layerCreator = std::make_shared<const LayerCreator>(
0179 lcConfig, logger.clone("LayerCreator", config.layerLogLevel));
0180
0181 LayerArrayCreator::Config lacConfig;
0182 auto layerArrayCreator = std::make_shared<const LayerArrayCreator>(
0183 lacConfig, logger.clone("LayerArrayCreator", config.layerLogLevel));
0184
0185 TrackingVolumeArrayCreator::Config tvacConfig;
0186 auto tVolumeArrayCreator = std::make_shared<const TrackingVolumeArrayCreator>(
0187 tvacConfig,
0188 logger.clone("TrackingVolumeArrayCreator", config.volumeLogLevel));
0189
0190 CylinderVolumeHelper::Config cvhConfig;
0191 cvhConfig.layerArrayCreator = layerArrayCreator;
0192 cvhConfig.trackingVolumeArrayCreator = tVolumeArrayCreator;
0193 auto cylinderVolumeHelper = std::make_shared<const CylinderVolumeHelper>(
0194 cvhConfig, logger.clone("CylinderVolumeHelper", config.volumeLogLevel));
0195
0196
0197
0198 std::list<std::shared_ptr<const ITrackingVolumeBuilder>> volumeBuilders;
0199
0200
0201 if (config.buildBeamPipe) {
0202
0203 PassiveLayerBuilder::Config bplConfig;
0204 bplConfig.layerIdentification = "BeamPipe";
0205 bplConfig.centralLayerRadii = {config.beamPipeRadius};
0206 bplConfig.centralLayerHalflengthZ = {config.beamPipeHalflengthZ};
0207 bplConfig.centralLayerThickness = {config.beamPipeLayerThickness};
0208 auto beamPipeBuilder = std::make_shared<const PassiveLayerBuilder>(
0209 bplConfig, logger.clone("BeamPipeLayerBuilder", config.layerLogLevel));
0210
0211 CylinderVolumeBuilder::Config bpvConfig;
0212 bpvConfig.trackingVolumeHelper = cylinderVolumeHelper;
0213 bpvConfig.volumeName = "BeamPipe";
0214 bpvConfig.layerBuilder = beamPipeBuilder;
0215 bpvConfig.layerEnvelopeR = {config.beamPipeEnvelopeR,
0216 config.beamPipeEnvelopeR};
0217 bpvConfig.buildToRadiusZero = true;
0218 auto beamPipeVolumeBuilder = std::make_shared<const CylinderVolumeBuilder>(
0219 bpvConfig,
0220 logger.clone("BeamPipeVolumeBuilder", config.volumeLogLevel));
0221
0222 volumeBuilders.push_back(beamPipeVolumeBuilder);
0223 }
0224
0225
0226 TGeoManager::Import(config.fileName.c_str());
0227
0228 auto layerBuilderConfigs = makeLayerBuilderConfigs(config, logger);
0229
0230
0231 std::vector<std::shared_ptr<const ActsPlugins::TGeoLayerBuilder>>
0232 tgLayerBuilders;
0233
0234 for (auto& lbc : layerBuilderConfigs) {
0235 std::shared_ptr<const LayerCreator> layerCreatorLB = nullptr;
0236
0237 if (lbc.autoSurfaceBinning) {
0238
0239
0240 SurfaceArrayCreator::Config sacConfigLB;
0241 sacConfigLB.surfaceMatcher = lbc.surfaceBinMatcher;
0242 auto surfaceArrayCreatorLB = std::make_shared<const SurfaceArrayCreator>(
0243 sacConfigLB,
0244 logger.clone(lbc.configurationName + "SurfaceArrayCreator",
0245 config.surfaceLogLevel));
0246
0247 LayerCreator::Config lcConfigLB;
0248 lcConfigLB.surfaceArrayCreator = surfaceArrayCreatorLB;
0249 layerCreatorLB = std::make_shared<const LayerCreator>(
0250 lcConfigLB, logger.clone(lbc.configurationName + "LayerCreator",
0251 config.layerLogLevel));
0252 }
0253
0254
0255 ProtoLayerHelper::Config plhConfigLB;
0256 auto protoLayerHelperLB = std::make_shared<const ProtoLayerHelper>(
0257 plhConfigLB, logger.clone(lbc.configurationName + "ProtoLayerHelper",
0258 config.layerLogLevel));
0259
0260
0261 lbc.layerCreator =
0262 (layerCreatorLB != nullptr) ? layerCreatorLB : layerCreator;
0263 lbc.protoLayerHelper =
0264 (protoLayerHelperLB != nullptr) ? protoLayerHelperLB : protoLayerHelper;
0265
0266 auto layerBuilder = std::make_shared<const ActsPlugins::TGeoLayerBuilder>(
0267 lbc, logger.clone(lbc.configurationName + "LayerBuilder",
0268 config.layerLogLevel));
0269
0270 tgLayerBuilders.push_back(layerBuilder);
0271
0272
0273 CylinderVolumeBuilder::Config volumeConfig;
0274 volumeConfig.trackingVolumeHelper = cylinderVolumeHelper;
0275 volumeConfig.volumeName = lbc.configurationName;
0276 volumeConfig.buildToRadiusZero = volumeBuilders.empty();
0277 volumeConfig.layerEnvelopeR = {config.layerEnvelopeR,
0278 config.layerEnvelopeR};
0279 auto ringLayoutConfiguration =
0280 [&](const std::vector<ActsPlugins::TGeoLayerBuilder::LayerConfig>&
0281 lConfigs) {
0282 for (const auto& lcfg : lConfigs) {
0283 for (const auto& scfg : lcfg.splitConfigs) {
0284 if (scfg.first == AxisDirection::AxisR && scfg.second > 0.) {
0285 volumeConfig.ringTolerance =
0286 std::max(volumeConfig.ringTolerance, scfg.second);
0287 volumeConfig.checkRingLayout = true;
0288 }
0289 }
0290 }
0291 };
0292 ringLayoutConfiguration(lbc.layerConfigurations[0]);
0293 ringLayoutConfiguration(lbc.layerConfigurations[2]);
0294 volumeConfig.layerBuilder = layerBuilder;
0295 auto volumeBuilder = std::make_shared<const CylinderVolumeBuilder>(
0296 volumeConfig, logger.clone(lbc.configurationName + "VolumeBuilder",
0297 config.volumeLogLevel));
0298
0299 volumeBuilders.push_back(volumeBuilder);
0300 }
0301
0302
0303
0304 TrackingGeometryBuilder::Config tgConfig;
0305
0306 tgConfig.materialDecorator = std::move(materialDecorator);
0307 tgConfig.geometryIdentifierHook = config.geometryIdentifierHook;
0308
0309 for (auto& vb : volumeBuilders) {
0310 tgConfig.trackingVolumeBuilders.push_back(
0311 [=](const auto& gcontext, const auto& inner, const auto&) {
0312 return vb->trackingVolume(gcontext, inner);
0313 });
0314 }
0315
0316 tgConfig.trackingVolumeHelper = cylinderVolumeHelper;
0317 auto cylinderGeometryBuilder =
0318 std::make_shared<const TrackingGeometryBuilder>(
0319 tgConfig,
0320 logger.clone("TrackerGeometryBuilder", config.volumeLogLevel));
0321
0322 auto trackingGeometry = cylinderGeometryBuilder->trackingGeometry(context);
0323
0324 for (auto& lBuilder : tgLayerBuilders) {
0325 auto detElements = lBuilder->detectorElements();
0326 detElementStore.insert(detElementStore.begin(), detElements.begin(),
0327 detElements.end());
0328 }
0329
0330
0331 return trackingGeometry;
0332 }
0333
0334 }
0335
0336
0337 void TGeoDetector::readTGeoLayerBuilderConfigsFile(const std::string& path,
0338 Config& config) {
0339 if (path.empty()) {
0340 return;
0341 }
0342 nlohmann::json djson;
0343 std::ifstream infile(path, std::ifstream::in | std::ifstream::binary);
0344 infile >> djson;
0345
0346 config.unitScalor = djson["geo-tgeo-unit-scalor"];
0347
0348 config.buildBeamPipe = djson["geo-tgeo-build-beampipe"];
0349 if (config.buildBeamPipe) {
0350 const auto beamPipeParameters =
0351 djson["geo-tgeo-beampipe-parameters"].get<std::array<double, 3>>();
0352 config.beamPipeRadius = beamPipeParameters[0];
0353 config.beamPipeHalflengthZ = beamPipeParameters[1];
0354 config.beamPipeLayerThickness = beamPipeParameters[2];
0355 }
0356
0357
0358 for (const auto& volume : djson["Volumes"]) {
0359 auto& vol = config.volumes.emplace_back();
0360 vol = volume;
0361 }
0362 }
0363
0364 TGeoDetector::TGeoDetector(const Config& cfg)
0365 : Detector(getDefaultLogger("TGeoDetector", cfg.logLevel)), m_cfg(cfg) {
0366 m_nominalGeometryContext = GeometryContext();
0367
0368 m_trackingGeometry =
0369 buildTGeoDetector(m_cfg, m_nominalGeometryContext, m_detectorStore,
0370 m_cfg.materialDecorator, logger());
0371 }
0372
0373 void TGeoDetector::Config::readJson(const std::string& jsonFile) {
0374 readTGeoLayerBuilderConfigsFile(jsonFile, *this);
0375 }
0376
0377 }