@@ -55,6 +55,18 @@ static const char *findIndexBranchName(TTree *t) {
5555 return nullptr ;
5656}
5757
58+ static const char * findMcCollisionIndexBranchName (TTree * t ) {
59+ if (!t )
60+ return nullptr ;
61+ if (t -> GetBranch ("fIndexMcCollisions" ))
62+ return "fIndexMcCollisions" ;
63+ return nullptr ;
64+ }
65+
66+ static inline bool isMcCollisionTree (const char * tname ) {
67+ return TString (tname ).BeginsWith ("O2mccollision" );
68+ }
69+
5870// Scalar type tag
5971enum class ScalarTag {
6072 kInt ,
@@ -336,6 +348,10 @@ struct BCMaps {
336348 std ::vector < Int_t > indexMap ;
337349 std ::vector < ULong64_t > uniqueBCs ;
338350 std ::unordered_map < size_t , std ::vector < size_t >> newIndexOrigins ;
351+
352+ // McCollision scheme (populated when O2mccollision is sorted) during first stage
353+ std ::vector < Long64_t > mcOldEntries ;
354+ std ::vector < Long64_t > mcNewEntries ;
339355};
340356
341357static BCMaps buildBCMaps (TTree * treeBCs ) {
@@ -543,7 +559,7 @@ static bool isVLA(TBranch *br) {
543559// This is the VLA-aware rewritePayloadSorted implementation (keeps previous
544560// tested behavior)
545561static void rewritePayloadSorted (TDirectory * dirIn , TDirectory * dirOut ,
546- const BCMaps & maps ) {
562+ BCMaps & maps ) {
547563 std ::unordered_set < std ::string > skipNames ; // for count branches
548564 TIter it (dirIn -> GetListOfKeys ());
549565 while (TKey * k = (TKey * )it ()) {
@@ -562,6 +578,13 @@ static void rewritePayloadSorted(TDirectory *dirIn, TDirectory *dirOut,
562578
563579 const char * idxName = findIndexBranchName (src );
564580 if (!idxName ) {
581+ // Tables indexed by McCollisions (not BCs) are forwarded to the second
582+ // stage where the sorting scheme is available.
583+ if (findMcCollisionIndexBranchName (src )) {
584+ std ::cout << " [forward] " << tname
585+ << " (McCollision-indexed) -> second stage\n" ;
586+ continue ;
587+ }
565588 dirOut -> cd ();
566589 std ::cout << " [copy] " << tname << " (no index) -> cloning\n" ;
567590 TTree * c = src -> CloneTree (-1 , "fast" );
@@ -649,6 +672,18 @@ static void rewritePayloadSorted(TDirectory *dirIn, TDirectory *dirOut,
649672 return a .entry < b .entry ;
650673 });
651674
675+ // If this is the McCollision tree, record the sort permutation so that
676+ // tables indexed by McCollisions (fIndexMcCollisions) can be reordered consistently
677+ if (isMcCollisionTree (tname )) {
678+ maps .mcOldEntries .resize (keys .size ());
679+ maps .mcNewEntries .assign (nEnt , -1 );
680+ for (Long64_t j = 0 ; j < (Long64_t )keys .size (); ++ j ) {
681+ maps .mcOldEntries [j ] = keys [j ].entry ;
682+ if (keys [j ].entry >= 0 )
683+ maps .mcNewEntries [keys [j ].entry ] = j ;
684+ }
685+ }
686+
652687 // prepare output tree
653688 dirOut -> cd ();
654689 TTree * out = src -> CloneTree (0 , "fast" );
@@ -889,6 +924,133 @@ static void rewritePayloadSorted(TDirectory *dirIn, TDirectory *dirOut,
889924 out -> Write ();
890925 } // end while keys in dir
891926
927+ // ---- second stage: tables indexed by McCollisions using fIndexMcCollisions ----
928+ if (!maps .mcNewEntries .empty ()) {
929+ TIter it2 (dirIn -> GetListOfKeys ());
930+ while (TKey * k2 = (TKey * )it2 ()) {
931+ if (TString (k2 -> GetClassName ()) != "TTree" )
932+ continue ;
933+ std ::unique_ptr < TObject > holder2 (k2 -> ReadObj ());
934+ TTree * src2 = dynamic_cast < TTree * > (holder2 .get ());
935+ if (!src2 )
936+ continue ;
937+ const char * tname2 = src2 -> GetName ();
938+ if (isBCtree (tname2 ) || isFlagsTree (tname2 ))
939+ continue ;
940+ if (findIndexBranchName (src2 ))
941+ continue ; // handled in first stage
942+ const char * mcIdxName = findMcCollisionIndexBranchName (src2 );
943+ if (!mcIdxName ) {
944+ // No BC index and no McCollision index → already handled (copied) earlier
945+ continue ;
946+ }
947+
948+ std ::cout << " [proc] reindex+SORT " << tname2
949+ << " (McCollision index=" << mcIdxName << ")\n" ;
950+
951+ TBranch * inMcIdxBr = src2 -> GetBranch (mcIdxName );
952+ if (!inMcIdxBr ) {
953+ std ::cerr << " ERR no McCollision index branch\n" ;
954+ continue ;
955+ }
956+ Int_t oldMcI = 0 , newMcI = 0 ;
957+ inMcIdxBr -> SetAddress (& oldMcI );
958+
959+ // Build sort keys: sort by new McCollision position.
960+ Long64_t nEnt2 = src2 -> GetEntries ();
961+ std ::vector < SortKey > keys2 ;
962+ keys2 .reserve (nEnt2 );
963+ for (Long64_t i = 0 ; i < nEnt2 ; ++ i ) {
964+ inMcIdxBr -> GetEntry (i );
965+ Long64_t newMcPos = -1 ;
966+ if (oldMcI >= 0 &&
967+ (size_t )oldMcI < maps .mcNewEntries .size ())
968+ newMcPos = maps .mcNewEntries [(size_t )oldMcI ];
969+ keys2 .push_back ({i , newMcPos });
970+ }
971+ std ::stable_sort (keys2 .begin (), keys2 .end (),
972+ [](const SortKey & a , const SortKey & b ) {
973+ bool ai = (a .newBC < 0 ), bi = (b .newBC < 0 );
974+ if (ai != bi )
975+ return !ai && bi ;
976+ if (a .newBC != b .newBC )
977+ return a .newBC < b .newBC ;
978+ return a .entry < b .entry ;
979+ });
980+
981+ dirOut -> cd ();
982+ TTree * out2 = src2 -> CloneTree (0 , "fast" );
983+
984+ std ::unordered_map < std ::string , TBranch * > inBrs2 , outBrs2 ;
985+ for (auto * b : * src2 -> GetListOfBranches ())
986+ inBrs2 [((TBranch * )b )-> GetName ()] = (TBranch * )b ;
987+ for (auto * b : * out2 -> GetListOfBranches ())
988+ outBrs2 [((TBranch * )b )-> GetName ()] = (TBranch * )b ;
989+
990+ TBranch * outMcIdxBr = out2 -> GetBranch (mcIdxName );
991+ outMcIdxBr -> SetAddress (& newMcI );
992+
993+ std ::unordered_set < std ::string > skipNames2 ;
994+ skipNames2 .insert (mcIdxName );
995+
996+ std ::vector < std ::unique_ptr < BufBase >> scalarBufs2 ;
997+ for (auto & kv : inBrs2 ) {
998+ if (skipNames2 .count (kv .first ))
999+ continue ;
1000+ TBranch * inBr = kv .second ;
1001+ TBranch * ouBr = outBrs2 .count (kv .first ) ? outBrs2 [kv .first ] : nullptr ;
1002+ if (!ouBr )
1003+ continue ;
1004+ TLeaf * leaf = (TLeaf * )inBr -> GetListOfLeaves ()-> At (0 );
1005+ if (!leaf || isVLA (inBr ))
1006+ continue ; // no variable-length arrays seen in McCollision-indexed tables (could be changed in the future)
1007+ ScalarTag tag = leafType (leaf );
1008+ if (tag == ScalarTag ::kUnknown )
1009+ continue ;
1010+ auto sb = bindScalarBranch (inBr , ouBr , tag );
1011+ if (sb )
1012+ scalarBufs2 .emplace_back (std ::move (sb ));
1013+ }
1014+
1015+ Long64_t changed2 = 0 ;
1016+ for (const auto & sk : keys2 ) {
1017+ src2 -> GetEntry (sk .entry );
1018+ Int_t prev = oldMcI ;
1019+ newMcI = (sk .newBC >= 0 ? (Int_t )sk .newBC : -1 );
1020+ if (newMcI != prev )
1021+ ++ changed2 ;
1022+ out2 -> Fill ();
1023+ }
1024+ std ::cout << " wrote " << out2 -> GetEntries ()
1025+ << " rows; remapped " << changed2
1026+ << " McCollision index values; sorted\n" ;
1027+ out2 -> Write ();
1028+ }
1029+ } else {
1030+ // No mccollision permutation available: clone deferred trees as-is
1031+ TIter it2 (dirIn -> GetListOfKeys ());
1032+ while (TKey * k2 = (TKey * )it2 ()) {
1033+ if (TString (k2 -> GetClassName ()) != "TTree" )
1034+ continue ;
1035+ std ::unique_ptr < TObject > holder2 (k2 -> ReadObj ());
1036+ TTree * src2 = dynamic_cast < TTree * > (holder2 .get ());
1037+ if (!src2 )
1038+ continue ;
1039+ if (isBCtree (src2 -> GetName ()) || isFlagsTree (src2 -> GetName ()))
1040+ continue ;
1041+ if (findIndexBranchName (src2 ))
1042+ continue ;
1043+ if (!findMcCollisionIndexBranchName (src2 ))
1044+ continue ;
1045+ std ::cerr << " [warn] no mccollision permutation for "
1046+ << src2 -> GetName () << " -> cloning as-is\n" ;
1047+ dirOut -> cd ();
1048+ TTree * c = src2 -> CloneTree (-1 , "fast" );
1049+ c -> SetDirectory (dirOut );
1050+ c -> Write ();
1051+ }
1052+ }
1053+
8921054 // non-tree objects: copy as-is (but for TMap use WriteTObject to preserve
8931055 // class)
8941056 it .Reset ();
0 commit comments