4545#include " DataFormatsTRD/TrackTRD.h"
4646#include " DataFormatsTRD/Tracklet64.h"
4747#include " DataFormatsTRD/CalibratedTracklet.h"
48+ #include " DataFormatsTRD/TriggerRecord.h"
49+ #include " CommonConstants/LHCConstants.h"
4850#include " TROOT.h"
4951#include " ReconstructionDataFormats/MatchInfoTOF.h"
5052#include " DataFormatsTOF/Cluster.h"
@@ -376,6 +378,20 @@ class TPCTimeSeries : public Task
376378 std::unordered_map<unsigned int , TRDTrackletData> tpcToTRDMap;
377379 auto trdTracklets = (mTPCOnly || !recoData.inputsTRD ) ? gsl::span<const o2::trd::Tracklet64>() : recoData.getTRDTracklets ();
378380 auto trdCalibTracklets = (mTPCOnly || !recoData.inputsTRD ) ? gsl::span<const o2::trd::CalibratedTracklet>() : recoData.getTRDCalibratedTracklets ();
381+
382+ // TRD-triggered BCs of this TF: TRD is read out only at these BCs. Built once per TF; per entry only the triggers closest
383+ // to the collision are stored (trdTrigDBCBefore/After). Records with bc >= LHCMaxBunches are dropped, as in the AOD producer.
384+ mTRDTrigBCs .clear ();
385+ if (mUnbinnedWriter && !mTPCOnly && recoData.inputsTRD ) {
386+ const auto trdTrig = recoData.getTRDTriggerRecords ();
387+ mTRDTrigBCs .reserve (trdTrig.size ());
388+ for (const auto & trg : trdTrig) {
389+ if (trg.getBCData ().bc < o2::constants::lhc::LHCMaxBunches) {
390+ mTRDTrigBCs .push_back (trg.getBCData ());
391+ }
392+ }
393+ std::sort (mTRDTrigBCs .begin (), mTRDTrigBCs .end ());
394+ }
379395 if (mUnbinnedWriter && !mTPCOnly ) {
380396 // scan ITS-TPC-TRD tracks
381397 auto itstpctrdTracks = recoData.getITSTPCTRDTracks <o2::trd::TrackTRD>();
@@ -399,9 +415,9 @@ class TPCTimeSeries : public Task
399415 trdData.trackletIndices [iLay] = trkltId;
400416 }
401417 }
402- // outer state of the ITS-TPC-TRD track: outward refit through ITS, TPC and TRD, at the outermost TRD layer (as in
403- // RecoContainer::getTrackParamOut). The base state of TrackTRD is the inward refit, which ends at the innermost ITS cluster.
404- trdData.trdTrackParCov = trdTrack. getOuterParam ( );
418+ // TRD-out: outer state of the ITS-TPC-TRD track ( outward refit through ITS, TPC and TRD, at the outermost TRD layer).
419+ // The base state of TrackTRD is the inward refit, which ends at the innermost ITS cluster.
420+ trdData.trdTrackParCov = recoData. getTrackParamOut (gid );
405421 trdData.hasTRDTrackPar = true ;
406422 tpcToTRDMap[refTPC] = trdData;
407423 }
@@ -1220,6 +1236,10 @@ class TPCTimeSeries : public Task
12201236 bool mSampleTsallis {false }; // /< perform sampling of unbinned data
12211237 bool mStoreFullTrackPar {false }; // /< experimental: store tpcOut/trdIn/tpcAtVtx as TrackPar (constant per job)
12221238 uint8_t mTRDInReadout {255 }; // /< TRD in detector readout (GRPECS): 1 yes, 0 no, 255 unknown
1239+ std::vector<o2::InteractionRecord> mTRDTrigBCs ; // /< TRD-triggered BCs of the current TF, sorted
1240+ std::vector<int > mNContributorsITS ; // /< per vertex ID: ITS-only PV contributors (current TF)
1241+ std::vector<int > mNContributorsITSTPC ; // /< per vertex ID: ITS-TPC PV contributors, TRD/TOF-matched included (current TF)
1242+ std::vector<int > mNContributorsTRD ; // /< per vertex ID: ITS-TPC-TRD (and -TOF) PV contributors (current TF)
12231243 std::vector<std::mt19937> mGenerator ; // /< random generator for debug tree sampling
12241244 std::vector<std::unique_ptr<o2::utils::TreeStreamRedirector>> mStreamer ; // /< streamer for unbinned data
12251245 float mXOuterMatching {60 }; // /< reference x where delta track parameters for TPC with ITS-TPC track are stored in skimmed data
@@ -1310,6 +1330,11 @@ class TPCTimeSeries : public Task
13101330
13111331 // get vertex (check if vertex ID is valid). In case no vertex is assigned return nearest vertex or else default vertex
13121332 const auto vertex = (idxITSTPC.back () != -1 ) ? vertices[idxITSTPC.back ()] : ((mNearestVtxTPC [iTrk] != -1 ) ? vertices[mNearestVtxTPC [iTrk]] : o2::dataformats::PrimaryVertex{});
1333+ // index of that vertex (-1: none) and its contributor counts, -1 without vertex
1334+ const int vtxID = (idxITSTPC.back () != -1 ) ? idxITSTPC.back () : mNearestVtxTPC [iTrk];
1335+ const int nContribITS = (vtxID >= 0 && vtxID < static_cast <int >(mNContributorsITS .size ())) ? mNContributorsITS [vtxID] : -1 ;
1336+ const int nContribITSTPC = (vtxID >= 0 && vtxID < static_cast <int >(mNContributorsITSTPC .size ())) ? mNContributorsITSTPC [vtxID] : -1 ;
1337+ const int nContribTRD = (vtxID >= 0 && vtxID < static_cast <int >(mNContributorsTRD .size ())) ? mNContributorsTRD [vtxID] : -1 ;
13131338
13141339 // calculate DCAz: (time TPC track - time vertex) * vDrift + sign_side * vertexZ
13151340 const float signSide = trackFull.hasCSideClustersOnly () ? -1 : 1 ; // invert sign for C-side
@@ -1537,6 +1562,29 @@ class TPCTimeSeries : public Task
15371562 }
15381563 }
15391564
1565+ // TRD read out in the collision of this entry: TRD-triggered BCs closest to the BC range [IRMin, IRMax] of the entry's
1566+ // vertex. Both 0: a TRD trigger inside the range. Otherwise trdTrigDBCBefore < 0 = BCs from the range start back to the
1567+ // closest earlier trigger, trdTrigDBCAfter > 0 = BCs from the range end to the closest later trigger. Sentinels -999999 /
1568+ // 999999: no vertex with a BC range, or no such trigger in this TF.
1569+ int trdTrigDBCBefore = -999999 ;
1570+ int trdTrigDBCAfter = 999999 ;
1571+ if (vtxID >= 0 && !vertex.getIRMin ().isDummy () && !vertex.getIRMax ().isDummy ()) {
1572+ const auto & irMin = vertex.getIRMin ();
1573+ const auto & irMax = vertex.getIRMax ();
1574+ const auto itTrig = std::lower_bound (mTRDTrigBCs .begin (), mTRDTrigBCs .end (), irMin); // first trigger at or after irMin
1575+ if (itTrig != mTRDTrigBCs .end () && *itTrig <= irMax) {
1576+ trdTrigDBCBefore = 0 ;
1577+ trdTrigDBCAfter = 0 ;
1578+ } else {
1579+ if (itTrig != mTRDTrigBCs .end ()) {
1580+ trdTrigDBCAfter = static_cast <int >(itTrig->differenceInBC (irMax));
1581+ }
1582+ if (itTrig != mTRDTrigBCs .begin ()) {
1583+ trdTrigDBCBefore = static_cast <int >((itTrig - 1 )->differenceInBC (irMin));
1584+ }
1585+ }
1586+ }
1587+
15401588 int typeSide = 2 ; // A- and C-Side cluster
15411589 if (trackFull.hasASideClustersOnly ()) {
15421590 typeSide = 0 ;
@@ -1676,6 +1724,12 @@ class TPCTimeSeries : public Task
16761724 << " vertex_z=" << vertex.getZ ()
16771725 << " vertex_time=" << vertex.getTimeStamp ().getTimeStamp ()
16781726 << " vertex_nContributors=" << vertex.getNContributors ()
1727+ // contributor counts of the same vertex (-1 without vertex) and TRD triggers closest to its BC range
1728+ << " vertex_nContributorsITS=" << nContribITS
1729+ << " vertex_nContributorsITSTPC=" << nContribITSTPC
1730+ << " vertex_nContributorsTRD=" << nContribTRD
1731+ << " trdTrigDBCBefore=" << trdTrigDBCBefore
1732+ << " trdTrigDBCAfter=" << trdTrigDBCAfter
16791733 << " isNearestVertex=" << isNearestVtx
16801734 // tpc track properties
16811735 << " pt=" << trkOrig.getPt ()
@@ -1937,6 +1991,27 @@ class TPCTimeSeries : public Task
19371991 }
19381992 }
19391993
1994+ // per-vertex contributor counts, also written per entry of the unbinned tree (vertex_nContributorsITS/ITSTPC/TRD)
1995+ mNContributorsITS .assign (vertices.size (), 0 );
1996+ mNContributorsITSTPC .assign (vertices.size (), 0 );
1997+ mNContributorsTRD .assign (vertices.size (), 0 );
1998+ const int nVertices = vertices.size ();
1999+ for (const auto & [vID, n] : nContributors_ITS) {
2000+ if (vID >= 0 && vID < nVertices) {
2001+ mNContributorsITS [vID] = n;
2002+ }
2003+ }
2004+ for (const auto & [vID, n] : nContributors_ITSTPC) {
2005+ if (vID >= 0 && vID < nVertices) {
2006+ mNContributorsITSTPC [vID] = n;
2007+ }
2008+ }
2009+ for (const auto & [vID, n] : nContributors_TRD) {
2010+ if (vID >= 0 && vID < nVertices) {
2011+ mNContributorsTRD [vID] = n;
2012+ }
2013+ }
2014+
19402015 // calculate statistics
19412016 std::array<RobustAverage, 4 > avgVtxITS;
19422017 std::array<RobustAverage, 4 > avgVtxITSTPC;
0 commit comments