Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-06 08:10:22

0001 // This file is part of the Acts project.
0002 //
0003 // Copyright (C) 2023 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 http://mozilla.org/MPL/2.0/.
0008 
0009 #include "Acts/Detector/detail/BlueprintHelper.hpp"
0010 
0011 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/Definitions/Tolerance.hpp"
0013 #include "Acts/Geometry/VolumeBounds.hpp"
0014 
0015 #include <array>
0016 
0017 namespace {
0018 
0019 std::array<Acts::Vector3, 2u> endPointsXYZ(
0020     const Acts::Experimental::Blueprint::Node& node, Acts::BinningValue bVal) {
0021   unsigned int bIdx = 0;
0022   switch (bVal) {
0023     case Acts::binX:
0024       bIdx = 0;
0025       break;
0026     case Acts::binY:
0027       bIdx = 1;
0028       break;
0029     case Acts::binZ:
0030       bIdx = 2;
0031       break;
0032     default:
0033       break;
0034   }
0035   Acts::Vector3 axis = node.transform.rotation().col(bIdx);
0036   auto halfL = node.boundaryValues[bIdx];
0037   Acts::Vector3 center = node.transform.translation();
0038   Acts::Vector3 p0 = center - halfL * axis;
0039   Acts::Vector3 p1 = center + halfL * axis;
0040   return {p0, p1};
0041 }
0042 
0043 }  // namespace
0044 
0045 void Acts::Experimental::detail::BlueprintHelper::sort(Blueprint::Node& node,
0046                                                        bool recursive) {
0047   if (node.children.size() < 2u) {
0048     return;
0049   }
0050   // Sort along x, y, z
0051   if (node.binning.size() == 1) {
0052     auto bVal = node.binning.front();
0053     // x,y,z binning along the axis
0054     if (bVal == binX || bVal == binY || bVal == binZ) {
0055       Vector3 nodeCenter = node.transform.translation();
0056       Vector3 nodeSortAxis = node.transform.rotation().col(bVal);
0057       std::sort(
0058           node.children.begin(), node.children.end(),
0059           [&](const auto& a, const auto& b) {
0060             return (a->transform.translation() - nodeCenter).dot(nodeSortAxis) <
0061                    (b->transform.translation() - nodeCenter).dot(nodeSortAxis);
0062           });
0063     } else if (bVal == binR && node.boundsType == VolumeBounds::eCylinder) {
0064       std::sort(node.children.begin(), node.children.end(),
0065                 [](const auto& a, const auto& b) {
0066                   return 0.5 * (a->boundaryValues[0] + a->boundaryValues[1]) <
0067                          0.5 * (b->boundaryValues[0] + b->boundaryValues[1]);
0068                 });
0069     }
0070   }
0071 
0072   // Sort the children
0073   if (recursive) {
0074     for (auto& child : node.children) {
0075       sort(*child, true);
0076     }
0077   }
0078 }
0079 
0080 void Acts::Experimental::detail::BlueprintHelper::fillGaps(
0081     Blueprint::Node& node, bool adjustToParent) {
0082   // Return if this is a leaf node
0083   if (node.isLeaf()) {
0084     return;
0085   }
0086   if (node.boundsType == VolumeBounds::eCylinder && node.binning.size() == 1) {
0087     fillGapsCylindrical(node, adjustToParent);
0088   } else if (node.boundsType == VolumeBounds::eCuboid &&
0089              node.binning.size() == 1) {
0090     // Doesn't look like NOT adjusting to parent
0091     // makes sense. The gaps are not going
0092     // to be filled in non-binned directions
0093     fillGapsCuboidal(node, adjustToParent);
0094   } else {
0095     throw std::runtime_error(
0096         "BlueprintHelper: gap filling is not implemented for "
0097         "this boundary type");
0098   }
0099 }
0100 
0101 void Acts::Experimental::detail::BlueprintHelper::fillGapsCylindrical(
0102     Blueprint::Node& node, bool adjustToParent) {
0103   // Nodes must be sorted
0104   sort(node, false);
0105 
0106   // Container values
0107   auto cInnerR = node.boundaryValues[0];
0108   auto cOuterR = node.boundaryValues[1];
0109   auto cHalfZ = node.boundaryValues[2];
0110 
0111   std::vector<std::unique_ptr<Blueprint::Node>> gaps;
0112   // Only 1D binning implemented for the moment
0113   auto bVal = node.binning.front();
0114   if (bVal == binZ) {
0115     // adjust inner/outer radius
0116     if (adjustToParent) {
0117       std::for_each(node.children.begin(), node.children.end(),
0118                     [&](auto& child) {
0119                       child->boundaryValues[0] = cInnerR;
0120                       child->boundaryValues[1] = cOuterR;
0121                     });
0122     }
0123     auto [negC, posC] = endPointsXYZ(node, bVal);
0124     // Assume sorted along the local z axis
0125     unsigned int igap = 0;
0126     for (auto& child : node.children) {
0127       auto [neg, pos] = endPointsXYZ(*child, bVal);
0128       ActsScalar gapSpan = (neg - negC).norm();
0129       if (gapSpan > s_onSurfaceTolerance) {
0130         // Fill a gap node
0131         auto gapName = node.name + "_gap_" + std::to_string(igap);
0132         auto gapTransform = Transform3::Identity();
0133         gapTransform.rotate(node.transform.rotation());
0134         gapTransform.pretranslate(0.5 * (neg + negC));
0135         auto gap = std::make_unique<Blueprint::Node>(
0136             gapName, gapTransform, VolumeBounds::eCylinder,
0137             std::vector<ActsScalar>{cInnerR, cOuterR, 0.5 * gapSpan});
0138         gaps.push_back(std::move(gap));
0139         ++igap;
0140       }
0141       // Set to new current negative value
0142       negC = pos;
0143     }
0144     // Check if a last one needs to be filled
0145     ActsScalar gapSpan = (negC - posC).norm();
0146     if (gapSpan > s_onSurfaceTolerance) {
0147       // Fill a gap node
0148       auto gapName = node.name + "_gap_" + std::to_string(igap);
0149       auto gapTransform = Transform3::Identity();
0150       gapTransform.rotate(node.transform.rotation());
0151       gapTransform.pretranslate(0.5 * (negC + posC));
0152       auto gap = std::make_unique<Blueprint::Node>(
0153           gapName, gapTransform, VolumeBounds::eCylinder,
0154           std::vector<ActsScalar>{cInnerR, cOuterR, 0.5 * gapSpan});
0155       gaps.push_back(std::move(gap));
0156     }
0157 
0158   } else if (bVal == binR) {
0159     // We have binning in R present
0160     if (adjustToParent) {
0161       std::for_each(node.children.begin(), node.children.end(),
0162                     [&](auto& child) {
0163                       child->transform = node.transform;
0164                       child->boundaryValues[2] = cHalfZ;
0165                     });
0166     }
0167     // Fill the gaps in R
0168     unsigned int igap = 0;
0169     ActsScalar lastR = cInnerR;
0170     for (auto& child : node.children) {
0171       ActsScalar iR = child->boundaryValues[0];
0172       if (std::abs(iR - lastR) > s_onSurfaceTolerance) {
0173         auto gap = std::make_unique<Blueprint::Node>(
0174             node.name + "_gap_" + std::to_string(igap), node.transform,
0175             VolumeBounds::eCylinder,
0176             std::vector<ActsScalar>{lastR, iR, cHalfZ});
0177         gaps.push_back(std::move(gap));
0178         ++igap;
0179       }
0180       // Set to new outer radius
0181       lastR = child->boundaryValues[1];
0182     }
0183     // Check if a last one needs to be filled
0184     if (std::abs(lastR - cOuterR) > s_onSurfaceTolerance) {
0185       auto gap = std::make_unique<Blueprint::Node>(
0186           node.name + "_gap_" + std::to_string(igap), node.transform,
0187           VolumeBounds::eCylinder,
0188           std::vector<ActsScalar>{lastR, cOuterR, cHalfZ});
0189       gaps.push_back(std::move(gap));
0190     }
0191   } else {
0192     throw std::runtime_error(
0193         "BlueprintHelper: gap filling not implemented for "
0194         "cylinder and this binning type.");
0195   }
0196 
0197   // Insert
0198   for (auto& gap : gaps) {
0199     node.add(std::move(gap));
0200   }
0201 
0202   // Sort again after inserting
0203   sort(node, false);
0204   // Fill the gaps recursively
0205   for (auto& child : node.children) {
0206     fillGaps(*child, adjustToParent);
0207   }
0208 }
0209 
0210 void Acts::Experimental::detail::BlueprintHelper::fillGapsCuboidal(
0211     Blueprint::Node& node, bool adjustToParent) {
0212   // Nodes must be sorted
0213   sort(node, false);
0214 
0215   // Cuboidal detector binnings
0216   std::array<Acts::BinningValue, 3u> allowedBinVals = {binX, binY, binZ};
0217 
0218   std::vector<std::unique_ptr<Blueprint::Node>> gaps;
0219   auto binVal = node.binning.front();
0220 
0221   // adjust non-binned directions
0222   if (adjustToParent) {
0223     std::for_each(node.children.begin(), node.children.end(), [&](auto& child) {
0224       for (auto bv : allowedBinVals) {
0225         if (bv != binVal) {
0226           // Both boundary values and translation
0227           // have to be adjusted
0228           child->boundaryValues[bv] = node.boundaryValues[bv];
0229           child->transform.translation()[bv] = node.transform.translation()[bv];
0230         }
0231       }
0232     });
0233   }
0234   auto [negC, posC] = endPointsXYZ(node, binVal);
0235 
0236   // Assume sorted along the local binned axis
0237   unsigned int igap = 0;
0238   for (auto& child : node.children) {
0239     auto [neg, pos] = endPointsXYZ(*child, binVal);
0240     ActsScalar gapSpan = (neg - negC).norm();
0241     if (gapSpan > s_onSurfaceTolerance) {
0242       // Fill a gap node
0243       auto gapName = node.name + "_gap_" + std::to_string(igap);
0244       auto gapTransform = Transform3::Identity();
0245       gapTransform.rotate(node.transform.rotation());
0246       gapTransform.pretranslate(0.5 * (neg + negC));
0247       std::vector<ActsScalar> gapBounds{0, 0, 0};
0248       gapBounds[binVal] = 0.5 * gapSpan;
0249       for (auto bv : allowedBinVals) {
0250         if (bv != binVal) {
0251           gapBounds[bv] = node.boundaryValues[bv];
0252         }
0253       }
0254       auto gap = std::make_unique<Blueprint::Node>(
0255           gapName, gapTransform, VolumeBounds::eCuboid, gapBounds);
0256       gaps.push_back(std::move(gap));
0257       ++igap;
0258     }
0259     // Set to new current negative value
0260     negC = pos;
0261   }
0262   // Check if a last one needs to be filled
0263   ActsScalar gapSpan = (negC - posC).norm();
0264   if (gapSpan > s_onSurfaceTolerance) {
0265     // Fill a gap node
0266     auto gapName = node.name + "_gap_" + std::to_string(igap);
0267     auto gapTransform = Transform3::Identity();
0268     gapTransform.rotate(node.transform.rotation());
0269     gapTransform.pretranslate(0.5 * (negC + posC));
0270     std::vector<ActsScalar> gapBounds{0, 0, 0};
0271     gapBounds[binVal] = 0.5 * gapSpan;
0272     for (auto bv : allowedBinVals) {
0273       if (bv != binVal) {
0274         gapBounds[bv] = node.boundaryValues[bv];
0275       }
0276     }
0277     auto gap = std::make_unique<Blueprint::Node>(
0278         gapName, gapTransform, VolumeBounds::eCuboid, gapBounds);
0279     gaps.push_back(std::move(gap));
0280   }
0281 
0282   // Insert
0283   for (auto& gap : gaps) {
0284     node.add(std::move(gap));
0285   }
0286 
0287   // Sort again after inserting
0288   sort(node, false);
0289   // Fill the gaps recursively
0290   for (auto& child : node.children) {
0291     fillGaps(*child, adjustToParent);
0292   }
0293 }