Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-07-26 08:22:09

0001 /** TRACCC library, part of the ACTS project (R&D line)
0002  *
0003  * (c) 2025-2026 CERN for the benefit of the ACTS project
0004  *
0005  * Mozilla Public License Version 2.0
0006  */
0007 
0008 // Local include(s).
0009 #include "traccc/gbts_seeding/device/gbts_seeding_algorithm.hpp"
0010 
0011 #include "traccc/gbts_seeding/gbts_seeding_config.hpp"
0012 
0013 // VecMem include(s).
0014 #include <vecmem/containers/data/vector_buffer.hpp>
0015 #include <vecmem/containers/vector.hpp>
0016 
0017 // System include(s).
0018 #include <algorithm>
0019 #include <cmath>
0020 #include <utility>
0021 
0022 namespace traccc::device {
0023 
0024 // Stage 1:
0025 // Bin the spacepoints by layer in eta and phi,
0026 // compute the node parameters (x, y, z, w)
0027 // and the bin-wise min/max radius for the graph-building cuts.
0028 auto gbts_seeding_algorithm::make_nodes(
0029     const edm::spacepoint_collection::const_view& spacepoints,
0030     const edm::measurement_collection::const_view& measurements) const
0031     -> node_making_output {
0032   const gbts_seedfinder_config& cfg = m_config;
0033   const unsigned int nSp = copy().get_size(spacepoints);
0034 
0035   // 0. Bin spacepoints by the mapping supplied to config.surfaceToLayerMap.
0036   vecmem::data::vector_buffer<unsigned int> layerCounts_buf(cfg.nLayers + 1,
0037                                                             mr().main);
0038   copy().memset(layerCounts_buf, 0)->ignore();
0039 
0040   vecmem::data::vector_buffer<float4> reducedSP_buf(nSp, mr().main);
0041   copy().setup(reducedSP_buf)->ignore();
0042 
0043   vecmem::data::vector_buffer<unsigned short> spacepointsLayer_buf(nSp,
0044                                                                    mr().main);
0045   copy().setup(spacepointsLayer_buf)->ignore();
0046 
0047   vecmem::data::vector_buffer<short> volumeToLayerMap_buf(
0048       static_cast<unsigned int>(cfg.volumeToLayerMap.size()), mr().main);
0049   copy().setup(volumeToLayerMap_buf)->ignore();
0050   copy()(vecmem::get_data(cfg.volumeToLayerMap), volumeToLayerMap_buf)
0051       ->ignore();
0052 
0053   vecmem::data::vector_buffer<std::pair<unsigned int, unsigned int>>
0054       surfaceToLayerMap_buf;
0055   if (!cfg.surfaceToLayerMap.empty()) {
0056     surfaceToLayerMap_buf =
0057         vecmem::data::vector_buffer<std::pair<unsigned int, unsigned int>>(
0058             static_cast<unsigned int>(cfg.surfaceToLayerMap.size()), mr().main);
0059     copy().setup(surfaceToLayerMap_buf)->ignore();
0060     copy()(vecmem::get_data(cfg.surfaceToLayerMap), surfaceToLayerMap_buf)
0061         ->ignore();
0062   }
0063 
0064   vecmem::data::vector_buffer<char> layerType_buf(cfg.nLayers, mr().main);
0065   copy().setup(layerType_buf)->ignore();
0066   copy()(vecmem::get_data(cfg.layerInfo.type), layerType_buf)->ignore();
0067   gbts_count_spacepoints_by_layer_kernel(
0068       {nSp, spacepoints, measurements, volumeToLayerMap_buf,
0069        surfaceToLayerMap_buf, layerType_buf, reducedSP_buf, layerCounts_buf,
0070        spacepointsLayer_buf, cfg.volumeToLayerMap.size(),
0071        cfg.surfaceToLayerMap.size(),
0072        cfg.gbts_count_spacepoints_by_layer_params});
0073 
0074   vecmem::vector<unsigned int> layerCounts(cfg.nLayers + 1, mr().host);
0075   copy()(vecmem::get_data(layerCounts_buf), layerCounts)->wait();
0076 
0077   const unsigned int nNodes =
0078       static_cast<unsigned int>(layerCounts[cfg.nLayers]);
0079   TRACCC_DEBUG("nNodes " << nNodes);
0080   if (nNodes == 0) {
0081     TRACCC_WARNING("No nodes were found after spacepoint counting");
0082     return node_making_output{};
0083   }
0084 
0085   vecmem::data::vector_buffer<float4> sp_params_buf(nSp, mr().main);
0086   copy().setup(sp_params_buf)->ignore();
0087   vecmem::data::vector_buffer<unsigned int> original_sp_idx_buf(nSp, mr().main);
0088   copy().setup(original_sp_idx_buf)->ignore();
0089 
0090   // 1. Fused binning: scatter spacepoints into layer-ordered slots, compute
0091   //    their eta/phi bin indices and fill the (eta, phi) histogram, all in a
0092   //    single pass.
0093   vecmem::data::vector_buffer<std::pair<unsigned int, unsigned int>>
0094       layer_info_buf(cfg.nLayers, mr().main);
0095   copy().setup(layer_info_buf)->ignore();
0096   copy()(vecmem::get_data(cfg.layerInfo.info), layer_info_buf)->ignore();
0097 
0098   vecmem::data::vector_buffer<std::pair<float, float>> layer_geo_buf(
0099       cfg.nLayers, mr().main);
0100   copy().setup(layer_geo_buf)->ignore();
0101   copy()(vecmem::get_data(cfg.layerInfo.geo), layer_geo_buf)->ignore();
0102 
0103   vecmem::data::vector_buffer<unsigned int> node_phi_index_buf(nNodes,
0104                                                                mr().main);
0105   copy().setup(node_phi_index_buf)->ignore();
0106 
0107   vecmem::data::vector_buffer<unsigned int> node_eta_index_buf(nNodes,
0108                                                                mr().main);
0109   copy().setup(node_eta_index_buf)->ignore();
0110 
0111   const unsigned int hist_size = cfg.n_eta_bins * cfg.n_phi_bins;
0112   vecmem::data::vector_buffer<unsigned int> eta_phi_histo_buf(hist_size,
0113                                                               mr().main);
0114   copy().setup(eta_phi_histo_buf)->ignore();
0115   copy().memset(eta_phi_histo_buf, 0)->ignore();
0116   vecmem::data::vector_buffer<unsigned int> phi_cusums_buf(hist_size,
0117                                                            mr().main);
0118   copy().setup(phi_cusums_buf)->ignore();
0119 
0120   gbts_bin_spacepoints_kernel(
0121       {nSp, cfg.n_phi_bins, sp_params_buf, reducedSP_buf, layerCounts_buf,
0122        spacepointsLayer_buf, original_sp_idx_buf, layer_info_buf, layer_geo_buf,
0123        node_eta_index_buf, node_phi_index_buf, eta_phi_histo_buf});
0124 
0125   vecmem::data::vector_buffer<unsigned int> eta_node_counter_buf(cfg.n_eta_bins,
0126                                                                  mr().main);
0127   copy().setup(eta_node_counter_buf)->ignore();
0128 
0129   gbts_count_eta_phi_bins_kernel({cfg.n_eta_bins, cfg.n_phi_bins,
0130                                   eta_phi_histo_buf, eta_node_counter_buf,
0131                                   phi_cusums_buf});
0132 
0133   vecmem::vector<unsigned int> eta_sums(cfg.n_eta_bins, mr().host);
0134   copy()(vecmem::get_data(eta_node_counter_buf), eta_sums)->wait();
0135 
0136   vecmem::vector<unsigned int> eta_bin_views(2 * cfg.n_eta_bins, mr().host);
0137   for (unsigned int view_idx = 0; view_idx < cfg.n_eta_bins; view_idx++) {
0138     const unsigned int pos = 2 * view_idx;
0139     eta_bin_views[pos] = (view_idx == 0) ? 0 : eta_sums[view_idx - 1];
0140     eta_bin_views[pos + 1] = eta_sums[view_idx];
0141   }
0142 
0143   gbts_prefix_sum_eta_phi_bins_kernel(
0144       {cfg.n_eta_bins, cfg.n_phi_bins, eta_node_counter_buf, phi_cusums_buf});
0145 
0146   vecmem::data::vector_buffer<float4> node_params_buf(nNodes, mr().main);
0147   copy().setup(node_params_buf)->ignore();
0148   vecmem::data::vector_buffer<float> node_phi_buf(nNodes, mr().main);
0149   copy().setup(node_phi_buf)->ignore();
0150   vecmem::data::vector_buffer<unsigned int> node_index_buf(nNodes, mr().main);
0151   copy().setup(node_index_buf)->ignore();
0152 
0153   // Optional tau LUT consumed by device::gbts_sort_nodes when
0154   // cfg.gbts_sort_nodes_params.useTauLUT is set. A size-1 dummy is allocated
0155   // when the LUT is unused so the kernel always receives a valid (never-read)
0156   // view.
0157   const unsigned int tau_lut_size =
0158       std::max<unsigned int>(1u, static_cast<unsigned int>(cfg.tau_lut.size()));
0159   vecmem::data::vector_buffer<float> tau_lut_buf(tau_lut_size, mr().main);
0160   copy().setup(tau_lut_buf)->ignore();
0161   if (!cfg.tau_lut.empty()) {
0162     copy()(vecmem::get_data(cfg.tau_lut), tau_lut_buf)->ignore();
0163   }
0164 
0165   gbts_sort_nodes_kernel({nNodes, cfg.n_phi_bins, sp_params_buf,
0166                           node_eta_index_buf, node_phi_index_buf,
0167                           phi_cusums_buf, node_params_buf, node_phi_buf,
0168                           node_index_buf, original_sp_idx_buf, tau_lut_buf,
0169                           cfg.gbts_sort_nodes_params});
0170 
0171   vecmem::data::vector_buffer<unsigned int> eta_bin_views_buf(
0172       2 * cfg.n_eta_bins, mr().main);
0173   copy().setup(eta_bin_views_buf)->ignore();
0174   copy()(vecmem::get_data(eta_bin_views), eta_bin_views_buf)->ignore();
0175 
0176   vecmem::data::vector_buffer<float> bin_rads_buf(2 * cfg.n_eta_bins,
0177                                                   mr().main);
0178   copy().setup(bin_rads_buf)->ignore();
0179 
0180   gbts_find_minmax_radius_kernel(
0181       {cfg.n_eta_bins, eta_bin_views_buf, node_params_buf, bin_rads_buf});
0182 
0183   vecmem::vector<float> bin_rads(2 * cfg.n_eta_bins, mr().host);
0184   copy()(vecmem::get_data(bin_rads_buf), bin_rads)->wait();
0185 
0186   return node_making_output{std::move(reducedSP_buf),
0187                             std::move(node_params_buf),
0188                             std::move(node_phi_buf),
0189                             std::move(node_index_buf),
0190                             std::move(bin_rads),
0191                             std::move(eta_bin_views),
0192                             nNodes};
0193 }
0194 
0195 // Stage 2:
0196 // Find edges between compatible nodes
0197 // The main output is a graph in
0198 // the form of an edge list (array of node index pairs)
0199 // and an accompanying array of edge parameters
0200 // (exp(-eta), curvature, extrapolated phi at node1, extrapolated phi at node2).
0201 auto gbts_seeding_algorithm::create_edges(
0202     vecmem::data::vector_buffer<float4> node_params,
0203     vecmem::data::vector_buffer<float> node_phi,
0204     vecmem::data::vector_buffer<unsigned int> node_index,
0205     const vecmem::vector<float>& bin_rads,
0206     const vecmem::vector<unsigned int>& eta_bin_views,
0207     const unsigned int nNodes,
0208     vecmem::data::vector_buffer<unsigned int>& counters_buf,
0209     vecmem::vector<unsigned int>& h_counters) const -> graph_making_output {
0210   const gbts_seedfinder_config& cfg = m_config;
0211   unsigned int* d_counters = counters_buf.ptr();
0212 
0213   // CPU: build the per-bin-pair work list (begin/end node ranges + phi search
0214   // window) on the host from the eta-bin views, splitting large bins into
0215   // node_buffer_length-sized chunks. Two passes: count then fill.
0216   unsigned int nBinPairs = 0;
0217   for (const std::pair<unsigned int, unsigned int>& binPair : cfg.binTables) {
0218     const unsigned int bin1_begin = eta_bin_views[2 * binPair.first];
0219     const unsigned int bin1_end = eta_bin_views[2 * binPair.first + 1];
0220     unsigned int nNodesInBin1 = bin1_end - bin1_begin;
0221     if (bin1_begin > bin1_end) {
0222       nNodesInBin1 = bin1_begin - bin1_end;
0223     }
0224     nBinPairs += 1 + (nNodesInBin1 - 1) / gbts_consts::node_buffer_length;
0225   }
0226 
0227   vecmem::vector<unsigned int> bin_pair_views(4 * nBinPairs, mr().host);
0228   vecmem::vector<float> bin_pair_dphi(nBinPairs, mr().host);
0229 
0230   unsigned int pairIdx = 0;
0231   for (const std::pair<unsigned int, unsigned int>& binPair : cfg.binTables) {
0232     const float rb1 = bin_rads[2 * binPair.first];
0233 
0234     const unsigned int begin_bin1 = eta_bin_views[2 * binPair.first];
0235     const unsigned int end_bin1 = eta_bin_views[2 * binPair.first + 1];
0236     if (begin_bin1 == end_bin1) {
0237       continue;
0238     }
0239     if (eta_bin_views[2 * binPair.second] ==
0240         eta_bin_views[2 * binPair.second + 1]) {
0241       continue;
0242     }
0243 
0244     const float rb2 = bin_rads[2 * binPair.second + 1];
0245     const float maxDeltaR = std::fabs(rb2 - rb1);
0246 
0247     float deltaPhi = cfg.gbts_dphi_window_params.min_delta_phi +
0248                      cfg.gbts_dphi_window_params.dphi_coeff * maxDeltaR;
0249     if (maxDeltaR < cfg.gbts_dphi_window_params.low_dr_threshold) {
0250       deltaPhi = cfg.gbts_dphi_window_params.min_delta_phi_low_dr +
0251                  cfg.gbts_dphi_window_params.dphi_coeff_low_dr * maxDeltaR;
0252     }
0253 
0254     unsigned int currBegin_bin1 = begin_bin1;
0255     unsigned int currEnd_bin1 =
0256         end_bin1 < gbts_consts::node_buffer_length
0257             ? end_bin1
0258             : begin_bin1 + gbts_consts::node_buffer_length;
0259 
0260     for (; currEnd_bin1 < end_bin1;
0261          currEnd_bin1 += gbts_consts::node_buffer_length, pairIdx++) {
0262       const unsigned int offset = 4 * pairIdx;
0263       bin_pair_views[offset] = currBegin_bin1;
0264       bin_pair_views[1 + offset] = currEnd_bin1;
0265       bin_pair_views[2 + offset] = eta_bin_views[2 * binPair.second];
0266       bin_pair_views[3 + offset] = eta_bin_views[2 * binPair.second + 1];
0267       bin_pair_dphi[pairIdx] = deltaPhi;
0268       currBegin_bin1 = currEnd_bin1;
0269     }
0270     currEnd_bin1 = end_bin1;
0271 
0272     const unsigned int offset = 4 * pairIdx;
0273     bin_pair_views[offset] = currBegin_bin1;
0274     bin_pair_views[1 + offset] = currEnd_bin1;
0275     bin_pair_views[2 + offset] = eta_bin_views[2 * binPair.second];
0276     bin_pair_views[3 + offset] = eta_bin_views[2 * binPair.second + 1];
0277     bin_pair_dphi[pairIdx] = deltaPhi;
0278     pairIdx++;
0279   }
0280   const unsigned int nUsedBinPairs = pairIdx;
0281   TRACCC_DEBUG("nUsedBinPairs " << nUsedBinPairs);
0282   if (nUsedBinPairs == 0) {
0283     TRACCC_WARNING("No bin pairs were used for edge finding");
0284     return graph_making_output{};
0285   }
0286 
0287   vecmem::data::vector_buffer<unsigned int> bin_pair_views_buf(
0288       4 * nUsedBinPairs, mr().main);
0289   copy().setup(bin_pair_views_buf)->ignore();
0290   copy()(vecmem::get_data(bin_pair_views), bin_pair_views_buf)->ignore();
0291 
0292   vecmem::data::vector_buffer<float> bin_pair_dphi_buf(nUsedBinPairs,
0293                                                        mr().main);
0294   copy().setup(bin_pair_dphi_buf)->ignore();
0295   copy()(vecmem::get_data(bin_pair_dphi), bin_pair_dphi_buf)->ignore();
0296 
0297   // 2. Find edges between spacepoint pairs.
0298   const unsigned int nMaxEdges = cfg.max_edges_factor * nNodes;
0299   // Packed per-edge parameter buffer ([exp(-eta), curv, phi_z, phi_w]).
0300   vecmem::data::vector_buffer<float4> edge_params_buf(nMaxEdges, mr().main);
0301   copy().setup(edge_params_buf)->ignore();
0302   vecmem::data::vector_buffer<uint2> edge_nodes_buf(nMaxEdges, mr().main);
0303   copy().setup(edge_nodes_buf)->ignore();
0304   vecmem::data::vector_buffer<unsigned int> num_incoming_edges_buf(nNodes + 1,
0305                                                                    mr().main);
0306   copy().setup(num_incoming_edges_buf)->ignore();
0307   copy().memset(num_incoming_edges_buf, 0)->ignore();
0308 
0309   gbts_make_graph_edges_kernel(
0310       {nUsedBinPairs, nMaxEdges, cfg.n_phi_bins, bin_pair_views_buf,
0311        bin_pair_dphi_buf, node_params, node_phi,
0312        cfg.gbts_make_graph_edges_params, d_counters + gbts_counter::nEdges,
0313        edge_nodes_buf, edge_params_buf, num_incoming_edges_buf});
0314 
0315   // Read back the number of edges produced.
0316   copy()(counters_buf, h_counters)->wait();
0317 
0318   unsigned int nEdges = h_counters[gbts_counter::nEdges];
0319   TRACCC_DEBUG("Created " << nEdges << " edges with a cap of " << nMaxEdges);
0320   if (nEdges > nMaxEdges) {
0321     TRACCC_WARNING("Number of edges exceeds the maximum allowed, Removing "
0322                    << nEdges - nMaxEdges << " edges");
0323     nEdges = nMaxEdges;
0324   } else if (nEdges == 0) {
0325     TRACCC_WARNING("No edges were found");
0326     return graph_making_output{};
0327   }
0328 
0329   // 3. Link edges and nodes.
0330   vecmem::data::vector_buffer<unsigned int> edge_links_buf(nEdges, mr().main);
0331   copy().setup(edge_links_buf)->ignore();
0332 
0333   gbts_link_graph_edges_kernel(
0334       {nEdges, edge_nodes_buf, edge_links_buf, num_incoming_edges_buf});
0335 
0336   // 4. Edge matching to create edge-to-edge connections.
0337   vecmem::data::vector_buffer<unsigned char> num_neighbours_buf(nEdges,
0338                                                                 mr().main);
0339   copy().setup(num_neighbours_buf)->ignore();
0340   copy().memset(num_neighbours_buf, 0)->ignore();
0341 
0342   vecmem::data::vector_buffer<int> reIndexer_buf(nEdges, mr().main);
0343   copy().setup(reIndexer_buf)->ignore();
0344   // Byte-fill 0xFF -> int -1, the "edge not kept" sentinel checked by
0345   // gbts_reindex_edges / gbts_compress_graph.
0346   copy().memset(reIndexer_buf, 0xFF)->ignore();
0347 
0348   vecmem::data::vector_buffer<unsigned int> neighbours_buf(
0349       cfg.max_num_neighbours * nEdges, mr().main);
0350   copy().setup(neighbours_buf)->ignore();
0351   copy().memset(neighbours_buf, 0)->ignore();
0352 
0353   gbts_match_graph_edges_kernel(
0354       {nEdges, cfg.max_num_neighbours, cfg.gbts_match_graph_edges_params,
0355        edge_params_buf, edge_nodes_buf, num_incoming_edges_buf, edge_links_buf,
0356        num_neighbours_buf, neighbours_buf, reIndexer_buf,
0357        d_counters + gbts_counter::nConnections});
0358 
0359   // 5. Edge re-indexing to keep only edges involved in any connection.
0360   gbts_reindex_edges_kernel(
0361       {nEdges, reIndexer_buf, d_counters + gbts_counter::nConnectedEdges});
0362 
0363   copy()(counters_buf, h_counters)->wait();
0364 
0365   const unsigned int nConnections = h_counters[gbts_counter::nConnections];
0366   const unsigned int nConnectedEdges =
0367       h_counters[gbts_counter::nConnectedEdges];
0368   TRACCC_DEBUG("created " << nConnections << " edge links, found "
0369                           << nConnectedEdges
0370                           << " connected edges for seed extraction");
0371   if (nConnectedEdges == 0) {
0372     TRACCC_WARNING("No connected edges were found");
0373     return graph_making_output{};
0374   }
0375 
0376   const unsigned int nIntsPerEdge = 2 + 1 + cfg.max_num_neighbours;
0377   vecmem::data::vector_buffer<unsigned int> output_graph_buf(
0378       nConnectedEdges * nIntsPerEdge, mr().main);
0379   copy().setup(output_graph_buf)->ignore();
0380 
0381   gbts_compress_graph_kernel({nEdges, cfg.max_num_neighbours, node_index,
0382                               edge_nodes_buf, num_neighbours_buf,
0383                               neighbours_buf, reIndexer_buf, output_graph_buf});
0384 
0385   return graph_making_output{std::move(output_graph_buf), nConnectedEdges};
0386 }
0387 
0388 // Stage 3:
0389 // Find seed candidates as long chains of connected edges using a CCA
0390 // Then fit the potential seeds (eta, phi, curvature).
0391 // Finally, disambiguate them by repeated seed-vs-edge bidding rounds.
0392 auto gbts_seeding_algorithm::extract_seeds(
0393     vecmem::data::vector_buffer<unsigned int>& output_graph,
0394     vecmem::data::vector_buffer<float4>& reducedSP,
0395     const unsigned int nConnectedEdges, const unsigned int nSp,
0396     vecmem::data::vector_buffer<unsigned int>& counters_buf,
0397     vecmem::vector<unsigned int>& h_counters) const
0398     -> edm::seed_collection::buffer {
0399   const gbts_seedfinder_config& cfg = m_config;
0400   unsigned int* d_counters = counters_buf.ptr();
0401 
0402   // 6. Find longest segments with CCA.
0403   // active_edges is the per-edge "next iter index" flag: it holds `iter`
0404   // while the edge is active in iteration `iter`, and -1 once it settles.
0405   // Iteration 0 writes every entry before any later iteration reads it, so
0406   // no initialisation is required.
0407   vecmem::data::vector_buffer<char> active_edges_buf(nConnectedEdges,
0408                                                      mr().main);
0409   copy().setup(active_edges_buf)->ignore();
0410 
0411   vecmem::data::vector_buffer<unsigned char> levels_buf(2 * nConnectedEdges,
0412                                                         mr().main);
0413   copy().setup(levels_buf)->ignore();
0414   // Initialise to 1 so a level counts the maximum number of edge segments
0415   // for a seed originating at the edge.
0416   copy().memset(levels_buf, 0x1)->ignore();
0417 
0418   vecmem::data::vector_buffer<short2> outgoing_paths_buf(nConnectedEdges,
0419                                                          mr().main);
0420   copy().setup(outgoing_paths_buf)->ignore();
0421 
0422   for (unsigned char iter = 0; iter < traccc::device::gbts_consts::max_cca_iter;
0423        ++iter) {
0424     gbts_run_cca_iteration_kernel({nConnectedEdges, cfg.max_num_neighbours,
0425                                    cfg.minLevel, output_graph, levels_buf,
0426                                    active_edges_buf, outgoing_paths_buf, iter});
0427   }
0428 
0429   gbts_count_terminus_edges_kernel({nConnectedEdges, outgoing_paths_buf,
0430                                     d_counters + gbts_counter::nPaths,
0431                                     d_counters + gbts_counter::nTerminusEdges});
0432 
0433   copy()(counters_buf, h_counters)->wait();
0434 
0435   const unsigned int nPaths = h_counters[gbts_counter::nPaths];
0436   const unsigned int nTerminusEdges = h_counters[gbts_counter::nTerminusEdges];
0437   if (nTerminusEdges == 0) {
0438     TRACCC_WARNING("No terminus edges were found");
0439     return {0, mr().main};
0440   }
0441 
0442   TRACCC_DEBUG(nPaths << " size of path store | nTerminusEdges "
0443                       << nTerminusEdges);
0444 
0445   vecmem::data::vector_buffer<int2> path_store_buf(nPaths + nTerminusEdges,
0446                                                    mr().main);
0447   copy().setup(path_store_buf)->ignore();
0448   vecmem::data::vector_buffer<int2> seed_proposals_buf(nPaths, mr().main);
0449   copy().setup(seed_proposals_buf)->ignore();
0450   vecmem::data::vector_buffer<char> seed_ambiguity_buf(nPaths, mr().main);
0451   copy().setup(seed_ambiguity_buf)->ignore();
0452 
0453   vecmem::data::vector_buffer<unsigned long long int> edge_bids_buf(
0454       nConnectedEdges, mr().main);
0455   copy().setup(edge_bids_buf)->ignore();
0456   copy().memset(edge_bids_buf, 0)->ignore();
0457 
0458   gbts_add_terminus_to_path_store_kernel(
0459       {nConnectedEdges, path_store_buf, outgoing_paths_buf});
0460 
0461   gbts_fill_path_store_kernel({nTerminusEdges, cfg.max_num_neighbours, nPaths,
0462                                path_store_buf, output_graph, levels_buf,
0463                                d_counters + gbts_counter::nTerminusEdges});
0464 
0465   gbts_fit_segments_kernel(
0466       {nPaths, nTerminusEdges, cfg.max_num_neighbours, cfg.minLevel, reducedSP,
0467        output_graph, path_store_buf, seed_proposals_buf, edge_bids_buf,
0468        seed_ambiguity_buf, d_counters + gbts_counter::nTerminusEdges,
0469        d_counters + gbts_counter::nProps, cfg.gbts_fit_segments_params,
0470        cfg.gbts_make_graph_edges_params.max_z0});
0471 
0472   copy()(counters_buf, h_counters)->wait();
0473 
0474   const unsigned int nProps = h_counters[gbts_counter::nProps];
0475   TRACCC_DEBUG("nProps " << nProps);
0476   if (nProps == 0) {
0477     TRACCC_WARNING("No seed proposals were found");
0478     return {0, mr().main};
0479   }
0480 
0481   // 7. Disambiguate seeds through repeated seed-vs-edge bidding rounds.
0482   for (unsigned int round = 0; round < cfg.edge_bidding_rounds; ++round) {
0483     copy().memset(edge_bids_buf, 0)->ignore();
0484 
0485     gbts_rebid_seeds_for_edges_kernel(
0486         {nProps, path_store_buf, seed_proposals_buf, edge_bids_buf,
0487          seed_ambiguity_buf, d_counters + gbts_counter::nRejected,
0488          round == 0u});
0489 
0490     gbts_reset_edge_bids_kernel({nProps, path_store_buf, seed_proposals_buf,
0491                                  edge_bids_buf, seed_ambiguity_buf,
0492                                  d_counters + gbts_counter::nRejected});
0493   }
0494 
0495   copy()(counters_buf, h_counters)->wait();
0496   const unsigned int nRejectedProps = h_counters[gbts_counter::nRejected];
0497   const unsigned int nSeeds =
0498       (nRejectedProps >= nProps) ? 0u : nProps - nRejectedProps;
0499 
0500   TRACCC_DEBUG("Rejected " << nRejectedProps << " out of " << nProps
0501                            << " seed proposals");
0502   if (nSeeds == 0) {
0503     TRACCC_WARNING("All seed proposals were rejected");
0504     return {0, mr().main};
0505   }
0506 
0507   // 8. Convert to 3sp seeds and make output buffer.
0508   edm::seed_collection::buffer output_seeds(
0509       2 * nSeeds, mr().main, vecmem::data::buffer_type::resizable);
0510   copy().setup(output_seeds)->ignore();
0511 
0512   vecmem::data::vector_buffer<unsigned long long int> hit_bids_buf(nSp,
0513                                                                    mr().main);
0514   copy().setup(hit_bids_buf)->ignore();
0515   copy().memset(hit_bids_buf, 0)->ignore();
0516 
0517   const unsigned int edge_size = 1u + 2u + cfg.max_num_neighbours;
0518   gbts_bid_seeds_for_hits_kernel({nProps, nSeeds, edge_size, output_graph,
0519                                   seed_proposals_buf, path_store_buf,
0520                                   seed_ambiguity_buf, hit_bids_buf});
0521 
0522   gbts_convert_seeds_kernel(
0523       {nProps, nSeeds, cfg.max_num_neighbours, seed_proposals_buf,
0524        seed_ambiguity_buf, path_store_buf, output_graph, reducedSP,
0525        output_seeds, hit_bids_buf, cfg.gbts_convert_seeds_params});
0526 
0527   const unsigned int outputSeeds = copy().get_size(output_seeds);
0528   TRACCC_DEBUG("GBTS found " << outputSeeds << " seeds");
0529   return output_seeds;
0530 }
0531 
0532 gbts_seeding_algorithm::gbts_seeding_algorithm(
0533     const gbts_seedfinder_config& cfg, const memory_resource& mr,
0534     const vecmem::copy& copy, std::unique_ptr<const Logger> logger)
0535     : messaging(std::move(logger)), algorithm_base{mr, copy}, m_config{cfg} {}
0536 
0537 auto gbts_seeding_algorithm::operator()(
0538     const edm::spacepoint_collection::const_view& spacepoints,
0539     const edm::measurement_collection::const_view& measurements) const
0540     -> output_type {
0541   const unsigned int nSp = copy().get_size(spacepoints);
0542   TRACCC_DEBUG("nSp " << nSp);
0543   if (nSp == 0) {
0544     TRACCC_WARNING("No spacepoints were found in the event");
0545     return {0, mr().main};
0546   }
0547 
0548   // Stage 1: bin spacepoints and create nodes with the parameters (eta, phi,
0549   // r, z).
0550   node_making_output nodes = make_nodes(spacepoints, measurements);
0551   if (nodes.nNodes == 0) {
0552     // No nodes survived spacepoint counting -> no seeds.
0553     return {0, mr().main};
0554   }
0555 
0556   // Named counters shared by the graph-making and seed-extraction stages.
0557   vecmem::data::vector_buffer<unsigned int> counters_buf(
0558       gbts_counter::nCounters, mr().main);
0559   copy().setup(counters_buf)->ignore();
0560   copy().memset(counters_buf, 0)->ignore();
0561   vecmem::vector<unsigned int> h_counters(gbts_counter::nCounters,
0562                                           mr().host ? mr().host : &(mr().main));
0563 
0564   // Stage 2: graph. The per-node buffers are moved in so they are released
0565   // when create_gbts_edges_from_nodes returns, along with all the edge/link
0566   // transients.
0567   graph_making_output graph =
0568       create_edges(std::move(nodes.node_params), std::move(nodes.node_phi),
0569                    std::move(nodes.node_index), nodes.bin_rads,
0570                    nodes.eta_bin_views, nodes.nNodes, counters_buf, h_counters);
0571   if (graph.nConnectedEdges == 0) {
0572     // No connected edges survived graph making -> no seeds.
0573     return {0, mr().main};
0574   }
0575 
0576   // Stage 3: Create seeds from the graph edges.
0577   return extract_seeds(graph.output_graph, nodes.reducedSP,
0578                        graph.nConnectedEdges, nSp, counters_buf, h_counters);
0579 }
0580 
0581 }  // namespace traccc::device