File indexing completed on 2026-03-28 07:45:42
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "Acts/Seeding2/GraphBasedTrackSeeder.hpp"
0010
0011 #include "Acts/Seeding2/GbtsTrackingFilter.hpp"
0012 #include "Acts/Utilities/MathHelpers.hpp"
0013
0014 #include <algorithm>
0015 #include <cmath>
0016 #include <cstdint>
0017 #include <fstream>
0018 #include <memory>
0019 #include <numbers>
0020 #include <utility>
0021 #include <vector>
0022
0023 namespace Acts::Experimental {
0024
0025 GraphBasedTrackSeeder::DerivedConfig::DerivedConfig(const Config& config)
0026 : Config(config) {
0027 phiSliceWidth = 2 * std::numbers::pi_v<float> / config.nMaxPhiSlice;
0028 }
0029
0030 GraphBasedTrackSeeder::GraphBasedTrackSeeder(
0031 const DerivedConfig& config, std::shared_ptr<GbtsGeometry> geometry,
0032 std::unique_ptr<const Acts::Logger> logger)
0033 : m_cfg(config),
0034 m_geometry(std::move(geometry)),
0035 m_logger(std::move(logger)) {
0036 m_mlLut = parseGbtsMlLookupTable(m_cfg.lutInputFile);
0037 }
0038
0039 SeedContainer2 GraphBasedTrackSeeder::createSeeds(
0040 const SpacePointContainer2& spacePoints, const GbtsRoiDescriptor& roi,
0041 const std::uint32_t maxLayers, const GbtsTrackingFilter& filter) const {
0042 GbtsNodeStorage nodeStorage(m_geometry, m_mlLut);
0043
0044 SeedContainer2 SeedContainer;
0045 std::vector<std::vector<GbtsNode>> nodesPerLayer =
0046 createNodes(spacePoints, maxLayers);
0047 std::uint32_t nPixelLoaded = 0;
0048 std::uint32_t nStripLoaded = 0;
0049
0050 for (std::uint16_t l = 0; l < nodesPerLayer.size(); l++) {
0051 const std::vector<GbtsNode>& nodes = nodesPerLayer[l];
0052
0053 if (nodes.empty()) {
0054 continue;
0055 }
0056
0057 const bool isPixel = true;
0058
0059 if (isPixel) {
0060 nPixelLoaded += nodeStorage.loadPixelGraphNodes(
0061 l, nodes, m_cfg.useMl, m_cfg.maxEndcapClusterWidth);
0062 } else {
0063 nStripLoaded += nodeStorage.loadStripGraphNodes(l, nodes);
0064 }
0065 }
0066 ACTS_DEBUG("Loaded " << nPixelLoaded << " pixel space points and "
0067 << nStripLoaded << " strip space points");
0068
0069 nodeStorage.sortByPhi();
0070
0071 nodeStorage.initializeNodes(m_cfg.useMl);
0072
0073 nodeStorage.generatePhiIndexing(1.5f * m_cfg.phiSliceWidth);
0074
0075 std::vector<GbtsEdge> edgeStorage;
0076
0077 std::pair<std::int32_t, std::int32_t> graphStats =
0078 buildTheGraph(roi, nodeStorage, edgeStorage);
0079
0080 ACTS_DEBUG("Created graph with " << graphStats.first << " edges and "
0081 << graphStats.second << " edge links");
0082
0083 if (graphStats.first == 0 || graphStats.second == 0) {
0084 ACTS_WARNING("Missing edges or edge connections");
0085 }
0086
0087 std::uint32_t maxLevel = runCCA(graphStats.first, edgeStorage);
0088
0089 ACTS_DEBUG("Reached Level " << maxLevel << " after GNN iterations");
0090
0091 std::vector<SeedProperties> vSeedCandidates;
0092 extractSeedsFromTheGraph(maxLevel, graphStats.first, spacePoints.size(),
0093 edgeStorage, vSeedCandidates, filter);
0094
0095 if (vSeedCandidates.empty()) {
0096 ACTS_WARNING("No Seed Candidates");
0097 }
0098
0099 for (const auto& seed : vSeedCandidates) {
0100 if (seed.isClone != 0) {
0101 continue;
0102 }
0103
0104
0105 std::vector<SpacePointIndex2> Sp_Indexes{};
0106 Sp_Indexes.reserve(seed.spacePoints.size());
0107
0108 for (const auto& sp_idx : seed.spacePoints) {
0109 Sp_Indexes.emplace_back(sp_idx);
0110 }
0111
0112 auto newSeed = SeedContainer.createSeed();
0113 newSeed.assignSpacePointIndices(Sp_Indexes);
0114 newSeed.quality() = seed.seedQuality;
0115 }
0116
0117 ACTS_DEBUG("GBTS created " << SeedContainer.size() << " seeds");
0118
0119 return SeedContainer;
0120 }
0121
0122 GbtsMlLookupTable GraphBasedTrackSeeder::parseGbtsMlLookupTable(
0123 const std::string& lutInputFile) {
0124 if (!m_cfg.useMl) {
0125 return {};
0126 }
0127 if (lutInputFile.empty()) {
0128 throw std::runtime_error("Cannot find ML predictor LUT file");
0129 }
0130
0131 std::ifstream ifs(std::string(lutInputFile).c_str());
0132 if (!ifs.is_open()) {
0133 throw std::runtime_error("Failed to open LUT file");
0134 }
0135
0136 GbtsMlLookupTable mlLut;
0137 mlLut.reserve(100);
0138
0139 float clWidth{};
0140 float min1{};
0141 float max1{};
0142 float min2{};
0143 float max2{};
0144 while (ifs >> clWidth >> min1 >> max1 >> min2 >> max2) {
0145 mlLut.emplace_back(std::array<float, 5>{clWidth, min1, max1, min2, max2});
0146 }
0147
0148 if (!ifs.eof()) {
0149
0150 throw std::runtime_error("Stopped reading LUT file due to parse error");
0151 }
0152
0153 return mlLut;
0154 }
0155
0156 std::vector<std::vector<GbtsNode>> GraphBasedTrackSeeder::createNodes(
0157 const SpacePointContainer2& spacePoints,
0158 const std::uint32_t maxLayers) const {
0159 auto layerColumn = spacePoints.column<std::uint32_t>("layerId");
0160 auto clusterWidthColumn = spacePoints.column<float>("clusterWidth");
0161 auto localPositionColumn = spacePoints.column<float>("localPositionY");
0162
0163 std::vector<std::vector<GbtsNode>> nodesPerLayer(maxLayers);
0164
0165 for (auto& v : nodesPerLayer) {
0166 v.reserve(10000);
0167 }
0168
0169 for (const auto& sp : spacePoints) {
0170
0171
0172 const std::uint16_t layer = sp.extra(layerColumn);
0173
0174
0175 GbtsNode& node = nodesPerLayer[layer].emplace_back(layer);
0176
0177
0178
0179 node.x = sp.x();
0180 node.y = sp.y();
0181 node.z = sp.z();
0182 node.r = sp.r();
0183 node.phi = sp.phi();
0184 node.idx = sp.index();
0185 node.pcw = sp.extra(clusterWidthColumn);
0186 node.locPosY = sp.extra(localPositionColumn);
0187 }
0188
0189 return nodesPerLayer;
0190 }
0191
0192 std::pair<std::int32_t, std::int32_t> GraphBasedTrackSeeder::buildTheGraph(
0193 const GbtsRoiDescriptor& roi, GbtsNodeStorage& nodeStorage,
0194 std::vector<GbtsEdge>& edgeStorage) const {
0195
0196 const float cutDPhiMax = m_cfg.lrtMode ? 0.07f : 0.012f;
0197
0198 const float cutDCurvMax = m_cfg.lrtMode ? 0.015f : 0.001f;
0199
0200 const float cutTauRatioMax = m_cfg.lrtMode ? 0.015f : m_cfg.tauRatioCut;
0201 const float minZ0 = m_cfg.lrtMode ? -600.0f : static_cast<float>(roi.zMin());
0202 const float maxZ0 = m_cfg.lrtMode ? 600.0f : static_cast<float>(roi.zMax());
0203 const float minDeltaPhi = m_cfg.lrtMode ? 0.01f : 0.001f;
0204
0205
0206 const float maxOuterRadius = m_cfg.lrtMode ? 1050.0f : 550.0f;
0207
0208 const float cutZMinU =
0209 minZ0 + maxOuterRadius * static_cast<float>(roi.dzdrMin());
0210 const float cutZMaxU =
0211 maxZ0 + maxOuterRadius * static_cast<float>(roi.dzdrMax());
0212
0213
0214 const float tripletPtMin = 0.8f * m_cfg.minPt;
0215
0216
0217 const float ptScale = (0.9f * UnitConstants::GeV) / m_cfg.minPt;
0218
0219 const float maxCurv = m_cfg.ptCoeff / tripletPtMin;
0220
0221 float maxKappaHighEta =
0222 m_cfg.lrtMode ? 1.0f * maxCurv : std::sqrt(0.8f) * maxCurv;
0223 float maxKappaLowEta =
0224 m_cfg.lrtMode ? 1.0f * maxCurv : std::sqrt(0.6f) * maxCurv;
0225
0226
0227 if (!m_cfg.useOldTunings && !m_cfg.lrtMode) {
0228 maxKappaHighEta = 4.75e-4f * ptScale;
0229 maxKappaLowEta = 3.75e-4f * ptScale;
0230 }
0231
0232 const float dPhiCoeff = m_cfg.lrtMode ? 1.0f * maxCurv : 0.68f * maxCurv;
0233
0234
0235 const float deltaPhi0 = 0.5f * m_cfg.phiSliceWidth;
0236
0237 std::uint32_t nConnections = 0;
0238
0239 edgeStorage.reserve(m_cfg.nMaxEdges);
0240
0241 std::uint32_t nEdges = 0;
0242
0243
0244
0245
0246 const std::uint32_t zBins = 16;
0247 const float z0HistoCoeff = zBins / (maxZ0 - minZ0 + 1e-6);
0248
0249
0250 for (const auto& bg : m_geometry->binGroups()) {
0251 GbtsEtaBin& B1 = nodeStorage.getEtaBin(bg.first);
0252
0253 if (B1.empty()) {
0254 continue;
0255 }
0256
0257 const float rb1 = B1.minRadius;
0258
0259 const std::uint32_t layerId1 = B1.layerId;
0260
0261
0262
0263 std::vector<SlidingWindow> phiSlidingWindow;
0264
0265
0266 phiSlidingWindow.resize(bg.second.size());
0267
0268 std::uint32_t winIdx = 0;
0269
0270
0271 for (const auto& b2Idx : bg.second) {
0272 const GbtsEtaBin& B2 = nodeStorage.getEtaBin(b2Idx);
0273
0274 if (B2.empty()) {
0275 ++winIdx;
0276 continue;
0277 }
0278
0279 const float rb2 = B2.maxRadius;
0280
0281 float deltaPhi = deltaPhi0;
0282
0283
0284 if (m_cfg.useEtaBinning) {
0285 const float absDr = std::fabs(rb2 - rb1);
0286 if (m_cfg.useOldTunings) {
0287 deltaPhi = minDeltaPhi + dPhiCoeff * absDr;
0288 } else {
0289 if (absDr < 60.0) {
0290 deltaPhi = 0.002f + 4.33e-4f * ptScale * absDr;
0291 } else {
0292 deltaPhi = 0.015f + 2.2e-4f * ptScale * absDr;
0293 }
0294 }
0295 }
0296
0297 phiSlidingWindow[winIdx].bin = &B2;
0298 phiSlidingWindow[winIdx].hasNodes = true;
0299 phiSlidingWindow[winIdx].deltaPhi = deltaPhi;
0300 ++winIdx;
0301 }
0302
0303
0304 for (std::uint32_t n1Idx = 0; n1Idx < B1.vn.size(); ++n1Idx) {
0305
0306 B1.vFirstEdge[n1Idx] = nEdges;
0307
0308
0309 std::uint16_t numCreatedEdges = 0;
0310
0311 bool isConnected = false;
0312
0313 std::array<std::uint8_t, 16> z0Histo = {};
0314
0315 const std::array<float, 5>& n1pars = B1.params[n1Idx];
0316
0317 const float phi1 = n1pars[2];
0318 const float r1 = n1pars[3];
0319 const float z1 = n1pars[4];
0320
0321
0322 for (auto& slw : phiSlidingWindow) {
0323 if (!slw.hasNodes) {
0324 continue;
0325 }
0326
0327 const GbtsEtaBin& B2 = *slw.bin;
0328
0329 const float deltaPhi = slw.deltaPhi;
0330
0331
0332
0333 const float minPhi = phi1 - deltaPhi;
0334 const float maxPhi = phi1 + deltaPhi;
0335
0336
0337 for (std::uint32_t n2PhiIdx = slw.firstIt;
0338 n2PhiIdx < B2.vPhiNodes.size(); ++n2PhiIdx) {
0339 const float phi2 = B2.vPhiNodes[n2PhiIdx].first;
0340
0341 if (phi2 < minPhi) {
0342
0343 slw.firstIt = n2PhiIdx;
0344 continue;
0345 }
0346 if (phi2 > maxPhi) {
0347
0348 break;
0349 }
0350
0351 const std::uint32_t n2Idx = B2.vPhiNodes[n2PhiIdx].second;
0352
0353 const std::uint16_t nodeInfo = B2.vIsConnected[n2Idx];
0354
0355
0356 if ((layerId1 == 80000) && (nodeInfo == 0)) {
0357 continue;
0358 }
0359
0360 const std::uint32_t n2FirstEdge = B2.vFirstEdge[n2Idx];
0361 const std::uint16_t n2NumEdges = B2.vNumEdges[n2Idx];
0362 const std::uint32_t n2LastEdge = n2FirstEdge + n2NumEdges;
0363
0364 const std::array<float, 5>& n2pars = B2.params[n2Idx];
0365
0366 const float r2 = n2pars[3];
0367
0368 const float dr = r2 - r1;
0369
0370 if (dr < m_cfg.minDeltaRadius) {
0371 continue;
0372 }
0373
0374 const float z2 = n2pars[4];
0375
0376 const float dz = z2 - z1;
0377 const float tau = dz / dr;
0378 const float ftau = std::fabs(tau);
0379 if (ftau > 36.0f) {
0380 continue;
0381 }
0382
0383 if (ftau < n1pars[0]) {
0384 continue;
0385 }
0386 if (ftau > n1pars[1]) {
0387 continue;
0388 }
0389
0390 if (ftau < n2pars[0]) {
0391 continue;
0392 }
0393 if (ftau > n2pars[1]) {
0394 continue;
0395 }
0396
0397 const float z0 = z1 - r1 * tau;
0398
0399 if (layerId1 == 80000) {
0400 if (!checkZ0BitMask(nodeInfo, z0, minZ0, z0HistoCoeff)) {
0401 continue;
0402 }
0403 }
0404
0405 if (m_cfg.doubletFilterRZ) {
0406 if (z0 < minZ0 || z0 > maxZ0) {
0407 continue;
0408 }
0409
0410 const float zOuter = z0 + maxOuterRadius * tau;
0411
0412 if (zOuter < cutZMinU || zOuter > cutZMaxU) {
0413 continue;
0414 }
0415 }
0416
0417 const float curv = (phi2 - phi1) / dr;
0418 const float absCurv = std::abs(curv);
0419
0420 if (ftau < 4.0f) {
0421 if (absCurv > maxKappaLowEta) {
0422 continue;
0423 }
0424 } else {
0425 if (absCurv > maxKappaHighEta) {
0426 continue;
0427 }
0428 }
0429
0430 const float expEta = fastHypot(1, tau) - tau;
0431
0432
0433 if (m_cfg.matchBeforeCreate &&
0434 (layerId1 == 80000 || layerId1 == 81000)) {
0435
0436 bool isGood = n2NumEdges <= 2;
0437
0438 if (!isGood) {
0439 const float uat1 = 1.0f / expEta;
0440
0441 for (std::uint32_t n2InIdx = n2FirstEdge; n2InIdx < n2LastEdge;
0442 ++n2InIdx) {
0443 const float tau2 = edgeStorage.at(n2InIdx).p[0];
0444 const float tauRatio = tau2 * uat1 - 1.0f;
0445
0446 if (std::abs(tauRatio) > m_cfg.tauRatioPrecut) {
0447 continue;
0448 }
0449 isGood = true;
0450 break;
0451 }
0452 }
0453
0454 if (!isGood) {
0455 continue;
0456 }
0457 }
0458
0459 const float dPhi2 = curv * r2;
0460 const float dPhi1 = curv * r1;
0461
0462 if (nEdges < m_cfg.nMaxEdges) {
0463 edgeStorage.emplace_back(B1.vn[n1Idx], B2.vn[n2Idx], expEta, curv,
0464 phi1 + dPhi1);
0465
0466 ++numCreatedEdges;
0467
0468 const std::uint32_t outEdgeIdx = nEdges;
0469
0470 const float uat2 = 1.f / expEta;
0471 const float phi2u = phi2 + dPhi2;
0472 const float curv2 = curv;
0473
0474
0475 for (std::uint32_t inEdgeIdx = n2FirstEdge; inEdgeIdx < n2LastEdge;
0476 ++inEdgeIdx) {
0477 GbtsEdge* pS = &(edgeStorage.at(inEdgeIdx));
0478
0479 if (pS->nNei >= gbtsNumSegConns) {
0480 continue;
0481 }
0482
0483 const float tauRatio = pS->p[0] * uat2 - 1.0f;
0484
0485 if (std::abs(tauRatio) > cutTauRatioMax) {
0486 continue;
0487 }
0488
0489 float dPhi = phi2u - pS->p[2];
0490
0491 if (dPhi < -std::numbers::pi_v<float>) {
0492 dPhi += 2 * std::numbers::pi_v<float>;
0493 } else if (dPhi > std::numbers::pi_v<float>) {
0494 dPhi -= 2 * std::numbers::pi_v<float>;
0495 }
0496
0497 if (std::abs(dPhi) > cutDPhiMax) {
0498 continue;
0499 }
0500
0501 const float dcurv = curv2 - pS->p[1];
0502
0503 if (dcurv < -cutDCurvMax || dcurv > cutDCurvMax) {
0504 continue;
0505 }
0506
0507 pS->vNei[pS->nNei] = outEdgeIdx;
0508 ++pS->nNei;
0509
0510 isConnected = true;
0511
0512
0513
0514 const std::uint32_t z0BinIndex =
0515 static_cast<std::uint32_t>(z0HistoCoeff * (z0 - minZ0));
0516
0517 ++z0Histo[z0BinIndex];
0518
0519 nConnections++;
0520 }
0521 nEdges++;
0522 }
0523 }
0524 }
0525
0526
0527
0528 B1.vNumEdges[n1Idx] = numCreatedEdges;
0529 if (isConnected) {
0530 std::uint16_t z0BitMask = 0x0;
0531
0532 for (std::uint32_t bIdx = 0; bIdx < 16; ++bIdx) {
0533 if (z0Histo[bIdx] == 0) {
0534 continue;
0535 }
0536
0537 z0BitMask |= (1 << bIdx);
0538 }
0539
0540
0541 B1.vIsConnected[n1Idx] = z0BitMask;
0542 }
0543
0544 }
0545 }
0546
0547 if (nEdges >= m_cfg.nMaxEdges) {
0548 ACTS_WARNING(
0549 "Maximum number of graph edges exceeded - possible efficiency loss "
0550 << nEdges);
0551 }
0552 return std::make_pair(nEdges, nConnections);
0553 }
0554
0555 std::int32_t GraphBasedTrackSeeder::runCCA(
0556 const std::uint32_t nEdges, std::vector<GbtsEdge>& edgeStorage) const {
0557 constexpr std::uint32_t maxIter = 15;
0558
0559 std::int32_t maxLevel = 0;
0560
0561 std::uint32_t iter = 0;
0562
0563 std::vector<GbtsEdge*> v_old;
0564
0565 for (std::uint32_t edgeIndex = 0; edgeIndex < nEdges; ++edgeIndex) {
0566 GbtsEdge* pS = &(edgeStorage[edgeIndex]);
0567 if (pS->nNei == 0) {
0568 continue;
0569 }
0570
0571
0572
0573 v_old.push_back(pS);
0574 }
0575
0576 std::vector<GbtsEdge*> v_new;
0577 v_new.reserve(v_old.size());
0578
0579
0580 for (; iter < maxIter; iter++) {
0581 v_new.clear();
0582
0583 for (GbtsEdge* pS : v_old) {
0584 std::int32_t nextLevel = pS->level;
0585
0586 for (std::uint32_t nIdx = 0; nIdx < pS->nNei; ++nIdx) {
0587 const std::uint32_t nextEdgeIdx = pS->vNei[nIdx];
0588
0589 GbtsEdge* pN = &(edgeStorage[nextEdgeIdx]);
0590
0591 if (pS->level == pN->level) {
0592 nextLevel = pS->level + 1;
0593 v_new.push_back(pS);
0594 break;
0595 }
0596 }
0597
0598
0599 pS->next = static_cast<std::int8_t>(nextLevel);
0600 }
0601
0602
0603
0604 std::uint32_t nChanges = 0;
0605
0606 for (auto pS : v_new) {
0607 if (pS->next != pS->level) {
0608 nChanges++;
0609 pS->level = pS->next;
0610 if (maxLevel < pS->level) {
0611 maxLevel = pS->level;
0612 }
0613 }
0614 }
0615
0616 if (nChanges == 0) {
0617 break;
0618 }
0619
0620 v_old.swap(v_new);
0621 v_new.clear();
0622 }
0623
0624 return maxLevel;
0625 }
0626
0627 void GraphBasedTrackSeeder::extractSeedsFromTheGraph(
0628 std::uint32_t maxLevel, std::uint32_t nEdges, std::int32_t nHits,
0629 std::vector<GbtsEdge>& edgeStorage,
0630 std::vector<SeedProperties>& vSeedCandidates,
0631 const GbtsTrackingFilter& filter) const {
0632 vSeedCandidates.clear();
0633
0634
0635 std::uint32_t minLevel = 3;
0636
0637 if (m_cfg.lrtMode) {
0638
0639 minLevel = 2;
0640 }
0641
0642 if (maxLevel < minLevel) {
0643 return;
0644 }
0645
0646 std::vector<GbtsEdge*> vSeeds;
0647
0648 vSeeds.reserve(nEdges / 2);
0649
0650 for (std::uint32_t edgeIndex = 0; edgeIndex < nEdges; ++edgeIndex) {
0651 GbtsEdge* pS = &(edgeStorage.at(edgeIndex));
0652
0653 if (pS->level < static_cast<std::int32_t>(minLevel)) {
0654 continue;
0655 }
0656
0657 vSeeds.push_back(pS);
0658 }
0659
0660 if (vSeeds.empty()) {
0661 return;
0662 }
0663
0664 std::ranges::sort(vSeeds, std::ranges::greater{},
0665 [](const GbtsEdge* e) { return e->level; });
0666
0667
0668
0669 vSeedCandidates.reserve(vSeeds.size());
0670
0671 GbtsTrackingFilter::State filterState{};
0672
0673 for (GbtsEdge* pS : vSeeds) {
0674 if (pS->level == -1) {
0675 continue;
0676 }
0677
0678 GbtsEdgeState rs = filter.followTrack(filterState, edgeStorage, *pS);
0679
0680 if (!rs.initialized) {
0681 continue;
0682 }
0683
0684 if (minLevel > static_cast<std::uint32_t>(rs.vs.size())) {
0685 continue;
0686 }
0687
0688 const float seedEta = std::abs(-std::log(pS->p[0]));
0689
0690 std::vector<const GbtsNode*> vN;
0691
0692 for (auto sIt = rs.vs.rbegin(); sIt != rs.vs.rend(); ++sIt) {
0693 if (seedEta > m_cfg.edgeMaskMinEta) {
0694
0695 (*sIt)->level = -1;
0696 }
0697
0698 if (sIt == rs.vs.rbegin()) {
0699 vN.push_back((*sIt)->n1);
0700 }
0701
0702 vN.push_back((*sIt)->n2);
0703 }
0704
0705 if (vN.size() < 3) {
0706 continue;
0707 }
0708
0709 std::vector<std::uint32_t> vSpIdx;
0710 vSpIdx.resize(vN.size());
0711
0712 for (std::uint32_t k = 0; k < vN.size(); ++k) {
0713 vSpIdx[k] = vN[k]->idx;
0714 }
0715
0716 vSeedCandidates.emplace_back(-rs.j / vN.size(), 0, std::move(vSpIdx));
0717 }
0718
0719
0720
0721 std::ranges::sort(vSeedCandidates,
0722 [](const SeedProperties& s1, const SeedProperties& s2) {
0723 return s1 < s2;
0724 });
0725
0726 std::vector<std::uint32_t> h2t(nHits + 1, 0);
0727
0728 std::uint32_t trackId = 0;
0729
0730 for (const auto& seed : vSeedCandidates) {
0731 ++trackId;
0732
0733
0734 for (const auto& h : seed.spacePoints) {
0735 const std::uint32_t hitId = h + 1;
0736
0737 const std::uint32_t tid = h2t[hitId];
0738
0739
0740 if (tid == 0 || tid > trackId) {
0741
0742 h2t[hitId] = trackId;
0743 }
0744 }
0745 }
0746
0747 for (std::uint32_t trackIdx = 0; trackIdx < vSeedCandidates.size();
0748 ++trackIdx) {
0749 const std::uint32_t nTotal = vSeedCandidates[trackIdx].spacePoints.size();
0750 std::uint32_t nOther = 0;
0751
0752 trackId = trackIdx + 1;
0753
0754 for (const auto& h : vSeedCandidates[trackIdx].spacePoints) {
0755 const std::uint32_t hitId = h + 1;
0756
0757 const std::uint32_t tid = h2t[hitId];
0758
0759
0760 if (tid != trackId) {
0761 nOther++;
0762 }
0763 }
0764
0765 if (nOther > m_cfg.hitShareThreshold * nTotal) {
0766
0767 vSeedCandidates[trackIdx].isClone = -1;
0768 }
0769 }
0770 }
0771
0772 bool GraphBasedTrackSeeder::checkZ0BitMask(const std::uint16_t z0BitMask,
0773 const float z0, const float minZ0,
0774 const float z0HistoCoeff) const {
0775 if (z0BitMask == 0) {
0776 return true;
0777 }
0778
0779 const float dz = z0 - minZ0;
0780 const std::int32_t z0BinIndex = static_cast<std::int32_t>(z0HistoCoeff * dz);
0781
0782 if (((z0BitMask >> z0BinIndex) & 1) != 0) {
0783 return true;
0784 }
0785
0786
0787
0788 const float z0Resolution = 2.5;
0789
0790 const float dzm = dz - z0Resolution;
0791
0792 std::int32_t nextBin = static_cast<std::int32_t>(z0HistoCoeff * dzm);
0793
0794 if (nextBin >= 0 && nextBin != z0BinIndex) {
0795 if (((z0BitMask >> nextBin) & 1) != 0) {
0796 return true;
0797 }
0798 }
0799
0800 const float dzp = dz + z0Resolution;
0801
0802 nextBin = static_cast<std::int32_t>(z0HistoCoeff * dzp);
0803
0804 if (nextBin < 16 && nextBin != z0BinIndex) {
0805 if (((z0BitMask >> nextBin) & 1) != 0) {
0806 return true;
0807 }
0808 }
0809
0810 return false;
0811 }
0812
0813 }