@@ -71,7 +71,7 @@ class TPCTimeSeries : public Task
7171 uint8_t trdPattern = 0 ;
7272 uint8_t nTRDTracklets = 0 ;
7373 int trackletIndices[6 ] = {-1 , -1 , -1 , -1 , -1 , -1 };
74- o2::track::TrackParCov trdTrackParCov; // Phase 0.4: TRD track for propagation to R= 275
74+ o2::track::TrackParCov trdTrackParCov; // TRD track state for propagation to the common local X = 275 cm plane; filled only with --store-full-trackpar
7575 bool hasTRDTrackPar = false ;
7676 };
7777
@@ -90,9 +90,7 @@ class TPCTimeSeries : public Task
9090 float c11 = trk1.getSigmaSnp2 () + trk2.getSigmaSnp2 ();
9191 float c12 = trk1.getSigma1PtSnp () + trk2.getSigma1PtSnp ();
9292 float c22 = trk1.getSigma1Pt2 () + trk2.getSigma1Pt2 ();
93- float det = c00 * (c11 * c22 - c12 * c12)
94- - c01 * (c01 * c22 - c12 * c02)
95- + c02 * (c01 * c12 - c11 * c02);
93+ float det = c00 * (c11 * c22 - c12 * c12) - c01 * (c01 * c22 - c12 * c02) + c02 * (c01 * c12 - c11 * c02);
9694 if (std::abs (det) < 1e-30f ) {
9795 return -1 .f ;
9896 }
@@ -103,9 +101,7 @@ class TPCTimeSeries : public Task
103101 float i11 = (c00 * c22 - c02 * c02) * detInv;
104102 float i12 = (c01 * c02 - c00 * c12) * detInv;
105103 float i22 = (c00 * c11 - c01 * c01) * detInv;
106- return d0 * (i00 * d0 + i01 * d1 + i02 * d2)
107- + d1 * (i01 * d0 + i11 * d1 + i12 * d2)
108- + d2 * (i02 * d0 + i12 * d1 + i22 * d2);
104+ return d0 * (i00 * d0 + i01 * d1 + i02 * d2) + d1 * (i01 * d0 + i11 * d1 + i12 * d2) + d2 * (i02 * d0 + i12 * d1 + i22 * d2);
109105 }
110106
111107 // / Chi2 match in non-bending plane (Z, Tgl) — 2 DOF
@@ -165,6 +161,7 @@ class TPCTimeSeries : public Task
165161 mXOuterMatching = ic.options ().get <float >(" refX-for-outer-ITS" );
166162 mUseMinBiasTrigger = !ic.options ().get <bool >(" disable-min-bias-trigger" );
167163 mMaxOccupancyHistBins = ic.options ().get <int >(" max-occupancy-bins" );
164+ mStoreFullTrackPar = ic.options ().get <bool >(" store-full-trackpar" );
168165
169166 if (mUnbinnedWriter ) {
170167 for (int iThread = 0 ; iThread < mNThreads ; ++iThread) {
@@ -191,6 +188,13 @@ class TPCTimeSeries : public Task
191188 void run (ProcessingContext& pc) final
192189 {
193190 o2::base::GRPGeomHelper::instance ().checkUpdates (pc);
191+ // run-level TRD readout flag from GRPECS (unbinned output only): 1 = TRD in readout, 0 = not in readout,
192+ // 255 = unknown (defensive: GRPECS is requested only with the unbinned writer)
193+ mTRDInReadout = 255 ;
194+ if (mUnbinnedWriter ) {
195+ const auto * grpecs = o2::base::GRPGeomHelper::instance ().getGRPECS ();
196+ mTRDInReadout = grpecs ? static_cast <uint8_t >(grpecs->isDetReadOut (DetID::TRD ) ? 1 : 0 ) : static_cast <uint8_t >(255 );
197+ }
194198 mTPCVDriftHelper .extractCCDBInputs (pc);
195199 mPTHelper .extractCCDBInputs (pc);
196200 if (mTPCVDriftHelper .isUpdated ()) {
@@ -394,8 +398,10 @@ class TPCTimeSeries : public Task
394398 trdData.trackletIndices [iLay] = trkltId;
395399 }
396400 }
397- trdData.trdTrackParCov = o2::track::TrackParCov (trdTrack);
398- trdData.hasTRDTrackPar = true ;
401+ if (mStoreFullTrackPar ) {
402+ trdData.trdTrackParCov = o2::track::TrackParCov (trdTrack); // TrackTRD base state, not validated as the outer/entrance state (open Phase 0.4 finding)
403+ trdData.hasTRDTrackPar = true ;
404+ }
399405 tpcToTRDMap[refTPC] = trdData;
400406 }
401407 }
@@ -1211,6 +1217,8 @@ class TPCTimeSeries : public Task
12111217 float mMaxdEdxRegionRatio {0.5 }; // /< maximum abs dedx region ratio: log(dedx_region/dedx)
12121218 float mSamplingFactor {0.1 }; // /< sampling factor in case sampling is used for unbinned data
12131219 bool mSampleTsallis {false }; // /< perform sampling of unbinned data
1220+ bool mStoreFullTrackPar {false }; // /< experimental: compute and store tpcOut/trdIn/tpcAtVtx TrackPar and TPC-TRD chi2 (constant per job)
1221+ uint8_t mTRDInReadout {255 }; // /< TRD in detector readout (GRPECS): 1 yes, 0 no, 255 unknown
12141222 std::vector<std::mt19937> mGenerator ; // /< random generator for debug tree sampling
12151223 std::vector<std::unique_ptr<o2::utils::TreeStreamRedirector>> mStreamer ; // /< streamer for unbinned data
12161224 float mXOuterMatching {60 }; // /< reference x where delta track parameters for TPC with ITS-TPC track are stored in skimmed data
@@ -1477,40 +1485,46 @@ class TPCTimeSeries : public Task
14771485 }
14781486 }
14791487
1480- // Phase 0.4: TPC out / TRD in at kTPCTRDMiddle, same frame, same X
1481- static constexpr float kTPCTRDMiddle = 275 .f ; // cm, midpoint TPC outer / TRD layer 0
1482- auto propagator = o2::base::Propagator::Instance ();
1483-
1484- // D1: TPC outer → kTPCTRDMiddle
1485- o2::track::TrackParCov tpcOutCov (tracksTPC[iTrk].getParamOut ());
1486- uint8_t tpcOutOK = 2 ; // default: propagation failed
1487- {
1488- // rotate to sector angle at current position
1489- float sn = std::sin (tpcOutCov.getAlpha ());
1490- float cs = std::cos (tpcOutCov.getAlpha ());
1491- float gy = tpcOutCov.getX () * sn + tpcOutCov.getY () * cs;
1492- float gx = tpcOutCov.getX () * cs - tpcOutCov.getY () * sn;
1493- if (tpcOutCov.rotate (std::atan2 (gy, gx)) &&
1494- propagator->propagateTo (tpcOutCov, kTPCTRDMiddle , false , mMaxSnp , mCoarseStep , mMatType )) {
1495- tpcOutOK = 0 ;
1496- }
1497- }
1498-
1499- // D2: TRD matched → kTPCTRDMiddle, rotated to SAME alpha as TPC out
1488+ // Optional TPC-out / TRD-in states on a common local X plane (experimental, --store-full-trackpar, default off).
1489+ // Open Phase 0.4 findings, deferred: the target is local X = kTPCTRDMiddle in the frame rotated to the track
1490+ // position angle (lab radius = sqrt(X^2 + Y^2), not exactly 275 cm), and the TRD starting state is the TrackTRD
1491+ // base state, not validated as the outer/entrance state. With the switch off nothing below is computed.
1492+ static constexpr float kTPCTRDMiddle = 275 .f ; // cm, common local X plane between TPC outer wall and TRD layer 0
1493+ o2::track::TrackParCov tpcOutCov; // local temporary with covariance (needed for chi2); persisted as TrackPar
15001494 o2::track::TrackParCov trdInCov;
1501- uint8_t trdInOK = 1 ; // default: no TRD match
1502- float chi2PhiTPCTRD = -1 .f ;
1495+ uint8_t tpcOutOK = 255 ; // 0 propagated, 2 propagation failed, 255 switch off (not computed)
1496+ uint8_t trdInOK = 255 ; // 0 propagated, 1 not attempted (no TRD match or tpcOutOK != 0), 2 propagation failed, 255 switch off; count TRD matches with trdPattern > 0
1497+ float chi2PhiTPCTRD = -1 .f ; // -1: not computed (switch off, trdInOK != 0) or singular covariance
15031498 float chi2ZTPCTRD = -1 .f ;
1504- if (itTRD != tpcToTRDMap.end () && itTRD->second .hasTRDTrackPar && tpcOutOK == 0 ) {
1505- trdInCov = o2::track::TrackParCov (itTRD->second .trdTrackParCov );
1506- // rotate to TPC alpha FIRST, then propagate — guarantees same frame + same X
1507- if (trdInCov.rotate (tpcOutCov.getAlpha ()) &&
1508- propagator->propagateTo (trdInCov, kTPCTRDMiddle , false , mMaxSnp , mCoarseStep , mMatType )) {
1509- trdInOK = 0 ;
1510- chi2PhiTPCTRD = chi2Match_Phi (tpcOutCov, trdInCov);
1511- chi2ZTPCTRD = chi2Match_Z (tpcOutCov, trdInCov);
1512- } else {
1513- trdInOK = 2 ; // propagation failed
1499+ if (mStoreFullTrackPar ) {
1500+ // D1: TPC outer → kTPCTRDMiddle
1501+ tpcOutCov = o2::track::TrackParCov (tracksTPC[iTrk].getParamOut ());
1502+ tpcOutOK = 2 ; // default: propagation failed
1503+ {
1504+ // rotate to sector angle at current position
1505+ float sn = std::sin (tpcOutCov.getAlpha ());
1506+ float cs = std::cos (tpcOutCov.getAlpha ());
1507+ float gy = tpcOutCov.getX () * sn + tpcOutCov.getY () * cs;
1508+ float gx = tpcOutCov.getX () * cs - tpcOutCov.getY () * sn;
1509+ if (tpcOutCov.rotate (std::atan2 (gy, gx)) &&
1510+ propagator->propagateTo (tpcOutCov, kTPCTRDMiddle , false , mMaxSnp , mCoarseStep , mMatType )) {
1511+ tpcOutOK = 0 ;
1512+ }
1513+ }
1514+
1515+ // D2: TRD matched → kTPCTRDMiddle, rotated to SAME alpha as TPC out
1516+ trdInOK = 1 ; // default: not attempted
1517+ if (itTRD != tpcToTRDMap.end () && itTRD->second .hasTRDTrackPar && tpcOutOK == 0 ) {
1518+ trdInCov = o2::track::TrackParCov (itTRD->second .trdTrackParCov );
1519+ // rotate to TPC alpha FIRST, then propagate — guarantees same frame + same X
1520+ if (trdInCov.rotate (tpcOutCov.getAlpha ()) &&
1521+ propagator->propagateTo (trdInCov, kTPCTRDMiddle , false , mMaxSnp , mCoarseStep , mMatType )) {
1522+ trdInOK = 0 ;
1523+ chi2PhiTPCTRD = chi2Match_Phi (tpcOutCov, trdInCov);
1524+ chi2ZTPCTRD = chi2Match_Z (tpcOutCov, trdInCov);
1525+ } else {
1526+ trdInOK = 2 ; // propagation failed
1527+ }
15141528 }
15151529 }
15161530
@@ -1609,6 +1623,29 @@ class TPCTimeSeries : public Task
16091623 }
16101624 double vertexTime = vertex.getTimeStamp ().getTimeStamp ();
16111625 double trackTime0 = trackFull.getTime0 ();
1626+ // Optional payload (--store-full-trackpar, default off), persisted without covariance as TrackPar.
1627+ // This statement and the main chain below fill ONE entry: TreeStream keeps its element index until "\n",
1628+ // and the flag is constant for the job, so every entry has the same branch set (a varying set silently
1629+ // drops entries). Keep both statements adjacent, with no return/continue in between, and keep the objects in
1630+ // scope until the "\n" below (TreeStream stores pointers and reads them when the entry is filled).
1631+ // tpcAtVtx = TPC track after the DCA step; its reference depends on the path:
1632+ // all tracks: DCA to (0,0,0);
1633+ // then, for ITS-TPC vertex contributors passing the ITS-TPC DCA cuts: DCA to the primary vertex;
1634+ // then, if also passing the combined DCA cut and having an ITS track: rotated to the ITS track frame and
1635+ // propagated to the X of the ITS-TPC track.
1636+ // With the switch on, these three branches come first in the tree (compare by branch name, not position).
1637+ o2::track::TrackPar tpcOutPar;
1638+ o2::track::TrackPar trdInPar;
1639+ o2::track::TrackPar tpcAtVtxPar;
1640+ if (mStoreFullTrackPar ) {
1641+ tpcOutPar = tpcOutCov;
1642+ trdInPar = trdInCov;
1643+ tpcAtVtxPar = track;
1644+ *mStreamer [iThread] << " treeTimeSeries"
1645+ << " tpcOut=" << tpcOutPar
1646+ << " trdIn=" << trdInPar
1647+ << " tpcAtVtx=" << tpcAtVtxPar;
1648+ }
16121649 *mStreamer [iThread] << " treeTimeSeries"
16131650 // DCAs
16141651 << " triggerMask=" << triggerMask
@@ -1656,15 +1693,14 @@ class TPCTimeSeries : public Task
16561693 << " nTRDTracklets=" << nTRDTracklets
16571694 << " trdTracklets=" << trdTrackletVec
16581695 << " trdCalibTracklets=" << trdCalibVec
1659- // Phase 0.4: TPC out / TRD in at R= 275 cm
1660- << " tpcOut= " << tpcOutCov
1696+ // TPC out / TRD in on the common local X = 275 cm plane: status and matching chi2
1697+ // (255 / -1 when --store-full-trackpar is off; the TrackPar objects are written above)
16611698 << " tpcOutOK=" << tpcOutOK
1662- << " trdIn=" << trdInCov
16631699 << " trdInOK=" << trdInOK
16641700 << " chi2PhiTPCTRD=" << chi2PhiTPCTRD
16651701 << " chi2ZTPCTRD=" << chi2ZTPCTRD
1666- // Track parameters at vertex (full TrackParCov)
1667- << " tpcAtVtx =" << track
1702+ // TRD in detector readout for this run (GRPECS): 1 yes, 0 no, 255 unknown
1703+ << " trdInReadout =" << mTRDInReadout
16681704 << " chi2match_ITSTPC=" << chi2match_ITSTPC
16691705 << " PID=" << trkOrig.getPID ().getID ()
16701706 // TPC cov at vertex (without vertex constrained)
@@ -2056,7 +2092,7 @@ o2::framework::DataProcessorSpec getTPCTimeSeriesSpec(const bool disableWriter,
20562092
20572093 const bool enableAskMatLUT = matType == o2::base::Propagator::MatCorrType::USEMatCorrLUT;
20582094 auto ccdbRequest = std::make_shared<o2::base::GRPGeomRequest>(!disableWriter, // orbitResetTime
2059- false , // GRPECS=true for nHBF per TF
2095+ enableUnbinnedWriter , // GRPECS only when the unbinned trdInReadout can be written
20602096 false , // GRPLHCIF
20612097 true , // GRPMagField
20622098 enableAskMatLUT, // askMatLUT
@@ -2113,6 +2149,7 @@ o2::framework::DataProcessorSpec getTPCTimeSeriesSpec(const bool disableWriter,
21132149 {" sample-unbinned-tsallis" , VariantType::Bool, false , {" Perform sampling of unbinned data based on Tsallis function" }},
21142150 {" sampling-factor" , VariantType::Float, 0 .001f , {" Sampling factor in case sample-unbinned-tsallis is used" }},
21152151 {" disable-min-bias-trigger" , VariantType::Bool, false , {" Disable the minimum bias trigger for skimmed data" }},
2152+ {" store-full-trackpar" , VariantType::Bool, false , {" Experimental: compute TPC-out/TRD-in states on the common local X = 275 cm plane and the TPC-TRD matching chi2, and store tpcOut, trdIn, tpcAtVtx as TrackPar in the unbinned tree" }},
21162153 {" out-file-unbinned" , VariantType::String, " time_series_tracks.root" , {" name of the output file for the unbinned data" }},
21172154 {" max-occupancy-bins" , VariantType::Int, 912 , {" Maximum number of occupancy bins" }}}};
21182155}
0 commit comments