2323#include < vector>
2424#include < array>
2525
26+ using o2::its::clearResizeBoundedVector;
27+
2628namespace o2 ::trk
2729{
2830
29- template <int nLayers >
30- int TimeFrame<nLayers >::loadROFsFromHitTree(TTree* hitsTree, GeometryTGeo* gman, const nlohmann::json& config)
31+ template <int NLayers >
32+ int TimeFrame<NLayers >::loadROFsFromHitTree(TTree* hitsTree, GeometryTGeo* gman, const nlohmann::json& config)
3133{
3234 constexpr std::array<int , 2 > startLayer{0 , 3 };
3335 const Long64_t nEvents = hitsTree->GetEntries ();
@@ -39,23 +41,39 @@ int TimeFrame<nLayers>::loadROFsFromHitTree(TTree* hitsTree, GeometryTGeo* gman,
3941
4042 const int inROFpileup{config.contains (" inROFpileup" ) ? config[" inROFpileup" ].get <int >() : 1 };
4143
42- // Calculate number of ROFs and initialize data structures
43- this ->mNrof = (nEvents + inROFpileup - 1 ) / inROFpileup;
44+ // Calculate number of ROFs
45+ const int nRofs = (nEvents + inROFpileup - 1 ) / inROFpileup;
46+
47+ // Set up ROF timing for all layers (no staggering in TRK simulation, all layers read out together)
48+ constexpr uint32_t rofLength = 198 ; // ROF length in BC
49+ o2::its::ROFOverlapTable<NLayers> overlapTable;
50+ for (int iLayer = 0 ; iLayer < NLayers; ++iLayer) {
51+ overlapTable.defineLayer (iLayer, nRofs, rofLength, 0 , 0 , 0 );
52+ }
53+ overlapTable.init ();
54+ this ->setROFOverlapTable (overlapTable);
55+
56+ // Set up the vertex lookup table timing (pre-allocate, vertices will be filled later)
57+ o2::its::ROFVertexLookupTable<NLayers> vtxLookupTable;
58+ for (int iLayer = 0 ; iLayer < NLayers; ++iLayer) {
59+ vtxLookupTable.defineLayer (iLayer, nRofs, rofLength, 0 , 0 , 0 );
60+ }
61+ vtxLookupTable.init (); // pre-allocate without vertices
62+ this ->setROFVertexLookupTable (vtxLookupTable);
4463
4564 // Reset and prepare ROF data structures
46- for (int iLayer{0 }; iLayer < nLayers ; ++iLayer) {
65+ for (int iLayer{0 }; iLayer < NLayers ; ++iLayer) {
4766 this ->mMinR [iLayer] = std::numeric_limits<float >::max ();
4867 this ->mMaxR [iLayer] = std::numeric_limits<float >::lowest ();
4968 this ->mROFramesClusters [iLayer].clear ();
50- this ->mROFramesClusters [iLayer].resize (this -> mNrof + 1 , 0 );
69+ this ->mROFramesClusters [iLayer].resize (nRofs + 1 , 0 );
5170 this ->mUnsortedClusters [iLayer].clear ();
5271 this ->mTrackingFrameInfo [iLayer].clear ();
5372 this ->mClusterExternalIndices [iLayer].clear ();
5473 }
5574
5675 // Pre-count hits to reserve memory efficiently
57- int totalNHits{0 };
58- std::array<int , nLayers> clusterCountPerLayer{};
76+ std::array<int , NLayers> clusterCountPerLayer{};
5977 for (Long64_t iEvent = 0 ; iEvent < nEvents; ++iEvent) {
6078 hitsTree->GetEntry (iEvent);
6179 for (const auto & hit : *trkHit) {
@@ -64,35 +82,35 @@ int TimeFrame<nLayers>::loadROFsFromHitTree(TTree* hitsTree, GeometryTGeo* gman,
6482 }
6583 int subDetID = gman->getSubDetID (hit.GetDetectorID ());
6684 const int layer = startLayer[subDetID] + gman->getLayer (hit.GetDetectorID ());
67- if (layer >= nLayers ) {
85+ if (layer >= NLayers ) {
6886 continue ;
6987 }
7088 ++clusterCountPerLayer[layer];
71- totalNHits++;
7289 }
7390 }
7491
75- // Reserve memory for all layers
76- for (int iLayer{0 }; iLayer < nLayers ; ++iLayer) {
92+ // Reserve memory for all layers (mClusterSize is now per-layer)
93+ for (int iLayer{0 }; iLayer < NLayers ; ++iLayer) {
7794 this ->mUnsortedClusters [iLayer].reserve (clusterCountPerLayer[iLayer]);
7895 this ->mTrackingFrameInfo [iLayer].reserve (clusterCountPerLayer[iLayer]);
7996 this ->mClusterExternalIndices [iLayer].reserve (clusterCountPerLayer[iLayer]);
97+ clearResizeBoundedVector (this ->mClusterSize [iLayer], clusterCountPerLayer[iLayer], this ->mMemoryPool .get ());
8098 }
81- clearResizeBoundedVector (this ->mClusterSize , totalNHits, this ->mMemoryPool .get ());
8299
83100 std::array<float , 11 > resolution{0.001 , 0.001 , 0.001 , 0.001 , 0.004 , 0.004 , 0.004 , 0.004 , 0.004 , 0.004 , 0.004 };
84- if (config[" geometry" ][" pitch" ].size () == nLayers ) {
85- for (int iLayer{0 }; iLayer < config[" geometry" ][" pitch" ].size (); ++iLayer) {
101+ if (config[" geometry" ][" pitch" ].size () == static_cast < size_t >(NLayers) ) {
102+ for (size_t iLayer{0 }; iLayer < config[" geometry" ][" pitch" ].size (); ++iLayer) {
86103 LOGP (info, " Setting resolution for layer {} from config" , iLayer);
87104 LOGP (info, " Layer {} pitch {} cm" , iLayer, config[" geometry" ][" pitch" ][iLayer].get <float >());
88105 resolution[iLayer] = config[" geometry" ][" pitch" ][iLayer].get <float >() / std::sqrt (12 .f );
89106 }
90107 }
91108 LOGP (info, " Number of active parts in VD: {}" , gman->getNumberOfActivePartsVD ());
92109
93- int hitCounter{ 0 };
94- auto labels = new dataformats::MCTruthContainer<MCCompLabel>();
110+ // One shared MC label container for all layers
111+ auto * labels = new dataformats::MCTruthContainer<MCCompLabel>();
95112
113+ int hitCounter{0 };
96114 int iRof{0 }; // Current ROF index
97115 for (Long64_t iEvent = 0 ; iEvent < nEvents; ++iEvent) {
98116 hitsTree->GetEntry (iEvent);
@@ -108,7 +126,7 @@ int TimeFrame<nLayers>::loadROFsFromHitTree(TTree* hitsTree, GeometryTGeo* gman,
108126 o2::math_utils::Point3D<float > gloXYZ;
109127 o2::math_utils::Point3D<float > trkXYZ;
110128 float r{0 .f };
111- if (layer >= nLayers ) {
129+ if (layer >= NLayers ) {
112130 continue ;
113131 }
114132 if (layer >= 3 ) {
@@ -139,11 +157,12 @@ int TimeFrame<nLayers>::loadROFsFromHitTree(TTree* hitsTree, GeometryTGeo* gman,
139157 std::array<float , 2 >{trkXYZ.y (), trkXYZ.z ()},
140158 std::array<float , 3 >{resolution[layer] * resolution[layer], 0 ., resolution[layer] * resolution[layer]});
141159 // / Rotate to the global frame
142- this ->addClusterToLayer (layer, gloXYZ.x (), gloXYZ.y (), gloXYZ.z (), this ->mUnsortedClusters [layer].size ());
160+ const int clusterIdxInLayer = this ->mUnsortedClusters [layer].size ();
161+ this ->addClusterToLayer (layer, gloXYZ.x (), gloXYZ.y (), gloXYZ.z (), clusterIdxInLayer);
143162 this ->addClusterExternalIndexToLayer (layer, hitCounter);
144163 MCCompLabel label{hit.GetTrackID (), static_cast <int >(iEvent), 0 };
145164 labels->addElement (hitCounter, label);
146- this ->mClusterSize [hitCounter] = 1 ; // For compatibility with cluster-based tracking, set cluster size to 1 for hits
165+ this ->mClusterSize [layer][clusterIdxInLayer] = 1 ;
147166 hitCounter++;
148167 }
149168 trkHit->clear ();
@@ -154,21 +173,23 @@ int TimeFrame<nLayers>::loadROFsFromHitTree(TTree* hitsTree, GeometryTGeo* gman,
154173 for (unsigned int iLayer{0 }; iLayer < this ->mUnsortedClusters .size (); ++iLayer) {
155174 this ->mROFramesClusters [iLayer][iRof] = this ->mUnsortedClusters [iLayer].size (); // effectively calculating an exclusive sum
156175 }
157- // Update primary vertices ROF structure
158176 }
159- this ->mClusterLabels = labels;
160177 }
161- return this ->mNrof ;
178+
179+ // Set the shared labels container for all layers
180+ for (int iLayer = 0 ; iLayer < NLayers; ++iLayer) {
181+ this ->mClusterLabels [iLayer] = labels;
182+ }
183+
184+ return nRofs;
162185}
163186
164- template <int nLayers >
165- void TimeFrame<nLayers >::getPrimaryVerticesFromMC(TTree* mcHeaderTree, int nRofs, Long64_t nEvents, int inROFpileup)
187+ template <int NLayers >
188+ void TimeFrame<NLayers >::getPrimaryVerticesFromMC(TTree* mcHeaderTree, int nRofs, Long64_t nEvents, int inROFpileup, uint32_t rofLength )
166189{
167190 auto mcheader = new o2::dataformats::MCEventHeader;
168191 mcHeaderTree->SetBranchAddress (" MCEventHeader." , &mcheader);
169192
170- this ->mROFramesPV .clear ();
171- this ->mROFramesPV .resize (nRofs + 1 , 0 );
172193 this ->mPrimaryVertices .clear ();
173194
174195 int iRof{0 };
@@ -178,14 +199,24 @@ void TimeFrame<nLayers>::getPrimaryVerticesFromMC(TTree* mcHeaderTree, int nRofs
178199 vertex.setXYZ (mcheader->GetX (), mcheader->GetY (), mcheader->GetZ ());
179200 vertex.setNContributors (30 );
180201 vertex.setChi2 (0 .f );
181- LOGP (debug, " ROF {}: Added primary vertex at ({}, {}, {})" , iRof, mcheader->GetX (), mcheader->GetY (), mcheader->GetZ ());
182- this ->mPrimaryVertices .push_back (vertex);
202+
203+ // Set proper BC timestamp for vertex-ROF compatibility
204+ // The vertex timestamp is set to the center of its ROF with half-ROF as error
205+ const uint32_t rofCenter = static_cast <uint32_t >(rofLength * iRof + rofLength / 2 );
206+ const uint16_t rofHalf = static_cast <uint16_t >(rofLength / 2 );
207+ vertex.setTimeStamp ({rofCenter, rofHalf});
208+
209+ LOGP (debug, " ROF {}: Added primary vertex at ({}, {}, {}) with BC timestamp [{}, +/-{}]" ,
210+ iRof, mcheader->GetX (), mcheader->GetY (), mcheader->GetZ (), rofCenter, rofHalf);
211+ this ->addPrimaryVertex (vertex);
183212 if ((iEvent + 1 ) % inROFpileup == 0 || iEvent == nEvents - 1 ) {
184213 iRof++;
185- this ->mROFramesPV [iRof] = this ->mPrimaryVertices .size (); // effectively calculating an exclusive sum
186214 }
187215 }
188216 this ->mMultiplicityCutMask .resize (nRofs, true ); // / all ROFs are valid with MC primary vertices.
217+
218+ // Update the vertex lookup table with the newly added vertices
219+ this ->updateROFVertexLookupTable ();
189220}
190221
191222// Explicit template instantiation for TRK with 11 layers
0 commit comments