Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-02 07:50:52

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