Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-11-08 09:19:40

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 "ActsPlugins/DD4hep/DD4hepBlueprintFactory.hpp"
0010 
0011 #include "Acts/Detector/GeometryIdGenerator.hpp"
0012 #include "Acts/Detector/IndexedRootVolumeFinderBuilder.hpp"
0013 #include "Acts/Utilities/StringHelpers.hpp"
0014 #include "ActsPlugins/DD4hep/DD4hepBinningHelpers.hpp"
0015 #include "ActsPlugins/DD4hep/DD4hepConversionHelpers.hpp"
0016 
0017 using namespace Acts;
0018 using namespace Acts::Experimental;
0019 
0020 namespace ActsPlugins {
0021 
0022 DD4hepBlueprintFactory::DD4hepBlueprintFactory(
0023     const Config& cfg, std::unique_ptr<const Logger> mlogger)
0024     : m_cfg(cfg), m_logger(std::move(mlogger)) {
0025   ACTS_DEBUG("UnitLength conversion factor (DD4hep -> Acts): " << unitLength);
0026 }
0027 
0028 std::unique_ptr<Gen2Blueprint::Node> DD4hepBlueprintFactory::create(
0029     Cache& cache, const GeometryContext& gctx,
0030     const dd4hep::DetElement& dd4hepElement) const {
0031   ACTS_DEBUG("Drawing a blueprint from the DD4hep element '"
0032              << dd4hepElement.name() << "'.");
0033 
0034   // Create the root node
0035   std::vector<double> bValues = {0., 150., 1000.};
0036   std::vector<AxisDirection> binning = {AxisDirection::AxisR};
0037   auto root = std::make_unique<Gen2Blueprint::Node>(
0038       dd4hepElement.name(), Transform3::Identity(), VolumeBounds::eCylinder,
0039       bValues, binning);
0040 
0041   // Recursively parse the tree
0042   recursiveParse(cache, *root, gctx, dd4hepElement);
0043   // Return the top node
0044   return root;
0045 }
0046 
0047 void DD4hepBlueprintFactory::recursiveParse(
0048     Cache& cache, Gen2Blueprint::Node& mother, const GeometryContext& gctx,
0049     const dd4hep::DetElement& dd4hepElement, unsigned int hiearchyLevel) const {
0050   // This will allow to skip empty hierarchy levels
0051   Gen2Blueprint::Node* current = &mother;
0052   unsigned int hierarchyAddOn = 0;
0053 
0054   std::string ofs(hiearchyLevel * 2u, ' ');
0055 
0056   // Node types
0057   std::vector<std::string> nodeTypes = {"acts_world", "acts_container",
0058                                         "acts_volume"};
0059   for (const auto& nType : nodeTypes) {
0060     // Check if it complies with the given definition
0061     bool ntt = getParamOr<bool>(nType, dd4hepElement, false);
0062     if (ntt) {
0063       ACTS_DEBUG(ofs << "ACTS node '" << nType
0064                      << "' attached to dd4hep element '" << dd4hepElement.name()
0065                      << "',");
0066       // Extract potential internal builders and tools
0067       auto [internalsBuilder, rootsFinderBuilder, geoIdGenerator, auxInt,
0068             extOpt] =
0069           extractInternals(cache.dd4hepStore, gctx, dd4hepElement, nType);
0070       // Extract the bounds type, values and binning
0071       auto [transform, bValueType, bValues, binning, auxExt] =
0072           extractExternals(gctx, dd4hepElement, nType, extOpt);
0073       // Screen output of position and shape
0074       ACTS_DEBUG(ofs << " - translation  : "
0075                      << toString(transform.translation()));
0076       ACTS_DEBUG(ofs << " - bounds type  : " << bValueType);
0077       ACTS_DEBUG(ofs << " - bound values : " << toString(bValues));
0078       // If it is not the world node, create a new one
0079       if (nType == "acts_world") {
0080         mother.transform = transform;
0081         mother.boundsType = bValueType;
0082         mother.boundaryValues = bValues;
0083         mother.binning = binning;
0084 
0085       } else if (nType == "acts_container") {
0086         // Creating the branch node
0087         auto branch = std::make_unique<Gen2Blueprint::Node>(
0088             dd4hepElement.name(), transform, bValueType, bValues, binning);
0089         current = branch.get();
0090         mother.add(std::move(branch));
0091 
0092       } else if (nType == "acts_volume") {
0093         // Crreating a leaf node
0094         auto leaf = std::make_unique<Gen2Blueprint::Node>(
0095             dd4hepElement.name(), transform, bValueType, bValues);
0096         current = leaf.get();
0097         mother.add(std::move(leaf));
0098       }
0099       // Current is set now appropriately, adding auxiliary information
0100       if (!auxExt.empty()) {
0101         ACTS_VERBOSE(ofs << " - " << auxExt);
0102         current->auxiliary.push_back(auxExt);
0103       }
0104       // Adding the internals builder - if present
0105       if (internalsBuilder != nullptr) {
0106         ACTS_VERBOSE(ofs << " - " << auxInt[0u]);
0107         current->internalsBuilder = internalsBuilder;
0108       }
0109       // Adding root finder builder - if present
0110       if (rootsFinderBuilder != nullptr) {
0111         ACTS_VERBOSE(ofs << " - " << auxInt[1u]);
0112         current->rootVolumeFinderBuilder = rootsFinderBuilder;
0113       }
0114 
0115       // Check for proto material for the portals, max portal number
0116       // can be changed in configuration
0117       for (unsigned int p = 0u; p < m_cfg.maxPortals; ++p) {
0118         std::string pmName = "acts_portal_proto_material_" + std::to_string(p);
0119         auto protoMaterial = getParamOr<bool>(pmName, dd4hepElement, false);
0120         if (protoMaterial) {
0121           ACTS_VERBOSE(ofs << " - proto material binning for portal " << p
0122                            << " found");
0123           auto pmProtoAxis = DD4hepBinningHelpers::convertBinning(
0124               dd4hepElement, pmName + "_binning");
0125           // Strip out the axis without expansion
0126           std::vector<DirectedProtoAxis> pmAxisBare = {};
0127           for (const auto& [dpAxis, nB] : pmProtoAxis) {
0128             pmAxisBare.emplace_back(dpAxis);
0129           }
0130           current->portalMaterialBinning[p] = pmAxisBare;
0131           ACTS_VERBOSE(ofs << " - binning description is "
0132                            << current->portalMaterialBinning[p]);
0133         }
0134       }
0135 
0136       // Adding geo Id generator - if present
0137       if (geoIdGenerator != nullptr) {
0138         ACTS_VERBOSE(ofs << " - " << auxInt[2u]);
0139         current->geoIdGenerator = geoIdGenerator;
0140       }
0141     }
0142   }
0143 
0144   // Step down to the children - not possible for leaf nodes
0145   const dd4hep::DetElement::Children& children = dd4hepElement.children();
0146   if (!children.empty()) {
0147     ACTS_VERBOSE(ofs << "dd4hep element '" << dd4hepElement.name() << "' has "
0148                      << children.size() << " children.");
0149     for (auto& child : children) {
0150       dd4hep::DetElement dd4hepChild = child.second;
0151       recursiveParse(cache, *current, gctx, dd4hepChild,
0152                      hiearchyLevel + hierarchyAddOn);
0153     }
0154   }
0155 }
0156 
0157 std::tuple<Transform3, VolumeBounds::BoundsType, std::vector<double>,
0158            std::vector<AxisDirection>, std::string>
0159 DD4hepBlueprintFactory::extractExternals(
0160     [[maybe_unused]] const GeometryContext& gctx,
0161     const dd4hep::DetElement& dd4hepElement, const std::string& baseName,
0162     const std::optional<Extent>& extOpt) const {
0163   std::string aux = "";
0164 
0165   /// Get the transform - extract from values first
0166   auto transform = extractTransform(dd4hepElement, baseName, unitLength);
0167 
0168   // Get the bounds type
0169   auto bValueInt =
0170       getParamOr<int>(baseName + "_type", dd4hepElement,
0171                       static_cast<int>(VolumeBounds::BoundsType::eOther));
0172   auto bValueType = static_cast<VolumeBounds::BoundsType>(bValueInt);
0173   std::vector<double> bValues = {};
0174 
0175   // Get the bound values from parsed internals if possible
0176   if (extOpt.has_value() && bValueType == VolumeBounds::BoundsType::eCylinder) {
0177     // Set as defaults
0178     bValues = {0., 0., 0.};
0179     auto parsedExtent = extOpt.value();
0180     if (parsedExtent.constrains(AxisDirection::AxisR)) {
0181       bValues[0u] = std::floor(parsedExtent.min(AxisDirection::AxisR));
0182       bValues[1u] = std::ceil(parsedExtent.max(AxisDirection::AxisR));
0183     }
0184     if (parsedExtent.constrains(AxisDirection::AxisZ)) {
0185       double minZ = parsedExtent.min(AxisDirection::AxisZ) > 0.
0186                         ? std::floor(parsedExtent.min(AxisDirection::AxisZ))
0187                         : std::ceil(parsedExtent.min(AxisDirection::AxisZ));
0188       double maxZ = parsedExtent.max(AxisDirection::AxisZ) > 0.
0189                         ? std::floor(parsedExtent.max(AxisDirection::AxisZ))
0190                         : std::ceil(parsedExtent.max(AxisDirection::AxisZ));
0191       bValues[2u] = 0.5 * (maxZ - minZ);
0192       transform.translation().z() = 0.5 * (maxZ + minZ);
0193     }
0194     ACTS_VERBOSE("   cylindrical bounds determined from internals as "
0195                  << toString(bValues));
0196   }
0197 
0198   // Get the bounds values from the series if not found before
0199   if (bValues.empty()) {
0200     bValues =
0201         extractSeries<double>(dd4hepElement, baseName + "_bvalues", unitLength);
0202     ACTS_VERBOSE(" - cylindrical determined from variant parameters as "
0203                  << toString(bValues));
0204   }
0205 
0206   // Get the binning values
0207   auto binningString =
0208       getParamOr<std::string>(baseName + "_binning", dd4hepElement, "");
0209   std::vector<AxisDirection> bBinning = stringToAxisDirections(binningString);
0210   if (!binningString.empty()) {
0211     aux += "vol. binning : " + binningString;
0212   }
0213   // Return the tuple
0214   return {transform, bValueType, bValues, bBinning, aux};
0215 }
0216 
0217 std::tuple<std::shared_ptr<const IInternalStructureBuilder>,
0218            std::shared_ptr<const IRootVolumeFinderBuilder>,
0219            std::shared_ptr<const IGeometryIdGenerator>,
0220            std::array<std::string, 3u>, std::optional<Extent>>
0221 DD4hepBlueprintFactory::extractInternals(
0222     DD4hepDetectorElement::Store& dd4hepStore, const GeometryContext& gctx,
0223     const dd4hep::DetElement& dd4hepElement,
0224     const std::string& baseName) const {
0225   // Return objects
0226   std::shared_ptr<const IInternalStructureBuilder> internalsBuilder = nullptr;
0227   std::shared_ptr<const IRootVolumeFinderBuilder> rootsFinderBuilder = nullptr;
0228   std::shared_ptr<const IGeometryIdGenerator> geoIdGenerator = nullptr;
0229   /// The hand-over information for externals
0230   std::optional<Extent> ext = std::nullopt;
0231   /// Auxiliary information
0232   std::array<std::string, 3u> aux = {"", "", ""};
0233 
0234   // Check for internal structure builder
0235   auto internals =
0236       getParamOr<bool>(baseName + "_internals", dd4hepElement, false);
0237   if (internals) {
0238     auto internalsType = getParamOr<std::string>(baseName + "_internals_type",
0239                                                  dd4hepElement, "");
0240     if (internalsType == "layer") {
0241       aux[0u] = "int. struct : layer";
0242       // Create a new layer builder
0243       DD4hepLayerStructure::Options lOptions;
0244       lOptions.name = dd4hepElement.name();
0245       // Check whether internal/sensitive surfaces should have directly
0246       // translated material
0247       auto convertMaterial = getParamOr<bool>(
0248           "acts_surface_material_conversion", dd4hepElement, false);
0249       lOptions.conversionOptions.convertMaterial = convertMaterial;
0250       // Check if the extent should be measured
0251       auto interenalsMeasure = getParamOr<std::string>(
0252           baseName + "_internals_measure", dd4hepElement, "");
0253       auto internalsClearance =
0254           unitLength * getParamOr<double>(baseName + "_internals_clearance",
0255                                           dd4hepElement, 0.);
0256       auto internalAxisDirections = stringToAxisDirections(interenalsMeasure);
0257       if (!internalAxisDirections.empty()) {
0258         ACTS_VERBOSE(" - internals extent measurement requested");
0259         Extent internalsExtent;
0260         ExtentEnvelope clearance = ExtentEnvelope::Zero();
0261         for (const auto& bv : internalAxisDirections) {
0262           ACTS_VERBOSE("   -> measuring extent for " << axisDirectionName(bv));
0263           ACTS_VERBOSE("   -> with clearance :" << internalsClearance);
0264           clearance[bv] = {internalsClearance, internalsClearance};
0265         }
0266         internalsExtent.setEnvelope(clearance);
0267         lOptions.extent = internalsExtent;
0268         lOptions.extentConstraints = internalAxisDirections;
0269       }
0270       // Create the builder from the dd4hep element
0271       auto [ib, extOpt] = m_cfg.layerStructure->builder(
0272           dd4hepStore, gctx, dd4hepElement, lOptions);
0273       internalsBuilder = std::move(ib);
0274       if (extOpt.has_value()) {
0275         ACTS_VERBOSE(" - internals extent measured as "
0276                      << extOpt.value().toString());
0277       }
0278       ext = extOpt;
0279     }
0280   }
0281 
0282   // Check for root volume finder
0283   auto rootFinder = getParamOr<std::string>(baseName + "_root_volume_finder",
0284                                             dd4hepElement, "");
0285   if (rootFinder == "indexed") {
0286     aux[1u] = "root finder : indexed";
0287     std::vector<AxisDirection> binning = {AxisDirection::AxisZ,
0288                                           AxisDirection::AxisR};
0289     rootsFinderBuilder =
0290         std::make_shared<IndexedRootVolumeFinderBuilder>(binning);
0291   }
0292 
0293   // Check for geo Id generator
0294   auto geoIdGen =
0295       getParamOr<std::string>(baseName + "_geo_id", dd4hepElement, "");
0296   if (geoIdGen == "incremental") {
0297     aux[2u] = "geo_id gen. : incremental";
0298     GeometryIdGenerator::Config geoIdCfg;
0299     geoIdGenerator = std::make_shared<GeometryIdGenerator>(geoIdCfg);
0300   } else if (geoIdGen == "container") {
0301     aux[2u] = "geo_id gen. : container";
0302     GeometryIdGenerator::Config geoIdCfg;
0303     geoIdCfg.containerMode = true;
0304     geoIdCfg.containerId =
0305         getParamOr<int>(baseName + "_geo_id_base", dd4hepElement, 1);
0306     geoIdGenerator = std::make_shared<GeometryIdGenerator>(geoIdCfg);
0307   }
0308 
0309   return {internalsBuilder, rootsFinderBuilder, geoIdGenerator, aux, ext};
0310 }
0311 
0312 }  // namespace ActsPlugins