@@ -1215,37 +1215,74 @@ struct lambdaspincorrderived {
12151215 if (ptB < 0 || etaB < 0 || phiB < 0 || mB < 0 )
12161216 continue ;
12171217
1218- // Collect partners from nominal key, plus wrapped neighbor only for φ-edge bins
12191218 std::vector<MatchRef> matches;
1220- matches.reserve (128 ); // or keep binVec.size() if you prefer
1219+ const int maxKeep = maxMatchesPerPair.value ; // default 25
1220+ matches.reserve (std::max (64 , maxKeep > 0 ? maxKeep : 64 ));
1221+
12211222 const int64_t curColIdx = static_cast <int64_t >(collision1.index ());
1223+ std::unordered_set<int64_t > seenRow;
1224+ seenRow.reserve (static_cast <size_t >(std::max (256 , 4 * (maxKeep > 0 ? maxKeep : 64 ))));
12221225
1223- auto collectFrom = [&](int phiBinUse) {
1224- const size_t keyUse = linearKey (colBin, status, ptB, etaB, phiBinUse, mB ,
1226+ auto collectFrom = [&](int ptUse, int etaUse, int phiUse) {
1227+ if (maxKeep > 0 && static_cast <int >(matches.size ()) >= maxKeep) {
1228+ return ; // early stop
1229+ }
1230+
1231+ const size_t keyUse = linearKey (colBin, status, ptUse, etaUse, phiUse, mB ,
12251232 nStat, nPt, nEta, nPhi, nM);
12261233 auto const & vec = buffer[keyUse];
1234+
12271235 for (const auto & bc : vec) {
1236+ if (maxKeep > 0 && static_cast <int >(matches.size ()) >= maxKeep) {
1237+ break ;
1238+ }
12281239 if (bc.collisionIdx == curColIdx) {
12291240 continue ; // must be from different event
12301241 }
1242+
1243+ // dedupe first
1244+ if (!seenRow.insert (bc.rowIndex ).second ) {
1245+ continue ;
1246+ }
1247+
12311248 auto tX = V0s.iteratorAt (static_cast <uint64_t >(bc.rowIndex ));
12321249 if (!selectionV0 (tX)) {
12331250 continue ;
12341251 }
12351252 if (!checkKinematics (t1, tX)) {
12361253 continue ;
12371254 }
1255+
12381256 matches.push_back (MatchRef{bc.collisionIdx , bc.rowIndex });
12391257 }
12401258 };
12411259 // 1) nominal φ-bin
12421260 collectFrom (phiB);
12431261
1244- // 2) wrap only at boundaries: 0 <-> nPhi-1
1245- if (phiB == 0 ) {
1246- collectFrom (nPhi - 1 );
1247- } else if (phiB == nPhi - 1 ) {
1248- collectFrom (0 );
1262+ // scan pt±1, eta±1, phi±1 (wrapped)
1263+ for (int dpt = -1 ; dpt <= 1 ; ++dpt) {
1264+ const int ptUse = ptB + dpt;
1265+ if (ptUse < 0 || ptUse >= nPt) {
1266+ continue ;
1267+ }
1268+ for (int deta = -1 ; deta <= 1 ; ++deta) {
1269+ const int etaUse = etaB + deta;
1270+ if (etaUse < 0 || etaUse >= nEta) {
1271+ continue ;
1272+ }
1273+ for (int phiUse : phiBins) {
1274+ collectFrom (ptUse, etaUse, phiUse);
1275+ if (maxKeep > 0 && static_cast <int >(matches.size ()) >= maxKeep) {
1276+ break ;
1277+ }
1278+ }
1279+ if (maxKeep > 0 && static_cast <int >(matches.size ()) >= maxKeep) {
1280+ break ;
1281+ }
1282+ }
1283+ if (maxKeep > 0 && static_cast <int >(matches.size ()) >= maxKeep) {
1284+ break ;
1285+ }
12491286 }
12501287
12511288 if (matches.empty ()) {
0 commit comments