@@ -1191,37 +1191,74 @@ struct lambdaspincorrderived {
11911191 if (ptB < 0 || etaB < 0 || phiB < 0 || mB < 0 )
11921192 continue ;
11931193
1194- // Collect partners from nominal key, plus wrapped neighbor only for φ-edge bins
11951194 std::vector<MatchRef> matches;
1196- matches.reserve (128 ); // or keep binVec.size() if you prefer
1195+ const int maxKeep = maxMatchesPerPair.value ; // default 25
1196+ matches.reserve (std::max (64 , maxKeep > 0 ? maxKeep : 64 ));
1197+
11971198 const int64_t curColIdx = static_cast <int64_t >(collision1.index ());
1199+ std::unordered_set<int64_t > seenRow;
1200+ seenRow.reserve (static_cast <size_t >(std::max (256 , 4 * (maxKeep > 0 ? maxKeep : 64 ))));
11981201
1199- auto collectFrom = [&](int phiBinUse) {
1200- const size_t keyUse = linearKey (colBin, status, ptB, etaB, phiBinUse, mB ,
1202+ auto collectFrom = [&](int ptUse, int etaUse, int phiUse) {
1203+ if (maxKeep > 0 && static_cast <int >(matches.size ()) >= maxKeep) {
1204+ return ; // early stop
1205+ }
1206+
1207+ const size_t keyUse = linearKey (colBin, status, ptUse, etaUse, phiUse, mB ,
12011208 nStat, nPt, nEta, nPhi, nM);
12021209 auto const & vec = buffer[keyUse];
1210+
12031211 for (const auto & bc : vec) {
1212+ if (maxKeep > 0 && static_cast <int >(matches.size ()) >= maxKeep) {
1213+ break ;
1214+ }
12041215 if (bc.collisionIdx == curColIdx) {
12051216 continue ; // must be from different event
12061217 }
1218+
1219+ // dedupe first
1220+ if (!seenRow.insert (bc.rowIndex ).second ) {
1221+ continue ;
1222+ }
1223+
12071224 auto tX = V0s.iteratorAt (static_cast <uint64_t >(bc.rowIndex ));
12081225 if (!selectionV0 (tX)) {
12091226 continue ;
12101227 }
12111228 if (!checkKinematics (t1, tX)) {
12121229 continue ;
12131230 }
1231+
12141232 matches.push_back (MatchRef{bc.collisionIdx , bc.rowIndex });
12151233 }
12161234 };
12171235 // 1) nominal φ-bin
12181236 collectFrom (phiB);
12191237
1220- // 2) wrap only at boundaries: 0 <-> nPhi-1
1221- if (phiB == 0 ) {
1222- collectFrom (nPhi - 1 );
1223- } else if (phiB == nPhi - 1 ) {
1224- collectFrom (0 );
1238+ // scan pt±1, eta±1, phi±1 (wrapped)
1239+ for (int dpt = -1 ; dpt <= 1 ; ++dpt) {
1240+ const int ptUse = ptB + dpt;
1241+ if (ptUse < 0 || ptUse >= nPt) {
1242+ continue ;
1243+ }
1244+ for (int deta = -1 ; deta <= 1 ; ++deta) {
1245+ const int etaUse = etaB + deta;
1246+ if (etaUse < 0 || etaUse >= nEta) {
1247+ continue ;
1248+ }
1249+ for (int phiUse : phiBins) {
1250+ collectFrom (ptUse, etaUse, phiUse);
1251+ if (maxKeep > 0 && static_cast <int >(matches.size ()) >= maxKeep) {
1252+ break ;
1253+ }
1254+ }
1255+ if (maxKeep > 0 && static_cast <int >(matches.size ()) >= maxKeep) {
1256+ break ;
1257+ }
1258+ }
1259+ if (maxKeep > 0 && static_cast <int >(matches.size ()) >= maxKeep) {
1260+ break ;
1261+ }
12251262 }
12261263
12271264 if (matches.empty ()) {
0 commit comments