File indexing completed on 2025-08-06 08:10:22
0001
0002
0003
0004
0005
0006
0007
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 }
0044
0045 void Acts::Experimental::detail::BlueprintHelper::sort(Blueprint::Node& node,
0046 bool recursive) {
0047 if (node.children.size() < 2u) {
0048 return;
0049 }
0050
0051 if (node.binning.size() == 1) {
0052 auto bVal = node.binning.front();
0053
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
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
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
0091
0092
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
0104 sort(node, false);
0105
0106
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
0113 auto bVal = node.binning.front();
0114 if (bVal == binZ) {
0115
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
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
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
0142 negC = pos;
0143 }
0144
0145 ActsScalar gapSpan = (negC - posC).norm();
0146 if (gapSpan > s_onSurfaceTolerance) {
0147
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
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
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
0181 lastR = child->boundaryValues[1];
0182 }
0183
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
0198 for (auto& gap : gaps) {
0199 node.add(std::move(gap));
0200 }
0201
0202
0203 sort(node, false);
0204
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
0213 sort(node, false);
0214
0215
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
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
0227
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
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
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
0260 negC = pos;
0261 }
0262
0263 ActsScalar gapSpan = (negC - posC).norm();
0264 if (gapSpan > s_onSurfaceTolerance) {
0265
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
0283 for (auto& gap : gaps) {
0284 node.add(std::move(gap));
0285 }
0286
0287
0288 sort(node, false);
0289
0290 for (auto& child : node.children) {
0291 fillGaps(*child, adjustToParent);
0292 }
0293 }