File indexing completed on 2025-06-21 08:09:55
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "Acts/Plugins/Root/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/Root/ITGeoDetectorElementSplitter.hpp"
0016 #include "Acts/Plugins/Root/ITGeoIdentifierProvider.hpp"
0017 #include "Acts/Plugins/Root/TGeoDetectorElement.hpp"
0018 #include "Acts/Plugins/Root/TGeoParser.hpp"
0019 #include "Acts/Plugins/Root/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_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, unsigned int pl_id = 0) {
0108 int nb0 = 0;
0109 int 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;
0130 int nt1 = 0;
0131 is_autobinning = (lCfg.binning1.size() == 1) &&
0132 (std::get<int>(lCfg.binning1.at(0)) <= 0);
0133 if (!is_autobinning && std::get<int>(lCfg.binning1.at(pl_id)) <= 0) {
0134 throw std::invalid_argument(
0135 "Incorrect binning configuration found for loc1 protolayer #" +
0136 std::to_string(pl_id) +
0137 ". Layer is autobinned: No mixed binning (manual and auto) for loc1 "
0138 "possible between layers in a single subvolume. Quitting");
0139 }
0140 if (is_autobinning) {
0141
0142 nb1 = std::get<int>(lCfg.binning1.at(0));
0143
0144 nt1 = std::get<BinningType>(lCfg.binning1.at(0));
0145 } else if (pl_id < lCfg.binning1.size()) {
0146
0147 nb1 = std::get<int>(lCfg.binning1.at(pl_id));
0148 }
0149
0150 if (type == 0) {
0151 ProtoLayer pl(gctx, lSurfaces);
0152 ACTS_DEBUG("- creating CylinderLayer with "
0153 << lSurfaces.size()
0154 << " surfaces at r = " << pl.medium(AxisDirection::AxisR));
0155
0156 pl.envelope[Acts::AxisDirection::AxisR] = {lCfg.envelope.first,
0157 lCfg.envelope.second};
0158 pl.envelope[Acts::AxisDirection::AxisZ] = {lCfg.envelope.second,
0159 lCfg.envelope.second};
0160 if (nb0 >= 0 && nb1 >= 0) {
0161 layers.push_back(
0162 m_cfg.layerCreator->cylinderLayer(gctx, lSurfaces, nb0, nb1, pl));
0163 } else {
0164 layers.push_back(
0165 m_cfg.layerCreator->cylinderLayer(gctx, lSurfaces, nt0, nt1, pl));
0166 }
0167 } else {
0168 ProtoLayer pl(gctx, lSurfaces);
0169 ACTS_DEBUG("- creating DiscLayer with "
0170 << lSurfaces.size()
0171 << " surfaces at z = " << pl.medium(AxisDirection::AxisZ));
0172
0173 pl.envelope[Acts::AxisDirection::AxisR] = {lCfg.envelope.first,
0174 lCfg.envelope.second};
0175 pl.envelope[Acts::AxisDirection::AxisZ] = {lCfg.envelope.second,
0176 lCfg.envelope.second};
0177 if (nb0 >= 0 && nb1 >= 0) {
0178 layers.push_back(
0179 m_cfg.layerCreator->discLayer(gctx, lSurfaces, nb0, nb1, pl));
0180 } else {
0181 layers.push_back(
0182 m_cfg.layerCreator->discLayer(gctx, lSurfaces, nt0, nt1, pl));
0183 }
0184 }
0185 };
0186
0187 for (auto layerCfg : layerConfigs) {
0188 ACTS_DEBUG("- layer configuration found for layer " << layerCfg.volumeName
0189 << " with sensors ");
0190 for (auto& sensor : layerCfg.sensorNames) {
0191 ACTS_DEBUG(" - sensor: " << sensor);
0192 }
0193 if (!layerCfg.parseRanges.empty()) {
0194 for (const auto& [axisDir, pRange] : layerCfg.parseRanges) {
0195 ACTS_DEBUG("- layer parsing restricted in "
0196 << axisDirectionName(axisDir) << " to [" << pRange.first
0197 << "/" << pRange.second << "].");
0198 }
0199 }
0200 if (!layerCfg.splitConfigs.empty()) {
0201 for (const auto& [axisDir, tConfig] : layerCfg.splitConfigs) {
0202 ACTS_DEBUG("- layer splitting attempt in " << axisDirectionName(axisDir)
0203 << " with tolerance "
0204 << tConfig << ".");
0205 }
0206 }
0207
0208
0209
0210 TGeoVolume* tVolume =
0211 gGeoManager->FindVolumeFast(layerCfg.volumeName.c_str());
0212 TGeoHMatrix gmatrix = TGeoIdentity((layerCfg.volumeName + "ID").c_str());
0213
0214 if (tVolume == nullptr) {
0215 tVolume = gGeoManager->GetTopVolume();
0216 ACTS_DEBUG("- search volume is TGeo top volume");
0217 } else {
0218 ACTS_DEBUG("- setting search volume to " << tVolume->GetName());
0219
0220 auto node = TGeoParser::findNodeRecursive(gGeoManager->GetTopNode(),
0221 tVolume->GetName());
0222
0223 if (node == nullptr) {
0224 std::string volname(tVolume->GetName());
0225 throw std::invalid_argument("Could not locate node for " + volname);
0226 }
0227
0228 gmatrix = *(node->GetMatrix());
0229 }
0230
0231 if (tVolume != nullptr) {
0232 TGeoParser::Options tgpOptions;
0233 tgpOptions.volumeNames = {layerCfg.volumeName};
0234 tgpOptions.targetNames = layerCfg.sensorNames;
0235 tgpOptions.parseRanges = layerCfg.parseRanges;
0236 tgpOptions.unit = m_cfg.unit;
0237 TGeoParser::State tgpState;
0238 tgpState.volume = tVolume;
0239
0240 ACTS_DEBUG("- applying " << layerCfg.parseRanges.size()
0241 << " search restrictions.");
0242 for (const auto& [axisDir, pRange] : layerCfg.parseRanges) {
0243 ACTS_VERBOSE(" - range " << axisDirectionName(axisDir) << " within [ "
0244 << pRange.first << ", " << pRange.second
0245 << "]");
0246 }
0247
0248 TGeoParser::select(tgpState, tgpOptions, gmatrix);
0249
0250 ACTS_DEBUG("- number of selected nodes found : "
0251 << tgpState.selectedNodes.size());
0252
0253 for (auto& snode : tgpState.selectedNodes) {
0254 auto identifier =
0255 m_cfg.identifierProvider != nullptr
0256 ? m_cfg.identifierProvider->identify(gctx, *snode.node)
0257 : TGeoDetectorElement::Identifier();
0258
0259 auto tgElement = m_cfg.detectorElementFactory(
0260 identifier, *snode.node, *snode.transform, layerCfg.localAxes,
0261 m_cfg.unit, nullptr);
0262
0263 std::vector<std::shared_ptr<const Acts::TGeoDetectorElement>>
0264 tgElements =
0265 (m_cfg.detectorElementSplitter == nullptr)
0266 ? std::vector<std::shared_ptr<
0267 const Acts::TGeoDetectorElement>>{tgElement}
0268 : m_cfg.detectorElementSplitter->split(gctx, tgElement);
0269
0270 for (const auto& tge : tgElements) {
0271 m_elementStore.push_back(tge);
0272 layerSurfaces.push_back(tge->surface().getSharedPtr());
0273 }
0274 }
0275
0276 ACTS_DEBUG("- created TGeoDetectorElements : " << layerSurfaces.size());
0277
0278 if (m_cfg.protoLayerHelper != nullptr && !layerCfg.splitConfigs.empty()) {
0279 auto protoLayers = m_cfg.protoLayerHelper->protoLayers(
0280 gctx, unpack_shared_vector(layerSurfaces), layerCfg.splitConfigs);
0281 ACTS_DEBUG("- splitting into " << protoLayers.size() << " layers.");
0282
0283
0284
0285 const bool is_loc0_n_config =
0286 layerCfg.binning0.size() == protoLayers.size();
0287 const bool is_loc0_autobinning =
0288 (layerCfg.binning0.size() == 1) &&
0289 (std::get<int>(layerCfg.binning0.at(0)) <= 0);
0290 const bool is_loc1_n_config =
0291 layerCfg.binning1.size() == protoLayers.size();
0292 const bool is_loc1_autobinning =
0293 (layerCfg.binning1.size() == 1) &&
0294 (std::get<int>(layerCfg.binning1.at(0)) <= 0);
0295 if ((!is_loc0_n_config && !is_loc0_autobinning) ||
0296 (!is_loc1_n_config && !is_loc1_autobinning)) {
0297 throw std::invalid_argument(
0298 "Incorrect binning configuration found: Number of configurations "
0299 "does not match number of protolayers in subvolume " +
0300 layerCfg.volumeName + ". Quitting.");
0301 }
0302 unsigned int layer_id = 0;
0303 for (auto& pLayer : protoLayers) {
0304 layerSurfaces.clear();
0305
0306 for (const auto& lsurface : pLayer.surfaces()) {
0307 layerSurfaces.push_back(lsurface->getSharedPtr());
0308 }
0309 fillLayer(layerSurfaces, layerCfg, layer_id);
0310 layer_id++;
0311 }
0312 } else {
0313 fillLayer(layerSurfaces, layerCfg);
0314 }
0315 }
0316 }
0317 return;
0318 }
0319
0320 std::shared_ptr<Acts::TGeoDetectorElement>
0321 Acts::TGeoLayerBuilder::defaultElementFactory(
0322 const TGeoDetectorElement::Identifier& identifier, const TGeoNode& tGeoNode,
0323 const TGeoMatrix& tGeoMatrix, const std::string& axes, double scalor,
0324 std::shared_ptr<const Acts::ISurfaceMaterial> material) {
0325 return std::make_shared<TGeoDetectorElement>(
0326 identifier, tGeoNode, tGeoMatrix, axes, scalor, std::move(material));
0327 }