Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-18 08:13:29

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