File indexing completed on 2025-12-16 09:23:19
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "Acts/Seeding2/TripletSeedFinder.hpp"
0010
0011 #include "Acts/EventData/SpacePointContainer2.hpp"
0012 #include "Acts/Utilities/MathHelpers.hpp"
0013 #include "Acts/Utilities/Zip.hpp"
0014
0015 #include <ranges>
0016
0017 #include <Eigen/Dense>
0018 #include <boost/mp11.hpp>
0019 #include <boost/mp11/algorithm.hpp>
0020
0021 namespace Acts {
0022
0023 namespace {
0024
0025
0026
0027 bool stripCoordinateCheck(float tolerance, const ConstSpacePointProxy2& sp,
0028 const std::array<float, 3>& spacePointPosition,
0029 std::array<float, 3>& outputCoordinates) {
0030 const std::array<float, 3>& topStripVector = sp.topStripVector();
0031 const std::array<float, 3>& bottomStripVector = sp.bottomStripVector();
0032 const std::array<float, 3>& stripCenterDistance = sp.stripCenterDistance();
0033
0034
0035 const std::array<float, 3> d1 = {
0036 topStripVector[1] * spacePointPosition[2] -
0037 topStripVector[2] * spacePointPosition[1],
0038 topStripVector[2] * spacePointPosition[0] -
0039 topStripVector[0] * spacePointPosition[2],
0040 topStripVector[0] * spacePointPosition[1] -
0041 topStripVector[1] * spacePointPosition[0]};
0042
0043
0044 const float bd1 = bottomStripVector[0] * d1[0] +
0045 bottomStripVector[1] * d1[1] + bottomStripVector[2] * d1[2];
0046
0047
0048
0049 const float s1 = stripCenterDistance[0] * d1[0] +
0050 stripCenterDistance[1] * d1[1] +
0051 stripCenterDistance[2] * d1[2];
0052 if (std::abs(s1) > std::abs(bd1) * tolerance) {
0053 return false;
0054 }
0055
0056
0057 const std::array<float, 3> d0 = {
0058 bottomStripVector[1] * spacePointPosition[2] -
0059 bottomStripVector[2] * spacePointPosition[1],
0060 bottomStripVector[2] * spacePointPosition[0] -
0061 bottomStripVector[0] * spacePointPosition[2],
0062 bottomStripVector[0] * spacePointPosition[1] -
0063 bottomStripVector[1] * spacePointPosition[0]};
0064
0065
0066
0067 float s0 = stripCenterDistance[0] * d0[0] + stripCenterDistance[1] * d0[1] +
0068 stripCenterDistance[2] * d0[2];
0069 if (std::abs(s0) > std::abs(bd1) * tolerance) {
0070 return false;
0071 }
0072
0073
0074
0075
0076 const std::array<float, 3>& topStripCenter = sp.topStripCenter();
0077
0078
0079
0080 s0 = s0 / bd1;
0081 outputCoordinates[0] = topStripCenter[0] + topStripVector[0] * s0;
0082 outputCoordinates[1] = topStripCenter[1] + topStripVector[1] * s0;
0083 outputCoordinates[2] = topStripCenter[2] + topStripVector[2] * s0;
0084 return true;
0085 }
0086
0087 template <bool useStripInfo, bool sortedByCotTheta>
0088 class Impl final : public TripletSeedFinder {
0089 public:
0090 explicit Impl(const DerivedConfig& config) : m_cfg(config) {}
0091
0092 const DerivedConfig& config() const override { return m_cfg; }
0093
0094 template <typename TopDoublets>
0095 void createPixelTripletTopCandidates(
0096 const ConstSpacePointProxy2& spM,
0097 const DoubletsForMiddleSp::Proxy& bottomDoublet, TopDoublets& topDoublets,
0098 TripletTopCandidates& tripletTopCandidates) const {
0099 const float rM = spM.zr()[1];
0100 const float varianceZM = spM.varianceZ();
0101 const float varianceRM = spM.varianceR();
0102
0103
0104 tripletTopCandidates.reserve(tripletTopCandidates.size() +
0105 topDoublets.size());
0106
0107 const float cotThetaB = bottomDoublet.cotTheta();
0108 const float erB = bottomDoublet.er();
0109 const float iDeltaRB = bottomDoublet.iDeltaR();
0110 const float Ub = bottomDoublet.u();
0111 const float Vb = bottomDoublet.v();
0112
0113
0114 const float iSinTheta2 = 1 + cotThetaB * cotThetaB;
0115 const float sigmaSquaredPtDependent = iSinTheta2 * m_cfg.sigmapT2perRadius;
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125 const float scatteringInRegion2 = m_cfg.multipleScattering2 * iSinTheta2;
0126
0127 std::size_t topDoubletOffset = 0;
0128 for (auto [topDoublet, topDoubletIndex] :
0129 zip(topDoublets, std::ranges::iota_view<std::size_t, std::size_t>(
0130 0, topDoublets.size()))) {
0131 const SpacePointIndex2 spT = topDoublet.spacePointIndex();
0132 const float cotThetaT = topDoublet.cotTheta();
0133
0134
0135 const float cotThetaAvg2 = cotThetaB * cotThetaT;
0136
0137
0138
0139 const float error2 = topDoublet.er() + erB +
0140 2 * (cotThetaAvg2 * varianceRM + varianceZM) *
0141 iDeltaRB * topDoublet.iDeltaR();
0142
0143 const float deltaCotTheta = cotThetaB - cotThetaT;
0144 const float deltaCotTheta2 = deltaCotTheta * deltaCotTheta;
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156 if (deltaCotTheta2 > error2 + scatteringInRegion2) {
0157 if constexpr (sortedByCotTheta) {
0158
0159
0160
0161 if (cotThetaB < cotThetaT) {
0162 break;
0163 }
0164 topDoubletOffset = topDoubletIndex + 1;
0165 }
0166 continue;
0167 }
0168
0169 const float dU = topDoublet.u() - Ub;
0170
0171 if (dU == 0) {
0172 continue;
0173 }
0174
0175
0176 const float A = (topDoublet.v() - Vb) / dU;
0177 const float S2 = 1 + A * A;
0178 const float B = Vb - A * Ub;
0179 const float B2 = B * B;
0180
0181
0182
0183 if (S2 < B2 * m_cfg.minHelixDiameter2) {
0184 continue;
0185 }
0186
0187
0188
0189
0190 const float iHelixDiameter2 = B2 / S2;
0191
0192
0193 const float p2scatterSigma = iHelixDiameter2 * sigmaSquaredPtDependent;
0194
0195 if (deltaCotTheta2 > error2 + p2scatterSigma) {
0196 if constexpr (sortedByCotTheta) {
0197 if (cotThetaB < cotThetaT) {
0198 break;
0199 }
0200 topDoubletOffset = topDoubletIndex;
0201 }
0202 continue;
0203 }
0204
0205
0206
0207
0208 const float im = std::abs((A - B * rM) * rM);
0209 if (im > m_cfg.impactMax) {
0210 continue;
0211 }
0212
0213
0214
0215 tripletTopCandidates.emplace_back(spT, B / std::sqrt(S2), im);
0216 }
0217
0218 if constexpr (sortedByCotTheta) {
0219
0220 topDoublets = topDoublets.subrange(topDoubletOffset);
0221 }
0222 }
0223
0224 template <typename TopDoublets>
0225 void createStripTripletTopCandidates(
0226 const SpacePointContainer2& spacePoints, const ConstSpacePointProxy2& spM,
0227 const DoubletsForMiddleSp::Proxy& bottomDoublet,
0228 const TopDoublets& topDoublets,
0229 TripletTopCandidates& tripletTopCandidates) const {
0230 const float rM = spM.zr()[1];
0231 const float cosPhiM = spM.xy()[0] / rM;
0232 const float sinPhiM = spM.xy()[1] / rM;
0233 const float varianceZM = spM.varianceZ();
0234 const float varianceRM = spM.varianceR();
0235
0236
0237 tripletTopCandidates.reserve(tripletTopCandidates.size() +
0238 topDoublets.size());
0239
0240 float cotThetaB = bottomDoublet.cotTheta();
0241 const float erB = bottomDoublet.er();
0242 const float iDeltaRB = bottomDoublet.iDeltaR();
0243 const float Vb = bottomDoublet.v();
0244 const float Ub = bottomDoublet.u();
0245
0246
0247 const float iSinTheta2 = 1 + cotThetaB * cotThetaB;
0248 const float sigmaSquaredPtDependent = iSinTheta2 * m_cfg.sigmapT2perRadius;
0249
0250
0251
0252
0253
0254
0255
0256
0257
0258 const float scatteringInRegion2 = m_cfg.multipleScattering2 * iSinTheta2;
0259
0260 const float sinTheta = 1 / std::sqrt(iSinTheta2);
0261 const float cosTheta = cotThetaB * sinTheta;
0262
0263
0264
0265 const std::array<float, 2> rotationTermsUVtoXY = {cosPhiM * sinTheta,
0266 sinPhiM * sinTheta};
0267
0268 for (auto topDoublet : topDoublets) {
0269
0270 float dU = topDoublet.u() - Ub;
0271 if (dU == 0) {
0272 continue;
0273 }
0274
0275
0276 const float A0 = (topDoublet.v() - Vb) / dU;
0277
0278 const float zPositionMiddle = cosTheta * std::sqrt(1 + A0 * A0);
0279
0280
0281
0282 const std::array<float, 3> positionMiddle = {
0283 rotationTermsUVtoXY[0] - rotationTermsUVtoXY[1] * A0,
0284 rotationTermsUVtoXY[0] * A0 + rotationTermsUVtoXY[1],
0285 zPositionMiddle};
0286
0287 std::array<float, 3> rMTransf{};
0288 if (!stripCoordinateCheck(m_cfg.toleranceParam, spM, positionMiddle,
0289 rMTransf)) {
0290 continue;
0291 }
0292
0293
0294 const float B0 = 2 * (Vb - A0 * Ub);
0295 const float Cb = 1 - B0 * bottomDoublet.y();
0296 const float Sb = A0 + B0 * bottomDoublet.x();
0297 const std::array<float, 3> positionBottom = {
0298 rotationTermsUVtoXY[0] * Cb - rotationTermsUVtoXY[1] * Sb,
0299 rotationTermsUVtoXY[0] * Sb + rotationTermsUVtoXY[1] * Cb,
0300 zPositionMiddle};
0301
0302 const ConstSpacePointProxy2 spB =
0303 spacePoints[bottomDoublet.spacePointIndex()];
0304 std::array<float, 3> rBTransf{};
0305 if (!stripCoordinateCheck(m_cfg.toleranceParam, spB, positionBottom,
0306 rBTransf)) {
0307 continue;
0308 }
0309
0310
0311 const float Ct = 1 - B0 * topDoublet.y();
0312 const float St = A0 + B0 * topDoublet.x();
0313 const std::array<float, 3> positionTop = {
0314 rotationTermsUVtoXY[0] * Ct - rotationTermsUVtoXY[1] * St,
0315 rotationTermsUVtoXY[0] * St + rotationTermsUVtoXY[1] * Ct,
0316 zPositionMiddle};
0317
0318 const ConstSpacePointProxy2 spT =
0319 spacePoints[topDoublet.spacePointIndex()];
0320 std::array<float, 3> rTTransf{};
0321 if (!stripCoordinateCheck(m_cfg.toleranceParam, spT, positionTop,
0322 rTTransf)) {
0323 continue;
0324 }
0325
0326
0327 const float xB = rBTransf[0] - rMTransf[0];
0328 const float yB = rBTransf[1] - rMTransf[1];
0329 const float zB = rBTransf[2] - rMTransf[2];
0330 const float xT = rTTransf[0] - rMTransf[0];
0331 const float yT = rTTransf[1] - rMTransf[1];
0332 const float zT = rTTransf[2] - rMTransf[2];
0333
0334 const float iDeltaRB2 = 1 / (xB * xB + yB * yB);
0335 const float iDeltaRT2 = 1 / (xT * xT + yT * yT);
0336
0337 cotThetaB = -zB * std::sqrt(iDeltaRB2);
0338 const float cotThetaT = zT * std::sqrt(iDeltaRT2);
0339
0340
0341 const float averageCotTheta = 0.5f * (cotThetaB + cotThetaT);
0342 const float cotThetaAvg2 = averageCotTheta * averageCotTheta;
0343
0344
0345
0346 const float error2 = topDoublet.er() + erB +
0347 2 * (cotThetaAvg2 * varianceRM + varianceZM) *
0348 iDeltaRB * topDoublet.iDeltaR();
0349
0350 const float deltaCotTheta = cotThetaB - cotThetaT;
0351 const float deltaCotTheta2 = deltaCotTheta * deltaCotTheta;
0352
0353
0354
0355
0356
0357
0358
0359
0360
0361
0362
0363 if (deltaCotTheta2 > error2 + scatteringInRegion2) {
0364
0365 continue;
0366 }
0367
0368 const float rMxy =
0369 std::sqrt(rMTransf[0] * rMTransf[0] + rMTransf[1] * rMTransf[1]);
0370 const float irMxy = 1 / rMxy;
0371 const float Ax = rMTransf[0] * irMxy;
0372 const float Ay = rMTransf[1] * irMxy;
0373
0374 const float ub = (xB * Ax + yB * Ay) * iDeltaRB2;
0375 const float vb = (yB * Ax - xB * Ay) * iDeltaRB2;
0376 const float ut = (xT * Ax + yT * Ay) * iDeltaRT2;
0377 const float vt = (yT * Ax - xT * Ay) * iDeltaRT2;
0378
0379 dU = ut - ub;
0380
0381 if (dU == 0) {
0382 continue;
0383 }
0384 const float A = (vt - vb) / dU;
0385 const float S2 = 1 + A * A;
0386 const float B = vb - A * ub;
0387 const float B2 = B * B;
0388
0389
0390
0391 if (S2 < B2 * m_cfg.minHelixDiameter2) {
0392 continue;
0393 }
0394
0395
0396
0397
0398 const float iHelixDiameter2 = B2 / S2;
0399
0400
0401 const float p2scatterSigma = iHelixDiameter2 * sigmaSquaredPtDependent;
0402
0403 if (deltaCotTheta2 > error2 + p2scatterSigma) {
0404 continue;
0405 }
0406
0407
0408
0409
0410 const float im = std::abs((A - B * rMxy) * rMxy);
0411 if (im > m_cfg.impactMax) {
0412 continue;
0413 }
0414
0415
0416
0417 tripletTopCandidates.emplace_back(spT.index(), B / std::sqrt(S2), im);
0418 }
0419 }
0420
0421 void createTripletTopCandidates(
0422 const SpacePointContainer2& spacePoints, const ConstSpacePointProxy2& spM,
0423 const DoubletsForMiddleSp::Proxy& bottomDoublet,
0424 DoubletsForMiddleSp::Range& topDoublets,
0425 TripletTopCandidates& tripletTopCandidates) const override {
0426 if constexpr (useStripInfo) {
0427 createStripTripletTopCandidates(spacePoints, spM, bottomDoublet,
0428 topDoublets, tripletTopCandidates);
0429 } else {
0430 createPixelTripletTopCandidates(spM, bottomDoublet, topDoublets,
0431 tripletTopCandidates);
0432 }
0433 }
0434
0435 void createTripletTopCandidates(
0436 const SpacePointContainer2& spacePoints, const ConstSpacePointProxy2& spM,
0437 const DoubletsForMiddleSp::Proxy& bottomDoublet,
0438 DoubletsForMiddleSp::Subset& topDoublets,
0439 TripletTopCandidates& tripletTopCandidates) const override {
0440 if constexpr (useStripInfo) {
0441 createStripTripletTopCandidates(spacePoints, spM, bottomDoublet,
0442 topDoublets, tripletTopCandidates);
0443 } else {
0444 createPixelTripletTopCandidates(spM, bottomDoublet, topDoublets,
0445 tripletTopCandidates);
0446 }
0447 }
0448
0449 void createTripletTopCandidates(
0450 const SpacePointContainer2& spacePoints, const ConstSpacePointProxy2& spM,
0451 const DoubletsForMiddleSp::Proxy& bottomDoublet,
0452 DoubletsForMiddleSp::Subset2& topDoublets,
0453 TripletTopCandidates& tripletTopCandidates) const override {
0454 if constexpr (useStripInfo) {
0455 createStripTripletTopCandidates(spacePoints, spM, bottomDoublet,
0456 topDoublets, tripletTopCandidates);
0457 } else {
0458 createPixelTripletTopCandidates(spM, bottomDoublet, topDoublets,
0459 tripletTopCandidates);
0460 }
0461 }
0462
0463 private:
0464 DerivedConfig m_cfg;
0465 };
0466
0467 }
0468
0469 TripletSeedFinder::DerivedConfig::DerivedConfig(const Config& config,
0470 float bFieldInZ_)
0471 : Config(config), bFieldInZ(bFieldInZ_) {
0472 using namespace Acts::UnitLiterals;
0473
0474
0475 {
0476 const double xOverX0 = radLengthPerSeed;
0477 const double q2OverBeta2 = 1;
0478
0479 const double t = std::sqrt(xOverX0 * q2OverBeta2);
0480
0481
0482 highland =
0483 static_cast<float>(13.6_MeV * t * (1.0 + 0.038 * 2 * std::log(t)));
0484 }
0485
0486 const float maxScatteringAngle = highland / minPt;
0487 const float maxScatteringAngle2 = maxScatteringAngle * maxScatteringAngle;
0488
0489
0490 pTPerHelixRadius = bFieldInZ;
0491 minHelixDiameter2 = square(minPt * 2 / pTPerHelixRadius) * helixCutTolerance;
0492 const float pT2perRadius = square(highland / pTPerHelixRadius);
0493 sigmapT2perRadius = pT2perRadius * square(2 * sigmaScattering);
0494 multipleScattering2 = maxScatteringAngle2 * square(sigmaScattering);
0495 }
0496
0497 std::unique_ptr<TripletSeedFinder> TripletSeedFinder::create(
0498 const DerivedConfig& config) {
0499 using BooleanOptions =
0500 boost::mp11::mp_list<std::bool_constant<false>, std::bool_constant<true>>;
0501
0502 using UseStripInfoOptions = BooleanOptions;
0503 using SortedByCotThetaOptions = BooleanOptions;
0504
0505 using TripletOptions =
0506 boost::mp11::mp_product<boost::mp11::mp_list, UseStripInfoOptions,
0507 SortedByCotThetaOptions>;
0508
0509 std::unique_ptr<TripletSeedFinder> result;
0510 boost::mp11::mp_for_each<TripletOptions>([&](auto option) {
0511 using OptionType = decltype(option);
0512
0513 using UseStripInfo = boost::mp11::mp_at_c<OptionType, 0>;
0514 using SortedByCotTheta = boost::mp11::mp_at_c<OptionType, 1>;
0515
0516 if (config.useStripInfo != UseStripInfo::value ||
0517 config.sortedByCotTheta != SortedByCotTheta::value) {
0518 return;
0519 }
0520
0521
0522 if (result != nullptr) {
0523 throw std::runtime_error(
0524 "TripletSeedFinder: Multiple implementations found for one "
0525 "configuration");
0526 }
0527
0528
0529 result =
0530 std::make_unique<Impl<UseStripInfo::value, SortedByCotTheta::value>>(
0531 config);
0532 });
0533 if (result == nullptr) {
0534 throw std::runtime_error(
0535 "TripletSeedFinder: No implementation found for the given "
0536 "configuration");
0537 }
0538 return result;
0539 }
0540
0541 }