File indexing completed on 2025-12-13 09:21:26
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "Acts/Seeding/SeedFinderGbts.hpp"
0010
0011 #include "Acts/Seeding/GbtsTrackingFilter.hpp"
0012 #include "Acts/Seeding/SeedFinderGbtsConfig.hpp"
0013
0014 #include <algorithm>
0015 #include <cmath>
0016 #include <numbers>
0017 #include <utility>
0018 #include <vector>
0019
0020 namespace Acts::Experimental {
0021
0022 SeedFinderGbts::SeedFinderGbts(
0023 SeedFinderGbtsConfig config, const GbtsGeometry* gbtsGeo,
0024 const std::vector<TrigInDetSiLayer>* layerGeometry,
0025 std::unique_ptr<const Acts::Logger> logger)
0026 : m_config(std::move(config)),
0027 m_geo(gbtsGeo),
0028 m_storage(std::make_unique<GNN_DataStorage>(*m_geo)),
0029 m_layerGeometry(layerGeometry),
0030 m_logger(std::move(logger)) {}
0031
0032 SeedContainer2 SeedFinderGbts::CreateSeeds(
0033 const RoiDescriptor& roi,
0034 const SPContainerComponentsType& SpContainerComponents, int max_layers) {
0035 SeedContainer2 SeedContainer;
0036 std::vector<std::vector<GNN_Node>> node_storage =
0037 CreateNodes(SpContainerComponents, max_layers);
0038 unsigned int nPixelLoaded = 0;
0039 unsigned int nStripLoaded = 0;
0040
0041 for (std::size_t l = 0; l < node_storage.size(); l++) {
0042 const std::vector<GNN_Node>& nodes = node_storage[l];
0043
0044 if (nodes.empty()) {
0045 continue;
0046 }
0047
0048 bool is_pixel = true;
0049 if (is_pixel) {
0050
0051 nPixelLoaded += m_storage->loadPixelGraphNodes(l, nodes, m_config.useML);
0052
0053 } else {
0054 nStripLoaded += m_storage->loadStripGraphNodes(l, nodes);
0055 }
0056 }
0057 ACTS_DEBUG("Loaded " << nPixelLoaded << " pixel spacepoints and "
0058 << nStripLoaded << " strip spacepoints");
0059
0060 m_storage->sortByPhi();
0061
0062 m_storage->initializeNodes(m_config.useML);
0063
0064 m_config.phiSliceWidth = 2 * std::numbers::pi / m_config.nMaxPhiSlice;
0065 m_storage->generatePhiIndexing(1.5 * m_config.phiSliceWidth);
0066
0067 std::vector<GNN_Edge> edgeStorage;
0068
0069 std::pair<int, int> graphStats = buildTheGraph(roi, m_storage, edgeStorage);
0070
0071 ACTS_DEBUG("Created graph with " << graphStats.first << " edges and "
0072 << graphStats.second << " edge links");
0073
0074 int maxLevel = runCCA(graphStats.first, edgeStorage);
0075
0076 ACTS_DEBUG("Reached Level " << maxLevel << " after GNN iterations");
0077
0078 int minLevel = 3;
0079
0080 if (m_config.LRTmode) {
0081 minLevel = 2;
0082 }
0083
0084 std::vector<GNN_Edge*> vSeeds;
0085
0086 vSeeds.reserve(graphStats.first / 2);
0087
0088 for (int edgeIndex = 0; edgeIndex < graphStats.first; edgeIndex++) {
0089 GNN_Edge* pS = &(edgeStorage.at(edgeIndex));
0090
0091 if (pS->m_level < minLevel) {
0092 continue;
0093 }
0094
0095 vSeeds.push_back(pS);
0096 }
0097
0098 std::sort(vSeeds.begin(), vSeeds.end(), GNN_Edge::CompareLevel());
0099
0100
0101
0102 GbtsTrackingFilter tFilter(*m_layerGeometry, edgeStorage, m_config);
0103
0104 for (auto pS : vSeeds) {
0105 if (pS->m_level == -1) {
0106 continue;
0107 }
0108
0109 GbtsEdgeState rs(false);
0110
0111 tFilter.followTrack(pS, rs);
0112
0113 if (!rs.m_initialized) {
0114 continue;
0115 }
0116
0117 if (static_cast<int>(rs.m_vs.size()) < minLevel) {
0118 continue;
0119 }
0120
0121 std::vector<const GNN_Node*> vN;
0122
0123 for (std::vector<GNN_Edge*>::reverse_iterator sIt = rs.m_vs.rbegin();
0124 sIt != rs.m_vs.rend(); ++sIt) {
0125 (*sIt)->m_level = -1;
0126
0127 if (sIt == rs.m_vs.rbegin()) {
0128 vN.push_back((*sIt)->m_n1);
0129 }
0130
0131 vN.push_back((*sIt)->m_n2);
0132 }
0133
0134 if (vN.size() < 3) {
0135 continue;
0136 }
0137
0138
0139 std::vector<SpacePointIndex2> Sp_Indexes{};
0140 Sp_Indexes.reserve(vN.size());
0141
0142 for (std::size_t i = 0; i < vN.size(); i++) {
0143 Sp_Indexes.emplace_back(vN.at(i)->sp_idx());
0144 }
0145
0146 auto seed = SeedContainer.createSeed();
0147 seed.assignSpacePointIndices(Sp_Indexes);
0148 }
0149
0150 ACTS_DEBUG("GBTS created " << SeedContainer.size() << " seeds");
0151
0152 return SeedContainer;
0153 }
0154
0155 std::vector<std::vector<SeedFinderGbts::GNN_Node>> SeedFinderGbts::CreateNodes(
0156 const auto& container, int MaxLayers) {
0157 std::vector<std::vector<SeedFinderGbts::GNN_Node>> node_storage(MaxLayers);
0158
0159
0160 for (auto& v : node_storage) {
0161 v.reserve(100000);
0162 }
0163
0164 for (auto sp : std::get<0>(container)) {
0165
0166
0167 int layer = sp.extra(std::get<1>(container));
0168
0169
0170 SeedFinderGbts::GNN_Node& node = node_storage[layer].emplace_back(layer);
0171
0172
0173
0174 node.m_x = sp.x();
0175 node.m_y = sp.y();
0176 node.m_z = sp.z();
0177 node.m_r = sp.r();
0178 node.m_phi = sp.phi();
0179 node.m_idx =
0180 sp.index();
0181
0182 node.m_pcw = sp.extra(std::get<2>(container));
0183 }
0184
0185 return node_storage;
0186 }
0187
0188 std::pair<int, int> SeedFinderGbts::buildTheGraph(
0189 const RoiDescriptor& roi, const std::unique_ptr<GbtsDataStorage>& storage,
0190 std::vector<GbtsEdge>& edgeStorage) const {
0191
0192 const float cut_dphi_max = m_config.LRTmode ? 0.07f : 0.012f;
0193
0194 const float cut_dcurv_max = m_config.LRTmode ? 0.015f : 0.001f;
0195
0196 const float cut_tau_ratio_max =
0197 m_config.LRTmode ? 0.015f : static_cast<float>(m_config.tau_ratio_cut);
0198 const float min_z0 = m_config.LRTmode ? -600.0 : roi.zedMinus();
0199 const float max_z0 = m_config.LRTmode ? 600.0 : roi.zedPlus();
0200 const float min_deltaPhi = m_config.LRTmode ? 0.01f : 0.001f;
0201
0202
0203 const float maxOuterRadius = m_config.LRTmode ? 1050.0 : 550.0;
0204
0205 const float cut_zMinU = min_z0 + maxOuterRadius * roi.dzdrMinus();
0206 const float cut_zMaxU = max_z0 + maxOuterRadius * roi.dzdrPlus();
0207
0208
0209 float tripletPtMin = 0.8 * m_config.minPt;
0210
0211 const float pt_scale = 900.0 / m_config.minPt;
0212
0213 float maxCurv = m_config.ptCoeff / tripletPtMin;
0214
0215 float maxKappa_high_eta =
0216 m_config.LRTmode ? 1.0 * maxCurv : std::sqrt(0.8) * maxCurv;
0217 float maxKappa_low_eta =
0218 m_config.LRTmode ? 1.0 * maxCurv : std::sqrt(0.6) * maxCurv;
0219
0220
0221 if (!m_config.useOldTunings && !m_config.LRTmode) {
0222 maxKappa_high_eta = 4.75e-4f * pt_scale;
0223 maxKappa_low_eta = 3.75e-4f * pt_scale;
0224 }
0225
0226 const float dphi_coeff = m_config.LRTmode ? 1.0 * maxCurv : 0.68 * maxCurv;
0227
0228
0229 float deltaPhi = 0.5f * m_config.phiSliceWidth;
0230
0231 unsigned int nConnections = 0;
0232
0233 edgeStorage.reserve(m_config.nMaxEdges);
0234
0235 int nEdges = 0;
0236
0237 for (const auto& bg : m_geo->bin_groups()) {
0238
0239 GbtsEtaBin& B1 = storage->getEtaBin(bg.first);
0240
0241 if (B1.empty()) {
0242 continue;
0243 }
0244
0245 float rb1 = B1.getMinBinRadius();
0246
0247 for (const auto& b2_idx : bg.second) {
0248 const GbtsEtaBin& B2 = storage->getEtaBin(b2_idx);
0249
0250 if (B2.empty()) {
0251 continue;
0252 }
0253
0254 float rb2 = B2.getMaxBinRadius();
0255
0256 if (m_config.useEtaBinning) {
0257 float abs_dr = std::fabs(rb2 - rb1);
0258 if (m_config.useOldTunings) {
0259 deltaPhi = min_deltaPhi + dphi_coeff * abs_dr;
0260 } else {
0261 if (abs_dr < 60.0) {
0262 deltaPhi = 0.002f + 4.33e-4f * pt_scale * abs_dr;
0263 } else {
0264 deltaPhi = 0.015f + 2.2e-4f * pt_scale * abs_dr;
0265 }
0266 }
0267 }
0268
0269 unsigned int first_it = 0;
0270
0271 for (unsigned int n1Idx = 0; n1Idx < B1.m_vn.size();
0272 n1Idx++) {
0273
0274 std::vector<unsigned int>& v1In = B1.m_in[n1Idx];
0275
0276 if (v1In.size() >= MAX_SEG_PER_NODE) {
0277 continue;
0278 }
0279
0280 const std::array<float, 5>& n1pars = B1.m_params[n1Idx];
0281
0282 float phi1 = n1pars[2];
0283 float r1 = n1pars[3];
0284 float z1 = n1pars[4];
0285
0286
0287
0288 float minPhi = phi1 - deltaPhi;
0289 float maxPhi = phi1 + deltaPhi;
0290
0291 for (unsigned int n2PhiIdx = first_it; n2PhiIdx < B2.m_vPhiNodes.size();
0292 n2PhiIdx++) {
0293
0294 float phi2 = B2.m_vPhiNodes[n2PhiIdx].first;
0295
0296 if (phi2 < minPhi) {
0297 first_it = n2PhiIdx;
0298 continue;
0299 }
0300 if (phi2 > maxPhi) {
0301 break;
0302 }
0303
0304 unsigned int n2Idx = B2.m_vPhiNodes[n2PhiIdx].second;
0305
0306 const std::vector<unsigned int>& v2In = B2.m_in[n2Idx];
0307
0308 if (v2In.size() >= MAX_SEG_PER_NODE) {
0309 continue;
0310 }
0311
0312 const std::array<float, 5>& n2pars = B2.m_params[n2Idx];
0313
0314 float r2 = n2pars[3];
0315
0316 float dr = r2 - r1;
0317
0318 if (dr < m_config.minDeltaRadius) {
0319 continue;
0320 }
0321
0322 float z2 = n2pars[4];
0323
0324 float dz = z2 - z1;
0325 float tau = dz / dr;
0326 float ftau = std::fabs(tau);
0327 if (ftau > 36.0) {
0328 continue;
0329 }
0330
0331 if (ftau < n1pars[0]) {
0332 continue;
0333 }
0334 if (ftau > n1pars[1]) {
0335 continue;
0336 }
0337
0338 if (ftau < n2pars[0]) {
0339 continue;
0340 }
0341 if (ftau > n2pars[1]) {
0342 continue;
0343 }
0344
0345 if (m_config.doubletFilterRZ) {
0346 float z0 = z1 - r1 * tau;
0347
0348 if (z0 < min_z0 || z0 > max_z0) {
0349 continue;
0350 }
0351
0352 float zouter = z0 + maxOuterRadius * tau;
0353
0354 if (zouter < cut_zMinU || zouter > cut_zMaxU) {
0355 continue;
0356 }
0357 }
0358
0359 float curv = (phi2 - phi1) / dr;
0360 float abs_curv = std::abs(curv);
0361
0362 if (ftau < 4.0) {
0363 if (abs_curv > maxKappa_low_eta) {
0364 continue;
0365 }
0366 } else {
0367 if (abs_curv > maxKappa_high_eta) {
0368 continue;
0369 }
0370 }
0371
0372 float exp_eta = std::sqrt(1 + tau * tau) - tau;
0373
0374 if (m_config.matchBeforeCreate) {
0375
0376
0377 bool isGood = v2In.size() <=
0378 2;
0379
0380 if (!isGood) {
0381 float uat_1 = 1.0f / exp_eta;
0382
0383 for (const auto& n2_in_idx : v2In) {
0384 float tau2 = edgeStorage.at(n2_in_idx).m_p[0];
0385 float tau_ratio = tau2 * uat_1 - 1.0f;
0386
0387 if (std::fabs(tau_ratio) > cut_tau_ratio_max) {
0388 continue;
0389 }
0390 isGood = true;
0391 break;
0392 }
0393 }
0394
0395 if (!isGood) {
0396 continue;
0397 }
0398 }
0399
0400 float dPhi2 = curv * r2;
0401 float dPhi1 = curv * r1;
0402
0403 if (nEdges < m_config.nMaxEdges) {
0404 edgeStorage.emplace_back(B1.m_vn[n1Idx], B2.m_vn[n2Idx], exp_eta,
0405 curv, phi1 + dPhi1);
0406
0407 if (v1In.size() < MAX_SEG_PER_NODE) {
0408 v1In.push_back(nEdges);
0409 }
0410
0411 int outEdgeIdx = nEdges;
0412
0413 float uat_2 = 1 / exp_eta;
0414 float Phi2 = phi2 + dPhi2;
0415 float curv2 = curv;
0416
0417 for (const auto& inEdgeIdx :
0418 v2In) {
0419
0420 GbtsEdge* pS = &(edgeStorage.at(inEdgeIdx));
0421
0422 if (pS->m_nNei >= N_SEG_CONNS) {
0423 continue;
0424 }
0425
0426 float tau_ratio = pS->m_p[0] * uat_2 - 1.0f;
0427
0428 if (std::abs(tau_ratio) > cut_tau_ratio_max) {
0429 continue;
0430 }
0431
0432 float dPhi = Phi2 - pS->m_p[2];
0433
0434 if (dPhi < -std::numbers::pi) {
0435 dPhi += 2 * std::numbers::pi;
0436 } else if (dPhi > std::numbers::pi) {
0437 dPhi -= 2 * std::numbers::pi;
0438 }
0439
0440 if (dPhi < -cut_dphi_max || dPhi > cut_dphi_max) {
0441 continue;
0442 }
0443
0444 float dcurv = curv2 - pS->m_p[1];
0445
0446 if (dcurv < -cut_dcurv_max || dcurv > cut_dcurv_max) {
0447 continue;
0448 }
0449
0450 pS->m_vNei[pS->m_nNei++] = outEdgeIdx;
0451
0452 nConnections++;
0453 }
0454 nEdges++;
0455 }
0456 }
0457 }
0458 }
0459 }
0460
0461 if (nEdges >= m_config.nMaxEdges) {
0462 ACTS_WARNING(
0463 "Maximum number of graph edges exceeded - possible efficiency loss "
0464 << nEdges);
0465 }
0466 return std::make_pair(nEdges, nConnections);
0467 }
0468
0469 int SeedFinderGbts::runCCA(int nEdges,
0470 std::vector<GbtsEdge>& edgeStorage) const {
0471 const int maxIter = 15;
0472
0473 int maxLevel = 0;
0474
0475 int iter = 0;
0476
0477 std::vector<GbtsEdge*> v_old;
0478
0479 for (int edgeIndex = 0; edgeIndex < nEdges; edgeIndex++) {
0480 GbtsEdge* pS = &(edgeStorage[edgeIndex]);
0481 if (pS->m_nNei == 0) {
0482 continue;
0483 }
0484
0485 v_old.push_back(pS);
0486
0487 }
0488
0489 for (; iter < maxIter; iter++) {
0490
0491 std::vector<GbtsEdge*> v_new;
0492 v_new.clear();
0493 v_new.reserve(v_old.size());
0494
0495 for (auto pS : v_old) {
0496 int next_level = pS->m_level;
0497
0498 for (int nIdx = 0; nIdx < pS->m_nNei; nIdx++) {
0499 unsigned int nextEdgeIdx = pS->m_vNei[nIdx];
0500
0501 GbtsEdge* pN = &(edgeStorage[nextEdgeIdx]);
0502
0503 if (pS->m_level == pN->m_level) {
0504 next_level = pS->m_level + 1;
0505 v_new.push_back(pS);
0506 break;
0507 }
0508 }
0509
0510 pS->m_next = next_level;
0511 }
0512
0513
0514
0515 int nChanges = 0;
0516
0517 for (auto pS : v_new) {
0518 if (pS->m_next != pS->m_level) {
0519 nChanges++;
0520 pS->m_level = pS->m_next;
0521 if (maxLevel < pS->m_level) {
0522 maxLevel = pS->m_level;
0523 }
0524 }
0525 }
0526
0527 if (nChanges == 0) {
0528 break;
0529 }
0530
0531 v_old = std::move(v_new);
0532 v_new.clear();
0533 }
0534
0535 return maxLevel;
0536 }
0537
0538 }