Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 08:21:35

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
0008 
0009 // SeedFinderGbts.ipp
0010 // TODO: update to C++17 style
0011 
0012 #include "Acts/Geometry/Extent.hpp"
0013 #include "Acts/Seeding/SeedFinder.hpp"
0014 #include "Acts/Seeding/SeedFinderGbtsConfig.hpp"
0015 #include "Acts/Seeding/SeedFinderUtils.hpp"
0016 #include "Acts/Utilities/BinningType.hpp"
0017 
0018 #include <algorithm>
0019 #include <cmath>
0020 #include <fstream>
0021 #include <functional>
0022 #include <iostream>
0023 #include <list>
0024 #include <numbers>
0025 #include <numeric>
0026 #include <type_traits>
0027 #include <vector>
0028 
0029 // core so in ACTS namespace
0030 
0031 namespace Acts::Experimental {
0032 
0033 template <typename external_spacepoint_t>
0034 SeedFinderGbts<external_spacepoint_t>::SeedFinderGbts(
0035     const SeedFinderGbtsConfig<external_spacepoint_t>& config,
0036     const GbtsGeometry<external_spacepoint_t>& gbtsGeo,
0037     std::unique_ptr<const Acts::Logger> logger)
0038     : m_config(config),
0039       m_storage(
0040           std::make_unique<GbtsDataStorage<external_spacepoint_t>>(gbtsGeo)),
0041       m_logger(std::move(logger)) {}
0042 
0043 // define loadspace points function
0044 template <typename external_spacepoint_t>
0045 void SeedFinderGbts<external_spacepoint_t>::loadSpacePoints(
0046     const std::vector<GbtsSP<external_spacepoint_t>>& gbtsSPvect) {
0047   ACTS_VERBOSE("Loading space points");
0048   for (const auto& gbtssp : gbtsSPvect) {
0049     m_storage->addSpacePoint(gbtssp, (m_config.m_useClusterWidth > 0));
0050   }
0051 
0052   m_config.m_phiSliceWidth = 2 * std::numbers::pi / m_config.m_nMaxPhiSlice;
0053 
0054   m_storage->sortByPhi();
0055 
0056   m_storage->generatePhiIndexing(1.5 * m_config.m_phiSliceWidth);
0057 }
0058 
0059 template <typename external_spacepoint_t>
0060 void SeedFinderGbts<external_spacepoint_t>::runGbts_TrackFinder(
0061     std::vector<GbtsTrigTracklet<external_spacepoint_t>>& vTracks,
0062     const RoiDescriptor& roi,
0063     const GbtsGeometry<external_spacepoint_t>& gbtsGeo) {
0064   ACTS_VERBOSE("Running GBTS Track Finder");
0065   const float min_z0 = roi.zedMinus();
0066   const float max_z0 = roi.zedPlus();
0067   const float cut_zMinU = min_z0 + m_config.maxOuterRadius * roi.dzdrMinus();
0068   const float cut_zMaxU = max_z0 + m_config.maxOuterRadius * roi.dzdrPlus();
0069   float m_minR_squ = m_config.m_tripletPtMin * m_config.m_tripletPtMin /
0070                      std::pow(m_config.ptCoeff, 2);  // from athena
0071   float m_maxCurv = m_config.ptCoeff / m_config.m_tripletPtMin;
0072   const float maxKappa_high_eta = 0.8 / m_minR_squ;
0073   const float maxKappa_low_eta = 0.6 / m_minR_squ;
0074 
0075   // 1. loop over stages
0076 
0077   int currentStage = 0;
0078 
0079   const GbtsConnector& connector = *(gbtsGeo.connector());
0080 
0081   std::vector<GbtsEdge<external_spacepoint_t>> edgeStorage;
0082 
0083   edgeStorage.reserve(m_config.MaxEdges);
0084 
0085   int nEdges = 0;
0086 
0087   for (std::map<int, std::vector<GbtsConnector::LayerGroup>>::const_iterator
0088            it = connector.m_layerGroups.begin();
0089        it != connector.m_layerGroups.end(); ++it, currentStage++) {
0090     // loop over L1 layers for the current stage
0091 
0092     for (const auto& layerGroup : (*it).second) {
0093       unsigned int dst = layerGroup.m_dst;  // n1 : inner nodes
0094 
0095       const GbtsLayer<external_spacepoint_t>* pL1 =
0096           gbtsGeo.getGbtsLayerByKey(dst);
0097 
0098       if (pL1 == nullptr) {
0099         continue;
0100       }
0101 
0102       for (const auto& conn :
0103            layerGroup.m_sources) {  // loop over L2(L1) for the current stage
0104 
0105         unsigned int src = conn->m_src;  // n2 : the new connectors
0106 
0107         const GbtsLayer<external_spacepoint_t>* pL2 =
0108             gbtsGeo.getGbtsLayerByKey(src);
0109 
0110         if (pL2 == nullptr) {
0111           continue;
0112         }
0113         int nDstBins = pL1->m_bins.size();
0114         int nSrcBins = pL2->m_bins.size();
0115 
0116         for (int b1 = 0; b1 < nDstBins; b1++) {  // loop over bins in Layer 1
0117 
0118           const GbtsEtaBin<external_spacepoint_t>& B1 =
0119               m_storage->getEtaBin(pL1->m_bins.at(b1));
0120 
0121           if (B1.empty()) {
0122             continue;
0123           }
0124 
0125           float rb1 = pL1->getMinBinRadius(b1);
0126 
0127           // 3. loops over source eta-bins
0128 
0129           for (int b2 = 0; b2 < nSrcBins; b2++) {  // loop over bins in Layer 2
0130 
0131             if (m_config.m_useEtaBinning && (nSrcBins + nDstBins > 2)) {
0132               if (conn->m_binTable[b1 + b2 * nDstBins] != 1) {
0133                 continue;  // using precomputed LUT
0134               }
0135             }
0136 
0137             const GbtsEtaBin<external_spacepoint_t>& B2 =
0138                 m_storage->getEtaBin(pL2->m_bins.at(b2));
0139 
0140             if (B2.empty()) {
0141               continue;
0142             }
0143 
0144             float rb2 = pL2->getMaxBinRadius(b2);
0145 
0146             // calculated delta Phi for rb1 ---> rb2 extrapolation
0147 
0148             float deltaPhi =
0149                 0.5f *
0150                 m_config
0151                     .m_phiSliceWidth;  // the default sliding window along phi
0152 
0153             if (m_config.m_useEtaBinning) {
0154               deltaPhi = 0.001f + m_maxCurv * std::abs(rb2 - rb1);
0155             }
0156 
0157             unsigned int first_it = 0;
0158             for (const auto& n1 : B1.m_vn) {  // loop over nodes in Layer 1
0159 
0160               if (n1->m_in.size() >= MAX_SEG_PER_NODE) {
0161                 continue;
0162               }
0163 
0164               float r1 = n1->m_spGbts.r();
0165               float x1 = n1->m_spGbts.SP->x();
0166               float y1 = n1->m_spGbts.SP->y();
0167               float z1 = n1->m_spGbts.SP->z();
0168               float phi1 = n1->m_spGbts.phi();
0169 
0170               float minPhi = phi1 - deltaPhi;
0171               float maxPhi = phi1 + deltaPhi;
0172 
0173               for (unsigned int n2PhiIdx = first_it;
0174                    n2PhiIdx < B2.m_vPhiNodes.size();
0175                    n2PhiIdx++) {  // sliding window over nodes in Layer 2
0176 
0177                 float phi2 = B2.m_vPhiNodes.at(n2PhiIdx).first;
0178 
0179                 if (phi2 < minPhi) {
0180                   first_it = n2PhiIdx;
0181                   continue;
0182                 }
0183                 if (phi2 > maxPhi) {
0184                   break;
0185                 }
0186 
0187                 GbtsNode<external_spacepoint_t>* n2 =
0188                     B2.m_vn.at(B2.m_vPhiNodes.at(n2PhiIdx).second).get();
0189 
0190                 if (n2->m_out.size() >= MAX_SEG_PER_NODE) {
0191                   continue;
0192                 }
0193                 if (n2->isFull()) {
0194                   continue;
0195                 }
0196 
0197                 float r2 = n2->m_spGbts.r();
0198 
0199                 float dr = r2 - r1;
0200 
0201                 if (dr < m_config.m_minDeltaRadius) {
0202                   continue;
0203                 }
0204 
0205                 float z2 = n2->m_spGbts.SP->z();
0206 
0207                 float dz = z2 - z1;
0208                 float tau = dz / dr;
0209                 float ftau = std::abs(tau);
0210                 if (ftau > 36.0) {
0211                   continue;
0212                 }
0213 
0214                 if (ftau < n1->m_minCutOnTau) {
0215                   continue;
0216                 }
0217                 if (ftau < n2->m_minCutOnTau) {
0218                   continue;
0219                 }
0220                 if (ftau > n1->m_maxCutOnTau) {
0221                   continue;
0222                 }
0223                 if (ftau > n2->m_maxCutOnTau) {
0224                   continue;
0225                 }
0226 
0227                 if (m_config.m_doubletFilterRZ) {
0228                   float z0 = z1 - r1 * tau;
0229 
0230                   if (z0 < min_z0 || z0 > max_z0) {
0231                     continue;
0232                   }
0233 
0234                   float zouter = z0 + m_config.maxOuterRadius * tau;
0235 
0236                   if (zouter < cut_zMinU || zouter > cut_zMaxU) {
0237                     continue;
0238                   }
0239                 }
0240 
0241                 float dx = n2->m_spGbts.SP->x() - x1;
0242                 float dy = n2->m_spGbts.SP->y() - y1;
0243 
0244                 float L2 = 1 / (dx * dx + dy * dy);
0245 
0246                 float D =
0247                     (n2->m_spGbts.SP->y() * x1 - y1 * n2->m_spGbts.SP->x()) /
0248                     (r1 * r2);
0249 
0250                 float kappa = D * D * L2;
0251 
0252                 if (ftau < 4.0) {  // eta = 2.1
0253                   if (kappa > maxKappa_low_eta) {
0254                     continue;
0255                   }
0256 
0257                 } else {
0258                   if (kappa > maxKappa_high_eta) {
0259                     continue;
0260                   }
0261                 }
0262 
0263                 // match edge candidate against edges incoming to n2
0264 
0265                 float exp_eta = std::sqrt(1 + tau * tau) - tau;
0266 
0267                 bool isGood =
0268                     n2->m_in.size() <=
0269                     2;  // we must have enough incoming edges to decide
0270 
0271                 if (!isGood) {
0272                   float uat_1 = 1.0f / exp_eta;
0273 
0274                   for (const auto& n2_in_idx : n2->m_in) {
0275                     float tau2 = edgeStorage.at(n2_in_idx).m_p[0];
0276                     float tau_ratio = tau2 * uat_1 - 1.0f;
0277 
0278                     // bad match
0279                     if (std::abs(tau_ratio) > m_config.cut_tau_ratio_max) {
0280                       continue;
0281                     }
0282 
0283                     // good match found
0284                     isGood = true;
0285                     break;
0286                   }
0287                 }
0288                 if (!isGood) {
0289                   continue;  // no match found, skip creating [n1 <- n2] edge
0290                 }
0291 
0292                 float curv = D * std::sqrt(L2);  // signed curvature
0293                 float dPhi2 = std::asin(curv * r2);
0294                 float dPhi1 = std::asin(curv * r1);
0295 
0296                 if (nEdges < m_config.MaxEdges) {
0297                   edgeStorage.emplace_back(n1.get(), n2, exp_eta, curv,
0298                                            phi1 + dPhi1, phi2 + dPhi2);
0299 
0300                   n1->addIn(nEdges);
0301                   n2->addOut(nEdges);
0302 
0303                   nEdges++;
0304                 }
0305               }  // loop over n2 (outer) nodes
0306             }  // loop over n1 (inner) nodes
0307           }  // loop over source eta bins
0308         }  // loop over dst eta bins
0309       }  // loop over L2(L1) layers
0310     }  // loop over dst layers
0311   }  // loop over the stages of doublet making
0312 
0313   std::vector<const GbtsNode<external_spacepoint_t>*> vNodes;
0314 
0315   m_storage->getConnectingNodes(vNodes);
0316 
0317   if (vNodes.empty()) {
0318     ACTS_VERBOSE("No nodes");
0319     return;
0320   }
0321 
0322   int nNodes = vNodes.size();
0323 
0324   for (int nodeIdx = 0; nodeIdx < nNodes; nodeIdx++) {
0325     const GbtsNode<external_spacepoint_t>& pN = *vNodes.at(nodeIdx);
0326 
0327     std::vector<std::pair<float, int>> in_sort, out_sort;
0328     in_sort.resize(pN.m_in.size());
0329     out_sort.resize(pN.m_out.size());
0330 
0331     for (int inIdx = 0; inIdx < static_cast<int>(pN.m_in.size()); inIdx++) {
0332       int inEdgeIdx = pN.m_in.at(inIdx);
0333       GbtsEdge<external_spacepoint_t>* pS = &(edgeStorage.at(inEdgeIdx));
0334       in_sort[inIdx].second = inEdgeIdx;
0335       in_sort[inIdx].first = pS->m_p[0];
0336     }
0337     for (int outIdx = 0; outIdx < static_cast<int>(pN.m_out.size()); outIdx++) {
0338       int outEdgeIdx = pN.m_out.at(outIdx);
0339       GbtsEdge<external_spacepoint_t>* pS = &(edgeStorage.at(outEdgeIdx));
0340       out_sort[outIdx].second = outEdgeIdx;
0341       out_sort[outIdx].first = pS->m_p[0];
0342     }
0343 
0344     std::ranges::sort(in_sort);
0345     std::ranges::sort(out_sort);
0346 
0347     unsigned int last_out = 0;
0348 
0349     for (unsigned int in_idx = 0; in_idx < in_sort.size();
0350          in_idx++) {  // loop over incoming edges
0351 
0352       int inEdgeIdx = in_sort[in_idx].second;
0353 
0354       GbtsEdge<external_spacepoint_t>* pS = &(edgeStorage.at(inEdgeIdx));
0355 
0356       pS->m_nNei = 0;
0357       float tau1 = pS->m_p[0];
0358       float uat_1 = 1.0f / tau1;
0359       float curv1 = pS->m_p[1];
0360       float Phi1 = pS->m_p[2];
0361 
0362       for (unsigned int out_idx = last_out; out_idx < out_sort.size();
0363            out_idx++) {
0364         int outEdgeIdx = out_sort[out_idx].second;
0365 
0366         GbtsEdge<external_spacepoint_t>* pNS = &(edgeStorage.at(outEdgeIdx));
0367 
0368         float tau2 = pNS->m_p[0];
0369         float tau_ratio = tau2 * uat_1 - 1.0f;
0370 
0371         if (tau_ratio < -m_config.cut_tau_ratio_max) {
0372           last_out = out_idx;
0373           continue;
0374         }
0375         if (tau_ratio > m_config.cut_tau_ratio_max) {
0376           break;
0377         }
0378 
0379         float dPhi = pNS->m_p[3] - Phi1;
0380 
0381         if (dPhi < -std::numbers::pi_v<float>) {
0382           dPhi += static_cast<float>(2 * std::numbers::pi);
0383         } else if (dPhi > std::numbers::pi_v<float>) {
0384           dPhi -= static_cast<float>(2 * std::numbers::pi);
0385         }
0386 
0387         if (dPhi < -m_config.cut_dphi_max || dPhi > m_config.cut_dphi_max) {
0388           continue;
0389         }
0390 
0391         float curv2 = pNS->m_p[1];
0392         float dcurv = curv2 - curv1;
0393 
0394         if (dcurv < -m_config.cut_dcurv_max || dcurv > m_config.cut_dcurv_max) {
0395           continue;
0396         }
0397 
0398         pS->m_vNei[pS->m_nNei++] = outEdgeIdx;
0399         if (pS->m_nNei >= N_SEG_CONNS) {
0400           break;
0401         }
0402       }
0403     }
0404   }
0405 
0406   const int maxIter = 15;
0407 
0408   int maxLevel = 0;
0409 
0410   int iter = 0;
0411 
0412   std::vector<GbtsEdge<external_spacepoint_t>*> v_old;
0413 
0414   for (int edgeIndex = 0; edgeIndex < nEdges; edgeIndex++) {
0415     GbtsEdge<external_spacepoint_t>* pS = &(edgeStorage.at(edgeIndex));
0416     if (pS->m_nNei == 0) {
0417       continue;
0418     }
0419     v_old.push_back(pS);  // TO-DO: increment level for segments as they already
0420                           // have at least one neighbour
0421   }
0422 
0423   for (; iter < maxIter; iter++) {
0424     // generate proposals
0425     std::vector<GbtsEdge<external_spacepoint_t>*> v_new;
0426     v_new.clear();
0427 
0428     for (auto pS : v_old) {
0429       int next_level = pS->m_level;
0430 
0431       for (int nIdx = 0; nIdx < pS->m_nNei; nIdx++) {
0432         unsigned int nextEdgeIdx = pS->m_vNei[nIdx];
0433 
0434         GbtsEdge<external_spacepoint_t>* pN = &(edgeStorage.at(nextEdgeIdx));
0435 
0436         if (pS->m_level == pN->m_level) {
0437           next_level = pS->m_level + 1;
0438           v_new.push_back(pS);
0439           break;
0440         }
0441       }
0442 
0443       pS->m_next = next_level;  // proposal
0444     }
0445     // update
0446 
0447     int nChanges = 0;
0448 
0449     for (auto pS : v_new) {
0450       if (pS->m_next != pS->m_level) {
0451         nChanges++;
0452         pS->m_level = pS->m_next;
0453         if (maxLevel < pS->m_level) {
0454           maxLevel = pS->m_level;
0455         }
0456       }
0457     }
0458 
0459     if (nChanges == 0) {
0460       break;
0461     }
0462 
0463     v_old = std::move(v_new);
0464     v_new.clear();
0465   }
0466 
0467   int minLevel = 3;  // a triplet + 2 confirmation
0468 
0469   std::vector<GbtsEdge<external_spacepoint_t>*> vSeeds;
0470 
0471   vSeeds.reserve(m_config.MaxEdges / 2);
0472 
0473   for (int edgeIndex = 0; edgeIndex < nEdges; edgeIndex++) {
0474     GbtsEdge<external_spacepoint_t>* pS = &(edgeStorage.at(edgeIndex));
0475 
0476     if (pS->m_level < minLevel) {
0477       continue;
0478     }
0479 
0480     vSeeds.push_back(pS);
0481   }
0482 
0483   m_triplets.clear();
0484 
0485   std::ranges::sort(vSeeds,
0486                     typename GbtsEdge<external_spacepoint_t>::CompareLevel());
0487 
0488   if (vSeeds.empty()) {
0489     return;
0490   }
0491 
0492   // backtracking
0493 
0494   GbtsTrackingFilter<external_spacepoint_t> tFilter(
0495       m_config.m_layerGeometry, edgeStorage,
0496       logger().cloneWithSuffix("GbtsFilter"));
0497 
0498   for (auto pS : vSeeds) {
0499     if (pS->m_level == -1) {
0500       continue;
0501     }
0502 
0503     GbtsEdgeState<external_spacepoint_t> rs(false);
0504 
0505     tFilter.followTrack(pS, rs);
0506 
0507     if (!rs.m_initialized) {
0508       continue;
0509     }
0510 
0511     if (static_cast<int>(rs.m_vs.size()) < minLevel) {
0512       continue;
0513     }
0514 
0515     std::vector<const GbtsSP<external_spacepoint_t>*> vSP;
0516 
0517     for (typename std::vector<
0518              GbtsEdge<external_spacepoint_t>*>::reverse_iterator sIt =
0519              rs.m_vs.rbegin();
0520          sIt != rs.m_vs.rend(); ++sIt) {
0521       (*sIt)->m_level = -1;  // mark as collected
0522 
0523       if (sIt == rs.m_vs.rbegin()) {
0524         vSP.push_back(&(*sIt)->m_n1->m_spGbts);
0525       }
0526       vSP.push_back(&(*sIt)->m_n2->m_spGbts);
0527     }
0528 
0529     if (vSP.size() < 3) {
0530       continue;
0531     }
0532 
0533     // making triplets
0534 
0535     unsigned int nTriplets = 0;
0536 
0537     std::vector<TrigInDetTriplet<external_spacepoint_t>> output;
0538 
0539     for (unsigned int idx_m = 1; idx_m < vSP.size() - 1; idx_m++) {
0540       const GbtsSP<external_spacepoint_t>& spM = *vSP.at(idx_m);
0541       const double pS_r = spM.r();
0542       const double pS_x = spM.SP->x();
0543       const double pS_y = spM.SP->y();
0544       const double cosA = pS_x / pS_r;
0545       const double sinA = pS_y / pS_r;
0546 
0547       for (unsigned int idx_o = idx_m + 1; idx_o < vSP.size(); idx_o++) {
0548         const GbtsSP<external_spacepoint_t>& spO = *vSP.at(idx_o);
0549 
0550         double dx = spO.SP->x() - pS_x;
0551         double dy = spO.SP->y() - pS_y;
0552         double R2inv = 1.0 / (dx * dx + dy * dy);
0553         double xn = dx * cosA + dy * sinA;
0554         double yn = -dx * sinA + dy * cosA;
0555 
0556         const double uo = xn * R2inv;
0557         const double vo = yn * R2inv;
0558 
0559         for (unsigned int idx_i = 0; idx_i < idx_m; idx_i++) {
0560           const GbtsSP<external_spacepoint_t>& spI = *vSP.at(idx_i);
0561 
0562           dx = spI.SP->x() - pS_x;
0563           dy = spI.SP->y() - pS_y;
0564           R2inv = 1.0 / (dx * dx + dy * dy);
0565 
0566           xn = dx * cosA + dy * sinA;
0567           yn = -dx * sinA + dy * cosA;
0568 
0569           const double ui = xn * R2inv;
0570           const double vi = yn * R2inv;
0571 
0572           // 1. pT estimate
0573 
0574           const double du = uo - ui;
0575           if (du == 0.0) {
0576             continue;
0577           }
0578           const double A = (vo - vi) / du;
0579           const double B = vi - A * ui;
0580 
0581           if ((1 + A * A) < (B * B) * m_minR_squ) {
0582             continue;
0583           }
0584 
0585           // 2. d0 cut
0586 
0587           const double fabs_d0 = std::abs(pS_r * (B * pS_r - A));
0588 
0589           if (fabs_d0 > m_config.m_tripletD0Max) {
0590             continue;
0591           }
0592 
0593           // 3. phi0 cut
0594 
0595           // if (!roi.isFullscan()) {
0596           //   const double uc = 2 * B * pS_r - A;
0597           //   // const double phi0 = std::atan2(sinA - uc * cosA, cosA + uc *
0598           //   sinA);
0599           //   //           if ( !RoiUtil::containsPhi( *roiDescriptor, phi0 ) )
0600           //   {
0601           //   //             continue;
0602           //   //           }
0603           // }
0604 
0605           // 4. add new triplet
0606 
0607           const double Q = fabs_d0 * fabs_d0;
0608 
0609           output.emplace_back(spI, spM, spO, Q);
0610 
0611           nTriplets++;
0612 
0613           if (nTriplets >= m_config.m_maxTripletBufferLength) {
0614             break;
0615           }
0616         }
0617         if (nTriplets >= m_config.m_maxTripletBufferLength) {
0618           break;
0619         }
0620       }
0621       if (nTriplets >= m_config.m_maxTripletBufferLength) {
0622         break;
0623       }
0624     }
0625 
0626     if (output.empty()) {
0627       continue;
0628     }
0629 
0630     vTracks.emplace_back(vSP, output);
0631   }
0632 }
0633 
0634 template <typename external_spacepoint_t>
0635 template <typename output_container_t>
0636 void SeedFinderGbts<external_spacepoint_t>::createSeeds(
0637     const RoiDescriptor& roi,
0638     const GbtsGeometry<external_spacepoint_t>& gbtsGeo,
0639     output_container_t& out_cont) {
0640   ACTS_VERBOSE("Creating seeds");
0641   std::vector<GbtsTrigTracklet<external_spacepoint_t>>
0642       vTracks;  // make empty vector
0643 
0644   vTracks.reserve(5000);
0645 
0646   runGbts_TrackFinder(vTracks, roi, gbtsGeo);  // returns filled vector
0647 
0648   if (vTracks.empty()) {
0649     return;
0650   }
0651 
0652   m_triplets.clear();
0653 
0654   for (auto& track : vTracks) {
0655     for (auto& seed : track.m_seeds) {  // access member of GbtsTrigTracklet
0656       // Currently not used, but leaving in to use concept in future development
0657       //  float newQ = seed.Q();  // function of TrigInDetTriplet
0658       //  if (m_config.m_LRTmode) {
0659       //    // In LRT mode penalize pixels in Triplets
0660       //    if (seed.s1().isPixel()) {
0661       //      newQ += 1000;  // functions of TrigSiSpacePointBase
0662       //    }
0663       //    if (seed.s2().isPixel()) {
0664       //      newQ += 1000;
0665       //    }
0666       //    if (seed.s3().isPixel()) {
0667       //      newQ += 1000;
0668       //    }
0669       //  } else {
0670       //    // In normal (non LRT) mode penalise SSS by 1000, PSS (if enabled)
0671       //    and
0672       //    // PPS by 10000
0673       //    if (seed.s3().isSCT()) {
0674       //      newQ += seed.s1().isSCT() ? 1000.0 : 10000.0;
0675       //    }
0676       //  }
0677       //  seed.Q(newQ);
0678       m_triplets.emplace_back(seed);
0679     }
0680   }
0681   vTracks.clear();
0682 
0683   for (auto& triplet : m_triplets) {
0684     const external_spacepoint_t* S1 =
0685         triplet.s1().SP;  // triplet-> GbtsSP-> simspacepoint
0686     const external_spacepoint_t* S2 = triplet.s2().SP;
0687     const external_spacepoint_t* S3 = triplet.s3().SP;
0688 
0689     // input to seed
0690     float Vertex = 0;
0691     float Quality = triplet.Q();
0692     // make a new seed, add to vector of seeds
0693     out_cont.emplace_back(*S1, *S2, *S3);
0694     out_cont.back().setVertexZ(Vertex);
0695     out_cont.back().setQuality(Quality);
0696   }
0697 }
0698 
0699 // outer called in alg
0700 template <typename external_spacepoint_t>
0701 std::vector<Seed<external_spacepoint_t>>
0702 SeedFinderGbts<external_spacepoint_t>::createSeeds(
0703     const RoiDescriptor& roi,
0704     const GbtsGeometry<external_spacepoint_t>& gbtsGeo) {
0705   std::vector<seed_t> r;
0706   createSeeds(roi, gbtsGeo, r);
0707   return r;
0708 }
0709 
0710 }  // namespace Acts::Experimental