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