File indexing completed on 2025-07-13 07:50:39
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "Acts/Seeding2/BroadTripletSeedFinder.hpp"
0010
0011 #include "Acts/EventData/SpacePointContainer2.hpp"
0012 #include "Acts/Seeding2/BroadTripletSeedFilter.hpp"
0013 #include "Acts/Seeding2/DoubletSeedFinder.hpp"
0014 #include "Acts/Utilities/MathHelpers.hpp"
0015
0016 #include <numeric>
0017
0018 #include <Eigen/src/Core/Matrix.h>
0019
0020 using namespace Acts::UnitLiterals;
0021
0022 namespace Acts::Experimental {
0023
0024 namespace {
0025
0026
0027
0028 bool stripCoordinateCheck(float tolerance, const ConstSpacePointProxy2& sp,
0029 const Eigen::Vector3f& spacePointPosition,
0030 Eigen::Vector3f& outputCoordinates) {
0031 const Eigen::Vector3f& topStripVector = sp.topStripVector();
0032 const Eigen::Vector3f& bottomStripVector = sp.bottomStripVector();
0033 const Eigen::Vector3f& stripCenterDistance = sp.stripCenterDistance();
0034
0035
0036 Eigen::Vector3f d1 = topStripVector.cross(spacePointPosition);
0037
0038
0039 float bd1 = bottomStripVector.dot(d1);
0040
0041
0042
0043 float s1 = stripCenterDistance.dot(d1);
0044 if (std::abs(s1) > std::abs(bd1) * tolerance) {
0045 return false;
0046 }
0047
0048
0049 Eigen::Vector3f d0 = bottomStripVector.cross(spacePointPosition);
0050
0051
0052
0053 float s0 = stripCenterDistance.dot(d0);
0054 if (std::abs(s0) > std::abs(bd1) * tolerance) {
0055 return false;
0056 }
0057
0058
0059
0060
0061 const Eigen::Vector3f& topStripCenter = sp.topStripCenter();
0062
0063
0064
0065 s0 = s0 / bd1;
0066 outputCoordinates = topStripCenter + topStripVector * s0;
0067 return true;
0068 }
0069
0070 }
0071
0072 BroadTripletSeedFinder::DerivedTripletCuts::DerivedTripletCuts(
0073 const TripletCuts& cuts, float bFieldInZ_)
0074 : TripletCuts(cuts), bFieldInZ(bFieldInZ_) {
0075
0076 {
0077 const double xOverX0 = radLengthPerSeed;
0078 const double q2OverBeta2 = 1;
0079
0080 const double t = std::sqrt(xOverX0 * q2OverBeta2);
0081
0082
0083 highland =
0084 static_cast<float>(13.6_MeV * t * (1.0 + 0.038 * 2 * std::log(t)));
0085 }
0086
0087 const float maxScatteringAngle = highland / minPt;
0088 const float maxScatteringAngle2 = maxScatteringAngle * maxScatteringAngle;
0089
0090
0091 pTPerHelixRadius = bFieldInZ;
0092 minHelixDiameter2 = square(minPt * 2 / pTPerHelixRadius) * helixCutTolerance;
0093 const float pT2perRadius = square(highland / pTPerHelixRadius);
0094 sigmapT2perRadius = pT2perRadius * square(2 * sigmaScattering);
0095 multipleScattering2 = maxScatteringAngle2 * square(sigmaScattering);
0096 }
0097
0098 BroadTripletSeedFinder::BroadTripletSeedFinder(
0099 std::unique_ptr<const Logger> logger_)
0100 : m_logger(std::move(logger_)) {}
0101
0102 void BroadTripletSeedFinder::createSeedsFromGroup(
0103 const Options& options, State& state, Cache& cache,
0104 const DoubletSeedFinder& bottomFinder, const DoubletSeedFinder& topFinder,
0105 const DerivedTripletCuts& tripletCuts, const BroadTripletSeedFilter& filter,
0106 const SpacePointContainer2& spacePoints,
0107 std::span<const SpacePointIndex2> bottomSps, SpacePointIndex2 middleSp,
0108 std::span<const SpacePointIndex2> topSps,
0109 SeedContainer2& outputSeeds) const {
0110 cache.candidatesCollector.setMaxElements(
0111 filter.config().maxSeedsPerSpMConf,
0112 filter.config().maxQualitySeedsPerSpMConf);
0113
0114 auto spM = spacePoints[middleSp];
0115
0116 DoubletSeedFinder::MiddleSpInfo middleSpInfo =
0117 DoubletSeedFinder::computeMiddleSpInfo(spM);
0118
0119
0120 cache.topDoublets.clear();
0121 topFinder.createDoublets(spacePoints, spM, middleSpInfo, topSps,
0122 cache.topDoublets);
0123
0124
0125 if (cache.topDoublets.empty()) {
0126 ACTS_VERBOSE("No compatible Tops, returning");
0127 return;
0128 }
0129
0130
0131 float rMaxSeedConf = 0;
0132 if (filter.config().seedConfirmation) {
0133
0134 const bool isForwardRegion =
0135 spM.z() > filter.config().centralSeedConfirmationRange.zMaxSeedConf ||
0136 spM.z() < filter.config().centralSeedConfirmationRange.zMinSeedConf;
0137 SeedConfirmationRangeConfig seedConfRange =
0138 isForwardRegion ? filter.config().forwardSeedConfirmationRange
0139 : filter.config().centralSeedConfirmationRange;
0140
0141
0142 std::size_t nTopSeedConf = spM.r() > seedConfRange.rMaxSeedConf
0143 ? seedConfRange.nTopForLargeR
0144 : seedConfRange.nTopForSmallR;
0145
0146 rMaxSeedConf = seedConfRange.rMaxSeedConf;
0147
0148 if (cache.topDoublets.size() < nTopSeedConf) {
0149 ACTS_VERBOSE("Number of top SPs is "
0150 << cache.topDoublets.size()
0151 << " and is smaller than minimum, returning");
0152 return;
0153 }
0154 }
0155
0156
0157 cache.bottomDoublets.clear();
0158 bottomFinder.createDoublets(spacePoints, spM, middleSpInfo, bottomSps,
0159 cache.bottomDoublets);
0160
0161
0162 if (cache.bottomDoublets.empty()) {
0163 ACTS_VERBOSE("No compatible Bottoms, returning");
0164 return;
0165 }
0166
0167 ACTS_VERBOSE("Candidates: " << cache.bottomDoublets.size() << " bottoms and "
0168 << cache.topDoublets.size()
0169 << " tops for middle candidate indexed "
0170 << spM.index());
0171
0172
0173 cache.candidatesCollector.clear();
0174 if (options.useStripMeasurementInfo) {
0175 createStripTriplets(tripletCuts, rMaxSeedConf, filter, state.filter,
0176 cache.filter, spacePoints, spM, cache.bottomDoublets,
0177 cache.topDoublets, cache.tripletTopCandidates,
0178 cache.candidatesCollector);
0179 } else {
0180 createTriplets(cache.tripletCache, tripletCuts, rMaxSeedConf, filter,
0181 state.filter, cache.filter, spacePoints, spM,
0182 cache.bottomDoublets, cache.topDoublets,
0183 cache.tripletTopCandidates, cache.candidatesCollector);
0184 }
0185
0186
0187
0188 const std::size_t numQualitySeeds =
0189 cache.candidatesCollector.nHighQualityCandidates();
0190 cache.candidatesCollector.toSortedCandidates(spacePoints,
0191 cache.sortedCandidates);
0192 filter.filter1SpFixed(state.filter, spacePoints, cache.sortedCandidates,
0193 numQualitySeeds, outputSeeds);
0194 }
0195
0196 void BroadTripletSeedFinder::createSeedsFromSortedGroups(
0197 const Options& options, State& state, Cache& cache,
0198 const DoubletSeedFinder& bottomFinder, const DoubletSeedFinder& topFinder,
0199 const DerivedTripletCuts& tripletCuts, const BroadTripletSeedFilter& filter,
0200 const SpacePointContainer2& spacePoints,
0201 const std::vector<std::span<const SpacePointIndex2>>& bottomSpGroups,
0202 std::span<const SpacePointIndex2> middleSps,
0203 const std::vector<std::span<const SpacePointIndex2>>& topSpGroups,
0204 const std::pair<float, float>& radiusRangeForMiddle,
0205 SeedContainer2& outputSeeds) const {
0206 if (middleSps.empty()) {
0207 return;
0208 }
0209
0210
0211 cache.candidatesCollector.setMaxElements(
0212 filter.config().maxSeedsPerSpMConf,
0213 filter.config().maxQualitySeedsPerSpMConf);
0214
0215 cache.bottomSpOffsets.clear();
0216 cache.topSpOffsets.clear();
0217
0218
0219
0220
0221 auto firstMiddleSp = spacePoints[middleSps.front()];
0222 float firstMiddleSpR = firstMiddleSp.r();
0223
0224 std::ranges::transform(
0225 bottomSpGroups, std::back_inserter(cache.bottomSpOffsets),
0226 [&](const std::span<const SpacePointIndex2>& bottomSps) {
0227 auto low = std::ranges::lower_bound(
0228 bottomSps, firstMiddleSpR - bottomFinder.config().deltaRMax, {},
0229 [&](const SpacePointIndex2& spIndex) {
0230 auto sp = spacePoints[spIndex];
0231 return sp.r();
0232 });
0233 return low - bottomSps.begin();
0234 });
0235 std::ranges::transform(topSpGroups, std::back_inserter(cache.topSpOffsets),
0236 [&](const std::span<const SpacePointIndex2>& topSps) {
0237 auto low = std::ranges::lower_bound(
0238 topSps,
0239 firstMiddleSpR + topFinder.config().deltaRMin,
0240 {}, [&](const SpacePointIndex2& spIndex) {
0241 auto sp = spacePoints[spIndex];
0242 return sp.r();
0243 });
0244 return low - topSps.begin();
0245 });
0246
0247 for (SpacePointIndex2 middleSp : middleSps) {
0248 auto spM = spacePoints[middleSp];
0249 const float rM = spM.r();
0250
0251
0252 if (rM < radiusRangeForMiddle.first) {
0253 continue;
0254 }
0255 if (rM > radiusRangeForMiddle.second) {
0256
0257 break;
0258 }
0259
0260 DoubletSeedFinder::MiddleSpInfo middleSpInfo =
0261 DoubletSeedFinder::computeMiddleSpInfo(spM);
0262
0263
0264 cache.topDoublets.clear();
0265 for (std::size_t i = 0; i < topSpGroups.size(); ++i) {
0266 topFinder.createSortedDoublets(spacePoints, spM, middleSpInfo,
0267 topSpGroups[i], cache.topSpOffsets[i],
0268 cache.topDoublets);
0269 }
0270
0271
0272 if (cache.topDoublets.empty()) {
0273 ACTS_VERBOSE("No compatible Tops, moving to next middle candidate");
0274 continue;
0275 }
0276
0277
0278 float rMaxSeedConf = 0;
0279 if (filter.config().seedConfirmation) {
0280
0281 const bool isForwardRegion =
0282 spM.z() > filter.config().centralSeedConfirmationRange.zMaxSeedConf ||
0283 spM.z() < filter.config().centralSeedConfirmationRange.zMinSeedConf;
0284 SeedConfirmationRangeConfig seedConfRange =
0285 isForwardRegion ? filter.config().forwardSeedConfirmationRange
0286 : filter.config().centralSeedConfirmationRange;
0287
0288
0289 std::size_t nTopSeedConf = spM.r() > seedConfRange.rMaxSeedConf
0290 ? seedConfRange.nTopForLargeR
0291 : seedConfRange.nTopForSmallR;
0292
0293 rMaxSeedConf = seedConfRange.rMaxSeedConf;
0294
0295 if (cache.topDoublets.size() < nTopSeedConf) {
0296 ACTS_VERBOSE(
0297 "Number of top SPs is "
0298 << cache.topDoublets.size()
0299 << " and is smaller than minimum, moving to next middle candidate");
0300 continue;
0301 }
0302 }
0303
0304
0305 cache.bottomDoublets.clear();
0306 for (std::size_t i = 0; i < bottomSpGroups.size(); ++i) {
0307 bottomFinder.createSortedDoublets(
0308 spacePoints, spM, middleSpInfo, bottomSpGroups[i],
0309 cache.bottomSpOffsets[i], cache.bottomDoublets);
0310 }
0311
0312
0313 if (cache.bottomDoublets.empty()) {
0314 ACTS_VERBOSE("No compatible Bottoms, moving to next middle candidate");
0315 continue;
0316 }
0317
0318 ACTS_VERBOSE("Candidates: " << cache.bottomDoublets.size()
0319 << " bottoms and " << cache.topDoublets.size()
0320 << " tops for middle candidate indexed "
0321 << spM.index());
0322
0323
0324 cache.candidatesCollector.clear();
0325 if (options.useStripMeasurementInfo) {
0326 createStripTriplets(tripletCuts, rMaxSeedConf, filter, state.filter,
0327 cache.filter, spacePoints, spM, cache.bottomDoublets,
0328 cache.topDoublets, cache.tripletTopCandidates,
0329 cache.candidatesCollector);
0330 } else {
0331 createTriplets(cache.tripletCache, tripletCuts, rMaxSeedConf, filter,
0332 state.filter, cache.filter, spacePoints, spM,
0333 cache.bottomDoublets, cache.topDoublets,
0334 cache.tripletTopCandidates, cache.candidatesCollector);
0335 }
0336
0337
0338
0339 const std::size_t numQualitySeeds =
0340 cache.candidatesCollector.nHighQualityCandidates();
0341 cache.candidatesCollector.toSortedCandidates(spacePoints,
0342 cache.sortedCandidates);
0343 filter.filter1SpFixed(state.filter, spacePoints, cache.sortedCandidates,
0344 numQualitySeeds, outputSeeds);
0345 }
0346 }
0347
0348 void BroadTripletSeedFinder::createTriplets(
0349 TripletCache& cache, const DerivedTripletCuts& cuts, float rMaxSeedConf,
0350 const BroadTripletSeedFilter& filter,
0351 BroadTripletSeedFilter::State& filterState,
0352 BroadTripletSeedFilter::Cache& filterCache,
0353 const SpacePointContainer2& spacePoints, const ConstSpacePointProxy2& spM,
0354 const DoubletSeedFinder::DoubletsForMiddleSp& bottomDoublets,
0355 const DoubletSeedFinder::DoubletsForMiddleSp& topDoublets,
0356 TripletTopCandidates& tripletTopCandidates,
0357 CandidatesForMiddleSp2& candidatesCollector) {
0358 const float rM = spM.r();
0359 const float varianceRM = spM.varianceR();
0360 const float varianceZM = spM.varianceZ();
0361
0362
0363 cache.sortedBottoms.resize(bottomDoublets.size());
0364 std::iota(cache.sortedBottoms.begin(), cache.sortedBottoms.end(), 0);
0365 std::ranges::sort(cache.sortedBottoms, {},
0366 [&bottomDoublets](const std::size_t s) {
0367 return bottomDoublets.cotTheta[s];
0368 });
0369
0370 cache.sortedTops.resize(topDoublets.size());
0371 std::iota(cache.sortedTops.begin(), cache.sortedTops.end(), 0);
0372 std::ranges::sort(cache.sortedTops, {}, [&topDoublets](const std::size_t s) {
0373 return topDoublets.cotTheta[s];
0374 });
0375
0376
0377 tripletTopCandidates.resize(topDoublets.size());
0378
0379 std::size_t t0 = 0;
0380
0381 for (const std::size_t b : cache.sortedBottoms) {
0382
0383 if (t0 >= topDoublets.size()) {
0384 break;
0385 }
0386
0387 auto spB = spacePoints[bottomDoublets.spacePoints[b]];
0388 const auto& lb = bottomDoublets.linCircles[b];
0389
0390 float cotThetaB = lb.cotTheta;
0391 float Vb = lb.V;
0392 float Ub = lb.U;
0393 float ErB = lb.Er;
0394 float iDeltaRB = lb.iDeltaR;
0395
0396
0397 float iSinTheta2 = 1 + cotThetaB * cotThetaB;
0398
0399
0400
0401
0402
0403
0404
0405
0406
0407 float scatteringInRegion2 = cuts.multipleScattering2 * iSinTheta2;
0408
0409
0410 tripletTopCandidates.clear();
0411
0412
0413
0414
0415 std::size_t minCompatibleTopSPs = 2;
0416 if (!filter.config().seedConfirmation || spB.r() > rMaxSeedConf) {
0417 minCompatibleTopSPs = 1;
0418 }
0419 if (filter.config().seedConfirmation &&
0420 candidatesCollector.nHighQualityCandidates() > 0) {
0421 minCompatibleTopSPs++;
0422 }
0423
0424 for (std::size_t indexSortedTop = t0; indexSortedTop < topDoublets.size();
0425 ++indexSortedTop) {
0426 const std::size_t t = cache.sortedTops[indexSortedTop];
0427 auto spT = spacePoints[topDoublets.spacePoints[t]];
0428 const auto& lt = topDoublets.linCircles[t];
0429 float cotThetaT = lt.cotTheta;
0430
0431
0432 float cotThetaAvg2 = cotThetaB * cotThetaT;
0433 if (cotThetaAvg2 <= 0) {
0434 continue;
0435 }
0436
0437
0438
0439 float error2 =
0440 lt.Er + ErB +
0441 2 * (cotThetaAvg2 * varianceRM + varianceZM) * iDeltaRB * lt.iDeltaR;
0442
0443 float deltaCotTheta = cotThetaB - cotThetaT;
0444 float deltaCotTheta2 = deltaCotTheta * deltaCotTheta;
0445
0446
0447
0448
0449
0450
0451
0452
0453
0454
0455
0456 if (deltaCotTheta2 > error2 + scatteringInRegion2) {
0457
0458
0459
0460 if (cotThetaB < cotThetaT) {
0461 break;
0462 }
0463 t0 = indexSortedTop + 1;
0464 continue;
0465 }
0466
0467 float dU = lt.U - Ub;
0468
0469 if (dU == 0.) {
0470 continue;
0471 }
0472
0473
0474 float A = (lt.V - Vb) / dU;
0475 float S2 = 1 + A * A;
0476 float B = Vb - A * Ub;
0477 float B2 = B * B;
0478
0479
0480
0481 if (S2 < B2 * cuts.minHelixDiameter2) {
0482 continue;
0483 }
0484
0485
0486
0487
0488 float iHelixDiameter2 = B2 / S2;
0489 float sigmaSquaredPtDependent = iSinTheta2 * cuts.sigmapT2perRadius;
0490
0491
0492 float p2scatterSigma = iHelixDiameter2 * sigmaSquaredPtDependent;
0493 if (!std::isinf(cuts.maxPtScattering)) {
0494
0495
0496
0497
0498 if (B2 == 0 || cuts.pTPerHelixRadius * std::sqrt(S2 / B2) >
0499 2. * cuts.maxPtScattering) {
0500 float pTscatterSigma =
0501 (cuts.highland / cuts.maxPtScattering) * cuts.sigmaScattering;
0502 p2scatterSigma = pTscatterSigma * pTscatterSigma * iSinTheta2;
0503 }
0504 }
0505
0506
0507 if (deltaCotTheta2 > error2 + p2scatterSigma) {
0508 if (cotThetaB < cotThetaT) {
0509 break;
0510 }
0511 t0 = indexSortedTop;
0512 continue;
0513 }
0514
0515
0516
0517
0518 float Im = std::abs((A - B * rM) * rM);
0519 if (Im > cuts.impactMax) {
0520 continue;
0521 }
0522
0523
0524
0525 tripletTopCandidates.emplace_back(spT.index(), B / std::sqrt(S2), Im);
0526 }
0527
0528
0529 if (tripletTopCandidates.size() < minCompatibleTopSPs) {
0530 continue;
0531 }
0532
0533 float zOrigin = spM.z() - rM * lb.cotTheta;
0534 filter.filter2SpFixed(
0535 filterState, filterCache, spacePoints, spB.index(), spM.index(),
0536 tripletTopCandidates.topSpacePoints, tripletTopCandidates.curvatures,
0537 tripletTopCandidates.impactParameters, zOrigin, candidatesCollector);
0538 }
0539 }
0540
0541 void BroadTripletSeedFinder::createStripTriplets(
0542 const DerivedTripletCuts& cuts, float rMaxSeedConf,
0543 const BroadTripletSeedFilter& filter,
0544 BroadTripletSeedFilter::State& filterState,
0545 BroadTripletSeedFilter::Cache& filterCache,
0546 const SpacePointContainer2& spacePoints, const ConstSpacePointProxy2& spM,
0547 const DoubletSeedFinder::DoubletsForMiddleSp& bottomDoublets,
0548 const DoubletSeedFinder::DoubletsForMiddleSp& topDoublets,
0549 TripletTopCandidates& tripletTopCandidates,
0550 CandidatesForMiddleSp2& candidatesCollector) {
0551 const float rM = spM.r();
0552 const float cosPhiM = spM.x() / rM;
0553 const float sinPhiM = spM.y() / rM;
0554 const float varianceRM = spM.varianceR();
0555 const float varianceZM = spM.varianceZ();
0556
0557
0558 tripletTopCandidates.resize(topDoublets.size());
0559
0560 for (std::size_t b = 0; b < bottomDoublets.size(); ++b) {
0561 auto spB = spacePoints[bottomDoublets.spacePoints[b]];
0562 const auto& lb = bottomDoublets.linCircles[b];
0563
0564 float cotThetaB = lb.cotTheta;
0565 float Vb = lb.V;
0566 float Ub = lb.U;
0567 float ErB = lb.Er;
0568 float iDeltaRB = lb.iDeltaR;
0569
0570
0571 float iSinTheta2 = 1 + cotThetaB * cotThetaB;
0572
0573
0574
0575
0576
0577
0578
0579
0580
0581 float scatteringInRegion2 = cuts.multipleScattering2 * iSinTheta2;
0582
0583 float sinTheta = 1 / std::sqrt(iSinTheta2);
0584 float cosTheta = cotThetaB * sinTheta;
0585
0586
0587 tripletTopCandidates.clear();
0588
0589
0590
0591 Eigen::Vector2f rotationTermsUVtoXY = {cosPhiM * sinTheta,
0592 sinPhiM * sinTheta};
0593
0594
0595
0596
0597 std::size_t minCompatibleTopSPs = 2;
0598 if (!filter.config().seedConfirmation || spB.r() > rMaxSeedConf) {
0599 minCompatibleTopSPs = 1;
0600 }
0601 if (filter.config().seedConfirmation &&
0602 candidatesCollector.nHighQualityCandidates() > 0) {
0603 minCompatibleTopSPs++;
0604 }
0605
0606 for (std::size_t t = 0; t < topDoublets.size(); ++t) {
0607 auto spT = spacePoints[topDoublets.spacePoints[t]];
0608 const auto& lt = topDoublets.linCircles[t];
0609
0610
0611 float dU = lt.U - Ub;
0612 if (dU == 0.) {
0613 continue;
0614 }
0615
0616
0617 float A0 = (lt.V - Vb) / dU;
0618
0619 float zPositionMiddle = cosTheta * std::sqrt(1 + A0 * A0);
0620
0621
0622
0623 Eigen::Vector3f positionMiddle = {
0624 rotationTermsUVtoXY[0] - rotationTermsUVtoXY[1] * A0,
0625 rotationTermsUVtoXY[0] * A0 + rotationTermsUVtoXY[1],
0626 zPositionMiddle};
0627
0628 Eigen::Vector3f rMTransf;
0629 if (!stripCoordinateCheck(cuts.toleranceParam, spM, positionMiddle,
0630 rMTransf)) {
0631 continue;
0632 }
0633
0634
0635 float B0 = 2 * (Vb - A0 * Ub);
0636 float Cb = 1 - B0 * lb.y;
0637 float Sb = A0 + B0 * lb.x;
0638 Eigen::Vector3f positionBottom = {
0639 rotationTermsUVtoXY[0] * Cb - rotationTermsUVtoXY[1] * Sb,
0640 rotationTermsUVtoXY[0] * Sb + rotationTermsUVtoXY[1] * Cb,
0641 zPositionMiddle};
0642
0643 Eigen::Vector3f rBTransf;
0644 if (!stripCoordinateCheck(cuts.toleranceParam, spB, positionBottom,
0645 rBTransf)) {
0646 continue;
0647 }
0648
0649
0650 float Ct = 1 - B0 * lt.y;
0651 float St = A0 + B0 * lt.x;
0652 Eigen::Vector3f positionTop = {
0653 rotationTermsUVtoXY[0] * Ct - rotationTermsUVtoXY[1] * St,
0654 rotationTermsUVtoXY[0] * St + rotationTermsUVtoXY[1] * Ct,
0655 zPositionMiddle};
0656
0657 Eigen::Vector3f rTTransf;
0658 if (!stripCoordinateCheck(cuts.toleranceParam, spT, positionTop,
0659 rTTransf)) {
0660 continue;
0661 }
0662
0663
0664 float xB = rBTransf[0] - rMTransf[0];
0665 float yB = rBTransf[1] - rMTransf[1];
0666 float zB = rBTransf[2] - rMTransf[2];
0667 float xT = rTTransf[0] - rMTransf[0];
0668 float yT = rTTransf[1] - rMTransf[1];
0669 float zT = rTTransf[2] - rMTransf[2];
0670
0671 float iDeltaRB2 = 1 / (xB * xB + yB * yB);
0672 float iDeltaRT2 = 1 / (xT * xT + yT * yT);
0673
0674 cotThetaB = -zB * std::sqrt(iDeltaRB2);
0675 float cotThetaT = zT * std::sqrt(iDeltaRT2);
0676
0677
0678 float averageCotTheta = 0.5f * (cotThetaB + cotThetaT);
0679 float cotThetaAvg2 = averageCotTheta * averageCotTheta;
0680
0681
0682
0683 float error2 =
0684 lt.Er + ErB +
0685 2 * (cotThetaAvg2 * varianceRM + varianceZM) * iDeltaRB * lt.iDeltaR;
0686
0687 float deltaCotTheta = cotThetaB - cotThetaT;
0688 float deltaCotTheta2 = deltaCotTheta * deltaCotTheta;
0689
0690
0691
0692
0693
0694
0695
0696
0697
0698
0699
0700 if (deltaCotTheta2 > error2 + scatteringInRegion2) {
0701
0702 continue;
0703 }
0704
0705 float rMxy =
0706 std::sqrt(rMTransf[0] * rMTransf[0] + rMTransf[1] * rMTransf[1]);
0707 float irMxy = 1 / rMxy;
0708 float Ax = rMTransf[0] * irMxy;
0709 float Ay = rMTransf[1] * irMxy;
0710
0711 float ub = (xB * Ax + yB * Ay) * iDeltaRB2;
0712 float vb = (yB * Ax - xB * Ay) * iDeltaRB2;
0713 float ut = (xT * Ax + yT * Ay) * iDeltaRT2;
0714 float vt = (yT * Ax - xT * Ay) * iDeltaRT2;
0715
0716 dU = ut - ub;
0717
0718 if (dU == 0.) {
0719 continue;
0720 }
0721 float A = (vt - vb) / dU;
0722 float S2 = 1 + A * A;
0723 float B = vb - A * ub;
0724 float B2 = B * B;
0725
0726
0727
0728 if (S2 < B2 * cuts.minHelixDiameter2) {
0729 continue;
0730 }
0731
0732
0733
0734
0735 float iHelixDiameter2 = B2 / S2;
0736 float sigmaSquaredPtDependent = iSinTheta2 * cuts.sigmapT2perRadius;
0737
0738
0739 float p2scatterSigma = iHelixDiameter2 * sigmaSquaredPtDependent;
0740 if (!std::isinf(cuts.maxPtScattering)) {
0741
0742
0743
0744
0745 if (B2 == 0 || cuts.pTPerHelixRadius * std::sqrt(S2 / B2) >
0746 2. * cuts.maxPtScattering) {
0747 float pTscatterSigma =
0748 (cuts.highland / cuts.maxPtScattering) * cuts.sigmaScattering;
0749 p2scatterSigma = pTscatterSigma * pTscatterSigma * iSinTheta2;
0750 }
0751 }
0752
0753
0754 if (deltaCotTheta2 > error2 + p2scatterSigma) {
0755 continue;
0756 }
0757
0758
0759
0760
0761 float Im = std::abs((A - B * rMxy) * rMxy);
0762 if (Im > cuts.impactMax) {
0763 continue;
0764 }
0765
0766
0767
0768 tripletTopCandidates.emplace_back(spT.index(), B / std::sqrt(S2), Im);
0769 }
0770
0771
0772 if (tripletTopCandidates.size() < minCompatibleTopSPs) {
0773 continue;
0774 }
0775
0776 float zOrigin = spM.z() - rM * lb.cotTheta;
0777 filter.filter2SpFixed(
0778 filterState, filterCache, spacePoints, spB.index(), spM.index(),
0779 tripletTopCandidates.topSpacePoints, tripletTopCandidates.curvatures,
0780 tripletTopCandidates.impactParameters, zOrigin, candidatesCollector);
0781 }
0782 }
0783
0784 }