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