Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-10-17 07:59:24

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/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 /// @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 = 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       // Fill the layer splitting parameters in r/z
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     // Perform splitting of cylinders and discs
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 /// @brief Function to build the generic tracking geometry
0154 // from a TGeo object.
0155 ///
0156 /// It does *currently* not translate the material, this has
0157 /// to be done with a material mapping stage
0158 ///
0159 /// @tparam variable_map_t is the variable map
0160 ///
0161 /// @param vm is the variable map from the options
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   // configure surface array creator
0168   SurfaceArrayCreator::Config sacConfig;
0169   auto surfaceArrayCreator = std::make_shared<const SurfaceArrayCreator>(
0170       sacConfig, logger.clone("SurfaceArrayCreator", config.surfaceLogLevel));
0171   // configure the proto layer helper
0172   ProtoLayerHelper::Config plhConfig;
0173   auto protoLayerHelper = std::make_shared<const ProtoLayerHelper>(
0174       plhConfig, logger.clone("ProtoLayerHelper", config.layerLogLevel));
0175   // configure the layer creator that uses the surface array creator
0176   LayerCreator::Config lcConfig;
0177   lcConfig.surfaceArrayCreator = surfaceArrayCreator;
0178   auto layerCreator = std::make_shared<const LayerCreator>(
0179       lcConfig, logger.clone("LayerCreator", config.layerLogLevel));
0180   // configure the layer array creator
0181   LayerArrayCreator::Config lacConfig;
0182   auto layerArrayCreator = std::make_shared<const LayerArrayCreator>(
0183       lacConfig, logger.clone("LayerArrayCreator", config.layerLogLevel));
0184   // tracking volume array creator
0185   TrackingVolumeArrayCreator::Config tvacConfig;
0186   auto tVolumeArrayCreator = std::make_shared<const TrackingVolumeArrayCreator>(
0187       tvacConfig,
0188       logger.clone("TrackingVolumeArrayCreator", config.volumeLogLevel));
0189   // configure the cylinder volume helper
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   // list the volume builders
0198   std::list<std::shared_ptr<const ITrackingVolumeBuilder>> volumeBuilders;
0199 
0200   // Create a beam pipe if configured to do so
0201   if (config.buildBeamPipe) {
0202     /// configure the beam pipe layer builder
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     // create the volume for the beam pipe
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     // add to the list of builders
0222     volumeBuilders.push_back(beamPipeVolumeBuilder);
0223   }
0224 
0225   // Import the file from
0226   TGeoManager::Import(config.fileName.c_str());
0227 
0228   auto layerBuilderConfigs = makeLayerBuilderConfigs(config, logger);
0229 
0230   // Remember the layer builders to collect the detector elements
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       // Configure surface array creator (optionally) per layer builder
0239       // (in order to configure them to work appropriately)
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       // configure the layer creator that uses the surface array creator
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     // Configure the proto layer helper
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     // remember the layer builder
0270     tgLayerBuilders.push_back(layerBuilder);
0271 
0272     // build the pixel volume
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     // add to the list of builders
0299     volumeBuilders.push_back(volumeBuilder);
0300   }
0301 
0302   //-------------------------------------------------------------------------------------
0303   // create the tracking geometry
0304   TrackingGeometryBuilder::Config tgConfig;
0305   // Add the builders
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   // Add the helper
0316   tgConfig.trackingVolumeHelper = cylinderVolumeHelper;
0317   auto cylinderGeometryBuilder =
0318       std::make_shared<const TrackingGeometryBuilder>(
0319           tgConfig,
0320           logger.clone("TrackerGeometryBuilder", config.volumeLogLevel));
0321   // get the geometry
0322   auto trackingGeometry = cylinderGeometryBuilder->trackingGeometry(context);
0323   // collect the detector element store
0324   for (auto& lBuilder : tgLayerBuilders) {
0325     auto detElements = lBuilder->detectorElements();
0326     detElementStore.insert(detElementStore.begin(), detElements.begin(),
0327                            detElements.end());
0328   }
0329 
0330   /// return the tracking geometry
0331   return trackingGeometry;
0332 }
0333 
0334 }  // namespace
0335 
0336 /// Read the TGeo layer builder configurations from the user configuration.
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   // Fill nested volume configs
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 }  // namespace ActsExamples