File indexing completed on 2025-12-16 09:23:18
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "Acts/Seeding2/DoubletSeedFinder.hpp"
0010
0011 #include "Acts/EventData/SpacePointContainer2.hpp"
0012 #include "Acts/Utilities/MathHelpers.hpp"
0013
0014 #include <stdexcept>
0015
0016 #include <boost/mp11.hpp>
0017 #include <boost/mp11/algorithm.hpp>
0018
0019 namespace Acts {
0020
0021 namespace {
0022
0023 template <bool isBottomCandidate, bool interactionPointCut, bool sortedByR,
0024 bool experimentCuts>
0025 class Impl final : public DoubletSeedFinder {
0026 public:
0027 explicit Impl(const DerivedConfig& config) : m_cfg(config) {}
0028
0029 const DerivedConfig& config() const override { return m_cfg; }
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041 template <typename CandidateSps>
0042 void createDoubletsImpl(const ConstSpacePointProxy2& middleSp,
0043 const MiddleSpInfo& middleSpInfo,
0044 CandidateSps& candidateSps,
0045 DoubletsForMiddleSp& compatibleDoublets) const {
0046 const float impactMax =
0047 isBottomCandidate ? -m_cfg.impactMax : m_cfg.impactMax;
0048
0049 const float xM = middleSp.xy()[0];
0050 const float yM = middleSp.xy()[1];
0051 const float zM = middleSp.zr()[0];
0052 const float rM = middleSp.zr()[1];
0053 const float varianceZM = middleSp.varianceZ();
0054 const float varianceRM = middleSp.varianceR();
0055
0056
0057 const float vIPAbs = impactMax * middleSpInfo.uIP2;
0058
0059 const auto outsideRangeCheck = [](const float value, const float min,
0060 const float max) {
0061
0062
0063 return static_cast<bool>(static_cast<int>(value < min) |
0064 static_cast<int>(value > max));
0065 };
0066
0067 const auto calculateError = [&](float varianceZO, float varianceRO,
0068 float iDeltaR2, float cotTheta) {
0069 return iDeltaR2 * ((varianceZM + varianceZO) +
0070 (cotTheta * cotTheta) * (varianceRM + varianceRO));
0071 };
0072
0073 if constexpr (sortedByR) {
0074
0075
0076 std::uint32_t offset = 0;
0077 for (ConstSpacePointProxy2 otherSp : candidateSps) {
0078 if constexpr (isBottomCandidate) {
0079
0080 if (rM - otherSp.zr()[1] <= m_cfg.deltaRMax) {
0081 break;
0082 }
0083 } else {
0084
0085 if (otherSp.zr()[1] - rM >= m_cfg.deltaRMin) {
0086 break;
0087 }
0088 }
0089
0090 ++offset;
0091 }
0092 candidateSps = candidateSps.subrange(offset);
0093 }
0094
0095 const SpacePointContainer2& container = candidateSps.container();
0096 for (auto [indexO, xyO, zrO, varianceZO, varianceRO] : candidateSps.zip(
0097 container.xyColumn(), container.zrColumn(),
0098 container.varianceZColumn(), container.varianceRColumn())) {
0099 const float xO = xyO[0];
0100 const float yO = xyO[1];
0101 const float zO = zrO[0];
0102 const float rO = zrO[1];
0103
0104 float deltaR = 0;
0105 if constexpr (isBottomCandidate) {
0106 deltaR = rM - rO;
0107
0108 if constexpr (sortedByR) {
0109
0110 if (deltaR < m_cfg.deltaRMin) {
0111 break;
0112 }
0113 }
0114 } else {
0115 deltaR = rO - rM;
0116
0117 if constexpr (sortedByR) {
0118
0119 if (deltaR > m_cfg.deltaRMax) {
0120 break;
0121 }
0122 }
0123 }
0124
0125 if constexpr (!sortedByR) {
0126 if (outsideRangeCheck(deltaR, m_cfg.deltaRMin, m_cfg.deltaRMax)) {
0127 continue;
0128 }
0129 }
0130
0131 float deltaZ = 0;
0132 if constexpr (isBottomCandidate) {
0133 deltaZ = zM - zO;
0134 } else {
0135 deltaZ = zO - zM;
0136 }
0137
0138 if (outsideRangeCheck(deltaZ, m_cfg.deltaZMin, m_cfg.deltaZMax)) {
0139 continue;
0140 }
0141
0142
0143
0144
0145
0146 const float zOriginTimesDeltaR = zM * deltaR - rM * deltaZ;
0147
0148 if (outsideRangeCheck(zOriginTimesDeltaR,
0149 m_cfg.collisionRegionMin * deltaR,
0150 m_cfg.collisionRegionMax * deltaR)) {
0151 continue;
0152 }
0153
0154
0155
0156
0157
0158 if constexpr (!interactionPointCut) {
0159
0160
0161
0162 if (outsideRangeCheck(deltaZ, -m_cfg.cotThetaMax * deltaR,
0163 m_cfg.cotThetaMax * deltaR)) {
0164 continue;
0165 }
0166
0167
0168 const float deltaX = xO - xM;
0169 const float deltaY = yO - yM;
0170
0171 const float xNewFrame =
0172 deltaX * middleSpInfo.cosPhiM + deltaY * middleSpInfo.sinPhiM;
0173 const float yNewFrame =
0174 deltaY * middleSpInfo.cosPhiM - deltaX * middleSpInfo.sinPhiM;
0175
0176 const float deltaR2 = deltaX * deltaX + deltaY * deltaY;
0177 const float iDeltaR2 = 1 / deltaR2;
0178
0179 const float uT = xNewFrame * iDeltaR2;
0180 const float vT = yNewFrame * iDeltaR2;
0181
0182 const float iDeltaR = std::sqrt(iDeltaR2);
0183 const float cotTheta = deltaZ * iDeltaR;
0184
0185 const float er =
0186 calculateError(varianceZO, varianceRO, iDeltaR2, cotTheta);
0187
0188
0189 compatibleDoublets.emplace_back(indexO, cotTheta, iDeltaR, er, uT, vT,
0190 xNewFrame, yNewFrame);
0191 continue;
0192 }
0193
0194
0195 const float deltaX = xO - xM;
0196 const float deltaY = yO - yM;
0197
0198 const float xNewFrame =
0199 deltaX * middleSpInfo.cosPhiM + deltaY * middleSpInfo.sinPhiM;
0200 const float yNewFrame =
0201 deltaY * middleSpInfo.cosPhiM - deltaX * middleSpInfo.sinPhiM;
0202
0203 const float deltaR2 = deltaX * deltaX + deltaY * deltaY;
0204 const float iDeltaR2 = 1 / deltaR2;
0205
0206 const float uT = xNewFrame * iDeltaR2;
0207 const float vT = yNewFrame * iDeltaR2;
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218 if (std::abs(rM * yNewFrame) > impactMax * xNewFrame) {
0219
0220
0221 const float vIP = (yNewFrame > 0) ? -vIPAbs : vIPAbs;
0222
0223
0224
0225
0226 const float aCoef = (vT - vIP) / (uT - middleSpInfo.uIP);
0227 const float bCoef = vIP - aCoef * middleSpInfo.uIP;
0228
0229
0230
0231 if ((bCoef * bCoef) * m_cfg.minHelixDiameter2 > 1 + aCoef * aCoef) {
0232 continue;
0233 }
0234 }
0235
0236
0237
0238
0239 if (outsideRangeCheck(deltaZ, -m_cfg.cotThetaMax * deltaR,
0240 m_cfg.cotThetaMax * deltaR)) {
0241 continue;
0242 }
0243
0244 const float iDeltaR = std::sqrt(iDeltaR2);
0245 const float cotTheta = deltaZ * iDeltaR;
0246
0247
0248 if constexpr (experimentCuts) {
0249 if (!m_cfg.experimentCuts(middleSp, container[indexO], cotTheta,
0250 isBottomCandidate)) {
0251 continue;
0252 }
0253 }
0254
0255 const float er =
0256 calculateError(varianceZO, varianceRO, iDeltaR2, cotTheta);
0257
0258
0259 compatibleDoublets.emplace_back(indexO, cotTheta, iDeltaR, er, uT, vT,
0260 xNewFrame, yNewFrame);
0261 }
0262 }
0263
0264 void createDoublets(const ConstSpacePointProxy2& middleSp,
0265 const MiddleSpInfo& middleSpInfo,
0266 SpacePointContainer2::ConstSubset& candidateSps,
0267 DoubletsForMiddleSp& compatibleDoublets) const override {
0268 createDoubletsImpl(middleSp, middleSpInfo, candidateSps,
0269 compatibleDoublets);
0270 }
0271
0272 void createDoublets(const ConstSpacePointProxy2& middleSp,
0273 const MiddleSpInfo& middleSpInfo,
0274 SpacePointContainer2::ConstRange& candidateSps,
0275 DoubletsForMiddleSp& compatibleDoublets) const override {
0276 createDoubletsImpl(middleSp, middleSpInfo, candidateSps,
0277 compatibleDoublets);
0278 }
0279
0280 private:
0281 DerivedConfig m_cfg;
0282 };
0283
0284 }
0285
0286 std::unique_ptr<DoubletSeedFinder> DoubletSeedFinder::create(
0287 const DerivedConfig& config) {
0288 using BooleanOptions =
0289 boost::mp11::mp_list<std::bool_constant<false>, std::bool_constant<true>>;
0290
0291 using IsBottomCandidateOptions = BooleanOptions;
0292 using InteractionPointCutOptions = BooleanOptions;
0293 using SortedByROptions = BooleanOptions;
0294 using ExperimentCutsOptions = BooleanOptions;
0295
0296 using DoubletOptions =
0297 boost::mp11::mp_product<boost::mp11::mp_list, IsBottomCandidateOptions,
0298 InteractionPointCutOptions, SortedByROptions,
0299 ExperimentCutsOptions>;
0300
0301 std::unique_ptr<DoubletSeedFinder> result;
0302 boost::mp11::mp_for_each<DoubletOptions>([&](auto option) {
0303 using OptionType = decltype(option);
0304
0305 using IsBottomCandidate = boost::mp11::mp_at_c<OptionType, 0>;
0306 using InteractionPointCut = boost::mp11::mp_at_c<OptionType, 1>;
0307 using SortedByR = boost::mp11::mp_at_c<OptionType, 2>;
0308 using ExperimentCuts = boost::mp11::mp_at_c<OptionType, 3>;
0309
0310 const bool configIsBottomCandidate =
0311 config.candidateDirection == Direction::Backward();
0312
0313 if (configIsBottomCandidate != IsBottomCandidate::value ||
0314 config.interactionPointCut != InteractionPointCut::value ||
0315 config.spacePointsSortedByRadius != SortedByR::value ||
0316 config.experimentCuts.connected() != ExperimentCuts::value) {
0317 return;
0318 }
0319
0320
0321 if (result != nullptr) {
0322 throw std::runtime_error(
0323 "DoubletSeedFinder: Multiple implementations found for one "
0324 "configuration");
0325 }
0326
0327
0328 result = std::make_unique<
0329 Impl<IsBottomCandidate::value, InteractionPointCut::value,
0330 SortedByR::value, ExperimentCuts::value>>(config);
0331 });
0332 if (result == nullptr) {
0333 throw std::runtime_error(
0334 "DoubletSeedFinder: No implementation found for the given "
0335 "configuration");
0336 }
0337 return result;
0338 }
0339
0340 DoubletSeedFinder::DerivedConfig::DerivedConfig(const Config& config,
0341 float bFieldInZ_)
0342 : Config(config), bFieldInZ(bFieldInZ_) {
0343
0344 const float pTPerHelixRadius = bFieldInZ;
0345 minHelixDiameter2 = square(minPt * 2 / pTPerHelixRadius) * helixCutTolerance;
0346 }
0347
0348 MiddleSpInfo DoubletSeedFinder::computeMiddleSpInfo(
0349 const ConstSpacePointProxy2& spM) {
0350 const float rM = spM.zr()[1];
0351 const float uIP = -1 / rM;
0352 const float cosPhiM = -spM.xy()[0] * uIP;
0353 const float sinPhiM = -spM.xy()[1] * uIP;
0354 const float uIP2 = uIP * uIP;
0355
0356 return {uIP, uIP2, cosPhiM, sinPhiM};
0357 }
0358
0359 }