Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-15 07:39:01

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
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 /// @brief Function that constructs a set of layer builder
0052 ///        configs from a central @c TGeoDetector config.
0053 ///
0054 /// @param config The input config
0055 /// @return Vector of layer builder configs
0056 std::vector<ActsPlugins::TGeoLayerBuilder::Config> makeLayerBuilderConfigs(
0057     const TGeoDetector::Config& config, const Logger& logger) {
0058   std::vector<ActsPlugins::TGeoLayerBuilder::Config> detLayerConfigs;
0059 
0060   // iterate over all configured detector volumes
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     // configure surface autobinning
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     // loop over the negative/central/positive layer configurations
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       // Fill the layer splitting parameters in r/z
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     // Perform splitting of cylinders and discs
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 /// @brief Function to build the generic tracking geometry
0155 // from a TGeo object.
0156 ///
0157 /// It does *currently* not translate the material, this has
0158 /// to be done with a material mapping stage
0159 ///
0160 /// @tparam variable_map_t is the variable map
0161 ///
0162 /// @param vm is the variable map from the options
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   // configure surface array creator
0169   SurfaceArrayCreator::Config sacConfig;
0170   auto surfaceArrayCreator = std::make_shared<const SurfaceArrayCreator>(
0171       sacConfig, logger.clone("SurfaceArrayCreator", config.surfaceLogLevel));
0172   // configure the proto layer helper
0173   ProtoLayerHelper::Config plhConfig;
0174   auto protoLayerHelper = std::make_shared<const ProtoLayerHelper>(
0175       plhConfig, logger.clone("ProtoLayerHelper", config.layerLogLevel));
0176   // configure the layer creator that uses the surface array creator
0177   LayerCreator::Config lcConfig;
0178   lcConfig.surfaceArrayCreator = surfaceArrayCreator;
0179   auto layerCreator = std::make_shared<const LayerCreator>(
0180       lcConfig, logger.clone("LayerCreator", config.layerLogLevel));
0181   // configure the layer array creator
0182   LayerArrayCreator::Config lacConfig;
0183   auto layerArrayCreator = std::make_shared<const LayerArrayCreator>(
0184       lacConfig, logger.clone("LayerArrayCreator", config.layerLogLevel));
0185   // tracking volume array creator
0186   TrackingVolumeArrayCreator::Config tvacConfig;
0187   auto tVolumeArrayCreator = std::make_shared<const TrackingVolumeArrayCreator>(
0188       tvacConfig,
0189       logger.clone("TrackingVolumeArrayCreator", config.volumeLogLevel));
0190   // configure the cylinder volume helper
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   // list the volume builders
0199   std::list<std::shared_ptr<const ITrackingVolumeBuilder>> volumeBuilders;
0200 
0201   // Create a beam pipe if configured to do so
0202   if (config.buildBeamPipe) {
0203     /// configure the beam pipe layer builder
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     // create the volume for the beam pipe
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     // add to the list of builders
0223     volumeBuilders.push_back(beamPipeVolumeBuilder);
0224   }
0225 
0226   // Import the file from
0227   TGeoManager::Import(config.fileName.c_str());
0228 
0229   auto layerBuilderConfigs = makeLayerBuilderConfigs(config, logger);
0230 
0231   // Remember the layer builders to collect the detector elements
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       // Configure surface array creator (optionally) per layer builder
0240       // (in order to configure them to work appropriately)
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       // configure the layer creator that uses the surface array creator
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     // Configure the proto layer helper
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     // remember the layer builder
0271     tgLayerBuilders.push_back(layerBuilder);
0272 
0273     // build the pixel volume
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     // add to the list of builders
0300     volumeBuilders.push_back(volumeBuilder);
0301   }
0302 
0303   //-------------------------------------------------------------------------------------
0304   // create the tracking geometry
0305   TrackingGeometryBuilder::Config tgConfig;
0306   // Add the builders
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   // Add the helper
0317   tgConfig.trackingVolumeHelper = cylinderVolumeHelper;
0318   auto cylinderGeometryBuilder =
0319       std::make_shared<const TrackingGeometryBuilder>(
0320           tgConfig,
0321           logger.clone("TrackerGeometryBuilder", config.volumeLogLevel));
0322   // get the geometry
0323   auto trackingGeometry = cylinderGeometryBuilder->trackingGeometry(context);
0324   // collect the detector element store
0325   for (auto& lBuilder : tgLayerBuilders) {
0326     auto detElements = lBuilder->detectorElements();
0327     detElementStore.insert(detElementStore.begin(), detElements.begin(),
0328                            detElements.end());
0329   }
0330 
0331   /// return the tracking geometry
0332   return trackingGeometry;
0333 }
0334 
0335 }  // namespace
0336 
0337 /// Read the TGeo layer builder configurations from the user configuration.
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   // Fill nested volume configs
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 }  // namespace ActsExamples