File indexing completed on 2025-08-05 08:10:21
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "Acts/Plugins/TGeo/TGeoLayerBuilder.hpp"
0010
0011 #include "Acts/Geometry/Extent.hpp"
0012 #include "Acts/Geometry/LayerCreator.hpp"
0013 #include "Acts/Geometry/ProtoLayer.hpp"
0014 #include "Acts/Geometry/ProtoLayerHelper.hpp"
0015 #include "Acts/Plugins/TGeo/ITGeoDetectorElementSplitter.hpp"
0016 #include "Acts/Plugins/TGeo/ITGeoIdentifierProvider.hpp"
0017 #include "Acts/Plugins/TGeo/TGeoDetectorElement.hpp"
0018 #include "Acts/Plugins/TGeo/TGeoParser.hpp"
0019 #include "Acts/Plugins/TGeo/TGeoPrimitivesHelper.hpp"
0020 #include "Acts/Utilities/Helpers.hpp"
0021
0022 #include <ostream>
0023 #include <stdexcept>
0024
0025 #include "TGeoManager.h"
0026 #include "TGeoMatrix.h"
0027
0028 namespace Acts {
0029 class ISurfaceMaterial;
0030 }
0031
0032 Acts::TGeoLayerBuilder::TGeoLayerBuilder(
0033 const Acts::TGeoLayerBuilder::Config& config,
0034 std::unique_ptr<const Logger> logger)
0035 : m_cfg(), m_logger(std::move(logger)) {
0036 setConfiguration(config);
0037 }
0038
0039 Acts::TGeoLayerBuilder::~TGeoLayerBuilder() = default;
0040
0041 void Acts::TGeoLayerBuilder::setConfiguration(
0042 const Acts::TGeoLayerBuilder::Config& config) {
0043 m_cfg = config;
0044 }
0045
0046 void Acts::TGeoLayerBuilder::setLogger(
0047 std::unique_ptr<const Logger> newLogger) {
0048 m_logger = std::move(newLogger);
0049 }
0050
0051 const Acts::LayerVector Acts::TGeoLayerBuilder::negativeLayers(
0052 const GeometryContext& gctx) const {
0053
0054 auto mutableThis = const_cast<TGeoLayerBuilder*>(this);
0055 LayerVector nVector;
0056 mutableThis->buildLayers(gctx, nVector, -1);
0057 return nVector;
0058 }
0059
0060 const Acts::LayerVector Acts::TGeoLayerBuilder::centralLayers(
0061 const GeometryContext& gctx) const {
0062
0063 auto mutableThis = const_cast<TGeoLayerBuilder*>(this);
0064 LayerVector cVector;
0065 mutableThis->buildLayers(gctx, cVector, 0);
0066 return cVector;
0067 }
0068
0069 const Acts::LayerVector Acts::TGeoLayerBuilder::positiveLayers(
0070 const GeometryContext& gctx) const {
0071
0072 auto mutableThis = const_cast<TGeoLayerBuilder*>(this);
0073 LayerVector pVector;
0074 mutableThis->buildLayers(gctx, pVector, 1);
0075 return pVector;
0076 }
0077
0078 void Acts::TGeoLayerBuilder::buildLayers(const GeometryContext& gctx,
0079 LayerVector& layers, int type) {
0080
0081 if (gGeoManager == nullptr) {
0082 ACTS_WARNING("No gGeoManager found - bailing out.");
0083 return;
0084 }
0085
0086 using LayerSurfaceVector = std::vector<std::shared_ptr<const Surface>>;
0087 LayerSurfaceVector layerSurfaces;
0088
0089 std::vector<LayerConfig> layerConfigs = m_cfg.layerConfigurations[type + 1];
0090 std::string layerType = m_layerTypes[type + 1];
0091
0092
0093 std::string addonOutput = m_cfg.layerSplitToleranceR[type + 1] > 0.
0094 ? std::string(", splitting in r")
0095 : std::string("");
0096 addonOutput += m_cfg.layerSplitToleranceZ[type + 1] > 0.
0097 ? std::string(", splitting in z")
0098 : std::string("");
0099 addonOutput += std::string(".");
0100
0101
0102 ACTS_DEBUG(layerType << " layers : found " << layerConfigs.size()
0103 << " configuration(s)" + addonOutput);
0104
0105
0106 auto fillLayer = [&](const LayerSurfaceVector& lSurfaces,
0107 const LayerConfig& lCfg,
0108 unsigned int pl_id = 0) -> void {
0109 int nb0 = 0, nt0 = 0;
0110 bool is_autobinning = ((lCfg.binning0.size() == 1) &&
0111 (std::get<int>(lCfg.binning0.at(0)) <= 0));
0112 if (!is_autobinning && std::get<int>(lCfg.binning0.at(pl_id)) <= 0) {
0113 throw std::invalid_argument(
0114 "Incorrect binning configuration found for loc0 protolayer #" +
0115 std::to_string(pl_id) +
0116 ". Layer is autobinned: No mixed binning (manual and auto) for loc0 "
0117 "possible between layers in a single subvolume. Quitting");
0118 }
0119 if (is_autobinning) {
0120
0121 nb0 = std::get<int>(lCfg.binning0.at(0));
0122
0123 nt0 = std::get<BinningType>(lCfg.binning0.at(0));
0124 } else if (pl_id < lCfg.binning0.size()) {
0125
0126 nb0 = std::get<int>(lCfg.binning0.at(pl_id));
0127 }
0128
0129 int nb1 = 0, nt1 = 0;
0130 is_autobinning = (lCfg.binning1.size() == 1) &&
0131 (std::get<int>(lCfg.binning1.at(0)) <= 0);
0132 if (!is_autobinning && std::get<int>(lCfg.binning1.at(pl_id)) <= 0) {
0133 throw std::invalid_argument(
0134 "Incorrect binning configuration found for loc1 protolayer #" +
0135 std::to_string(pl_id) +
0136 ". Layer is autobinned: No mixed binning (manual and auto) for loc1 "
0137 "possible between layers in a single subvolume. Quitting");
0138 }
0139 if (is_autobinning) {
0140
0141 nb1 = std::get<int>(lCfg.binning1.at(0));
0142
0143 nt1 = std::get<BinningType>(lCfg.binning1.at(0));
0144 } else if (pl_id < lCfg.binning1.size()) {
0145
0146 nb1 = std::get<int>(lCfg.binning1.at(pl_id));
0147 }
0148
0149 if (type == 0) {
0150 ProtoLayer pl(gctx, lSurfaces);
0151 ACTS_DEBUG("- creating CylinderLayer with "
0152 << lSurfaces.size() << " surfaces at r = " << pl.medium(binR));
0153
0154 pl.envelope[Acts::binR] = {lCfg.envelope.first, lCfg.envelope.second};
0155 pl.envelope[Acts::binZ] = {lCfg.envelope.second, lCfg.envelope.second};
0156 if (nb0 >= 0 && nb1 >= 0) {
0157 layers.push_back(
0158 m_cfg.layerCreator->cylinderLayer(gctx, lSurfaces, nb0, nb1, pl));
0159 } else {
0160 layers.push_back(
0161 m_cfg.layerCreator->cylinderLayer(gctx, lSurfaces, nt0, nt1, pl));
0162 }
0163 } else {
0164 ProtoLayer pl(gctx, lSurfaces);
0165 ACTS_DEBUG("- creating DiscLayer with "
0166 << lSurfaces.size() << " surfaces at z = " << pl.medium(binZ));
0167
0168 pl.envelope[Acts::binR] = {lCfg.envelope.first, lCfg.envelope.second};
0169 pl.envelope[Acts::binZ] = {lCfg.envelope.second, lCfg.envelope.second};
0170 if (nb0 >= 0 && nb1 >= 0) {
0171 layers.push_back(
0172 m_cfg.layerCreator->discLayer(gctx, lSurfaces, nb0, nb1, pl));
0173 } else {
0174 layers.push_back(
0175 m_cfg.layerCreator->discLayer(gctx, lSurfaces, nt0, nt1, pl));
0176 }
0177 }
0178 };
0179
0180 for (auto layerCfg : layerConfigs) {
0181 ACTS_DEBUG("- layer configuration found for layer " << layerCfg.volumeName
0182 << " with sensors ");
0183 for (auto& sensor : layerCfg.sensorNames) {
0184 ACTS_DEBUG(" - sensor: " << sensor);
0185 }
0186 if (!layerCfg.parseRanges.empty()) {
0187 for (const auto& pRange : layerCfg.parseRanges) {
0188 ACTS_DEBUG("- layer parsing restricted in "
0189 << binningValueNames()[pRange.first] << " to ["
0190 << pRange.second.first << "/" << pRange.second.second
0191 << "].");
0192 }
0193 }
0194 if (!layerCfg.splitConfigs.empty()) {
0195 for (const auto& sConfig : layerCfg.splitConfigs) {
0196 ACTS_DEBUG("- layer splitting attempt in "
0197 << binningValueNames()[sConfig.first] << " with tolerance "
0198 << sConfig.second << ".");
0199 }
0200 }
0201
0202
0203 TGeoVolume* tVolume =
0204 gGeoManager->FindVolumeFast(layerCfg.volumeName.c_str());
0205 if (tVolume == nullptr) {
0206 tVolume = gGeoManager->GetTopVolume();
0207 ACTS_DEBUG("- search volume is TGeo top volume");
0208 } else {
0209 ACTS_DEBUG("- setting search volume to " << tVolume->GetName());
0210 }
0211
0212 if (tVolume != nullptr) {
0213 TGeoParser::Options tgpOptions;
0214 tgpOptions.volumeNames = {layerCfg.volumeName};
0215 tgpOptions.targetNames = layerCfg.sensorNames;
0216 tgpOptions.parseRanges = layerCfg.parseRanges;
0217 tgpOptions.unit = m_cfg.unit;
0218 TGeoParser::State tgpState;
0219 tgpState.volume = tVolume;
0220
0221 ACTS_DEBUG("- applying " << layerCfg.parseRanges.size()
0222 << " search restrictions.");
0223 for (const auto& prange : layerCfg.parseRanges) {
0224 ACTS_VERBOSE(" - range " << binningValueNames()[prange.first]
0225 << " within [ " << prange.second.first << ", "
0226 << prange.second.second << "]");
0227 }
0228
0229 TGeoParser::select(tgpState, tgpOptions);
0230
0231 ACTS_DEBUG("- number of selected nodes found : "
0232 << tgpState.selectedNodes.size());
0233
0234 for (auto& snode : tgpState.selectedNodes) {
0235 auto identifier =
0236 m_cfg.identifierProvider != nullptr
0237 ? m_cfg.identifierProvider->identify(gctx, *snode.node)
0238 : Identifier();
0239
0240 auto tgElement =
0241 m_cfg.elementFactory(identifier, *snode.node, *snode.transform,
0242 layerCfg.localAxes, m_cfg.unit, nullptr);
0243
0244 std::vector<std::shared_ptr<const Acts::TGeoDetectorElement>>
0245 tgElements =
0246 (m_cfg.detectorElementSplitter == nullptr)
0247 ? std::vector<std::shared_ptr<
0248 const Acts::TGeoDetectorElement>>{tgElement}
0249 : m_cfg.detectorElementSplitter->split(gctx, tgElement);
0250
0251 for (const auto& tge : tgElements) {
0252 m_elementStore.push_back(tge);
0253 layerSurfaces.push_back(tge->surface().getSharedPtr());
0254 }
0255 }
0256
0257 ACTS_DEBUG("- created TGeoDetectorElements : " << layerSurfaces.size());
0258
0259 if (m_cfg.protoLayerHelper != nullptr && !layerCfg.splitConfigs.empty()) {
0260 auto protoLayers = m_cfg.protoLayerHelper->protoLayers(
0261 gctx, unpack_shared_vector(layerSurfaces), layerCfg.splitConfigs);
0262 ACTS_DEBUG("- splitting into " << protoLayers.size() << " layers.");
0263
0264
0265
0266 const bool is_loc0_n_config =
0267 layerCfg.binning0.size() == protoLayers.size();
0268 const bool is_loc0_autobinning =
0269 (layerCfg.binning0.size() == 1) &&
0270 (std::get<int>(layerCfg.binning0.at(0)) <= 0);
0271 const bool is_loc1_n_config =
0272 layerCfg.binning1.size() == protoLayers.size();
0273 const bool is_loc1_autobinning =
0274 (layerCfg.binning1.size() == 1) &&
0275 (std::get<int>(layerCfg.binning1.at(0)) <= 0);
0276 if ((!is_loc0_n_config && !is_loc0_autobinning) ||
0277 (!is_loc1_n_config && !is_loc1_autobinning)) {
0278 throw std::invalid_argument(
0279 "Incorrect binning configuration found: Number of configurations "
0280 "does not match number of protolayers in subvolume " +
0281 layerCfg.volumeName + ". Quitting.");
0282 }
0283 unsigned int layer_id = 0;
0284 for (auto& pLayer : protoLayers) {
0285 layerSurfaces.clear();
0286
0287 for (const auto& lsurface : pLayer.surfaces()) {
0288 layerSurfaces.push_back(lsurface->getSharedPtr());
0289 }
0290 fillLayer(layerSurfaces, layerCfg, layer_id);
0291 layer_id++;
0292 }
0293 } else {
0294 fillLayer(layerSurfaces, layerCfg);
0295 }
0296 }
0297 }
0298 return;
0299 }
0300
0301 std::shared_ptr<Acts::TGeoDetectorElement>
0302 Acts::TGeoLayerBuilder::defaultElementFactory(
0303 const Identifier& identifier, const TGeoNode& tGeoNode,
0304 const TGeoMatrix& tGeoMatrix, const std::string& axes, double scalor,
0305 std::shared_ptr<const Acts::ISurfaceMaterial> material) {
0306 return std::make_shared<TGeoDetectorElement>(
0307 identifier, tGeoNode, tGeoMatrix, axes, scalor, std::move(material));
0308 }