@@ -1132,37 +1132,74 @@ struct lambdaspincorrderived {
11321132 if (ptB < 0 || etaB < 0 || phiB < 0 || mB < 0 )
11331133 continue ;
11341134
1135- // Collect partners from nominal key, plus wrapped neighbor only for φ-edge bins
11361135 std::vector<MatchRef> matches;
1137- matches.reserve (128 ); // or keep binVec.size() if you prefer
1136+ const int maxKeep = maxMatchesPerPair.value ; // default 25
1137+ matches.reserve (std::max (64 , maxKeep > 0 ? maxKeep : 64 ));
1138+
11381139 const int64_t curColIdx = static_cast <int64_t >(collision1.index ());
1140+ std::unordered_set<int64_t > seenRow;
1141+ seenRow.reserve (static_cast <size_t >(std::max (256 , 4 * (maxKeep > 0 ? maxKeep : 64 ))));
11391142
1140- auto collectFrom = [&](int phiBinUse) {
1141- const size_t keyUse = linearKey (colBin, status, ptB, etaB, phiBinUse, mB ,
1143+ auto collectFrom = [&](int ptUse, int etaUse, int phiUse) {
1144+ if (maxKeep > 0 && static_cast <int >(matches.size ()) >= maxKeep) {
1145+ return ; // early stop
1146+ }
1147+
1148+ const size_t keyUse = linearKey (colBin, status, ptUse, etaUse, phiUse, mB ,
11421149 nStat, nPt, nEta, nPhi, nM);
11431150 auto const & vec = buffer[keyUse];
1151+
11441152 for (const auto & bc : vec) {
1153+ if (maxKeep > 0 && static_cast <int >(matches.size ()) >= maxKeep) {
1154+ break ;
1155+ }
11451156 if (bc.collisionIdx == curColIdx) {
11461157 continue ; // must be from different event
11471158 }
1159+
1160+ // dedupe first
1161+ if (!seenRow.insert (bc.rowIndex ).second ) {
1162+ continue ;
1163+ }
1164+
11481165 auto tX = V0s.iteratorAt (static_cast <uint64_t >(bc.rowIndex ));
11491166 if (!selectionV0 (tX)) {
11501167 continue ;
11511168 }
11521169 if (!checkKinematics (t1, tX)) {
11531170 continue ;
11541171 }
1172+
11551173 matches.push_back (MatchRef{bc.collisionIdx , bc.rowIndex });
11561174 }
11571175 };
11581176 // 1) nominal φ-bin
11591177 collectFrom (phiB);
11601178
1161- // 2) wrap only at boundaries: 0 <-> nPhi-1
1162- if (phiB == 0 ) {
1163- collectFrom (nPhi - 1 );
1164- } else if (phiB == nPhi - 1 ) {
1165- collectFrom (0 );
1179+ // scan pt±1, eta±1, phi±1 (wrapped)
1180+ for (int dpt = -1 ; dpt <= 1 ; ++dpt) {
1181+ const int ptUse = ptB + dpt;
1182+ if (ptUse < 0 || ptUse >= nPt) {
1183+ continue ;
1184+ }
1185+ for (int deta = -1 ; deta <= 1 ; ++deta) {
1186+ const int etaUse = etaB + deta;
1187+ if (etaUse < 0 || etaUse >= nEta) {
1188+ continue ;
1189+ }
1190+ for (int phiUse : phiBins) {
1191+ collectFrom (ptUse, etaUse, phiUse);
1192+ if (maxKeep > 0 && static_cast <int >(matches.size ()) >= maxKeep) {
1193+ break ;
1194+ }
1195+ }
1196+ if (maxKeep > 0 && static_cast <int >(matches.size ()) >= maxKeep) {
1197+ break ;
1198+ }
1199+ }
1200+ if (maxKeep > 0 && static_cast <int >(matches.size ()) >= maxKeep) {
1201+ break ;
1202+ }
11661203 }
11671204
11681205 if (matches.empty ()) {
@@ -1455,6 +1492,7 @@ struct lambdaspincorrderived {
14551492
14561493 // enable it
14571494 PROCESS_SWITCH (lambdaspincorrderived, processMCMEV3, " Process MC ME (MEV3)" , false );
1495+
14581496 // -----------------------------------------------------
14591497 // 5) MC Event Mixing using your MEV4 6D-buffer approach
14601498 // -----------------------------------------------------
0 commit comments