@@ -71,8 +71,61 @@ 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
75+ bool hasTRDTrackPar = false ;
7476 };
7577
78+ // / Chi2 match in bending plane (Y, Snp, Q2Pt) — 3 DOF
79+ // / Both tracks must be at the same X and alpha.
80+ // / Returns -1 if covariance matrix is singular.
81+ static float chi2Match_Phi (const o2::track::TrackParCov& trk1, const o2::track::TrackParCov& trk2)
82+ {
83+ float d0 = trk1.getY () - trk2.getY ();
84+ float d1 = trk1.getSnp () - trk2.getSnp ();
85+ float d2 = trk1.getQ2Pt () - trk2.getQ2Pt ();
86+ // Combined covariance C = C1 + C2
87+ float c00 = trk1.getSigmaY2 () + trk2.getSigmaY2 ();
88+ float c01 = trk1.getSigmaSnpY () + trk2.getSigmaSnpY ();
89+ float c02 = trk1.getSigma1PtY () + trk2.getSigma1PtY ();
90+ float c11 = trk1.getSigmaSnp2 () + trk2.getSigmaSnp2 ();
91+ float c12 = trk1.getSigma1PtSnp () + trk2.getSigma1PtSnp ();
92+ 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);
96+ if (std::abs (det) < 1e-30f ) {
97+ return -1 .f ;
98+ }
99+ float detInv = 1 .f / det;
100+ float i00 = (c11 * c22 - c12 * c12) * detInv;
101+ float i01 = (c02 * c12 - c01 * c22) * detInv;
102+ float i02 = (c01 * c12 - c02 * c11) * detInv;
103+ float i11 = (c00 * c22 - c02 * c02) * detInv;
104+ float i12 = (c01 * c02 - c00 * c12) * detInv;
105+ 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);
109+ }
110+
111+ // / Chi2 match in non-bending plane (Z, Tgl) — 2 DOF
112+ // / Both tracks must be at the same X and alpha.
113+ // / Returns -1 if covariance matrix is singular.
114+ static float chi2Match_Z (const o2::track::TrackParCov& trk1, const o2::track::TrackParCov& trk2)
115+ {
116+ float d0 = trk1.getZ () - trk2.getZ ();
117+ float d1 = trk1.getTgl () - trk2.getTgl ();
118+ float c00 = trk1.getSigmaZ2 () + trk2.getSigmaZ2 ();
119+ float c01 = trk1.getSigmaTglZ () + trk2.getSigmaTglZ ();
120+ float c11 = trk1.getSigmaTgl2 () + trk2.getSigmaTgl2 ();
121+ float det = c00 * c11 - c01 * c01;
122+ if (std::abs (det) < 1e-30f ) {
123+ return -1 .f ;
124+ }
125+ float detInv = 1 .f / det;
126+ return (d0 * d0 * c11 - 2 .f * d0 * d1 * c01 + d1 * d1 * c00) * detInv;
127+ }
128+
76129 // / \constructor
77130 TPCTimeSeries (std::shared_ptr<o2::base::GRPGeomRequest> req, const bool disableWriter, const o2::base::Propagator::MatCorrType matType, const bool enableUnbinnedWriter, const bool tpcOnly, std::shared_ptr<o2::globaltracking::DataRequest> dr) : mCCDBRequest (req), mDisableWriter (disableWriter), mMatType (matType), mUnbinnedWriter (enableUnbinnedWriter), mTPCOnly (tpcOnly), mDataRequest (dr) {};
78131
@@ -341,6 +394,8 @@ class TPCTimeSeries : public Task
341394 trdData.trackletIndices [iLay] = trkltId;
342395 }
343396 }
397+ trdData.trdTrackParCov = o2::track::TrackParCov (trdTrack);
398+ trdData.hasTRDTrackPar = true ;
344399 tpcToTRDMap[refTPC] = trdData;
345400 }
346401 }
@@ -1421,6 +1476,55 @@ class TPCTimeSeries : public Task
14211476 }
14221477 }
14231478 }
1479+
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
1500+ o2::track::TrackParCov trdInCov;
1501+ uint8_t trdInOK = 1 ; // default: no TRD match
1502+ float chi2PhiTPCTRD = -1 .f ;
1503+ 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
1514+ }
1515+ }
1516+
1517+ // ITS-TPC track at vertex (full TrackParCov, propagated to DCA)
1518+ o2::track::TrackParCov itstpcAtVtx;
1519+ bool hasITSTPCAtVtx = false ;
1520+ if (hasITSTPC) {
1521+ itstpcAtVtx = tracksITSTPC[idxITSTPC.front ()];
1522+ o2::dataformats::DCA dcaTmp;
1523+ if (propagator->propagateToDCA (vertex.getXYZ (), itstpcAtVtx, propagator->getNominalBz (), mFineStep , mMatType , &dcaTmp)) {
1524+ hasITSTPCAtVtx = true ;
1525+ }
1526+ }
1527+
14241528 int typeSide = 2 ; // A- and C-Side cluster
14251529 if (trackFull.hasASideClustersOnly ()) {
14261530 typeSide = 0 ;
@@ -1563,6 +1667,17 @@ class TPCTimeSeries : public Task
15631667 << " nTRDTracklets=" << nTRDTracklets
15641668 << " trdTracklets=" << trdTrackletVec
15651669 << " trdCalibTracklets=" << trdCalibVec
1670+ // Phase 0.4: TPC out / TRD in at R=275 cm
1671+ << " tpcOut=" << tpcOutCov
1672+ << " tpcOutOK=" << tpcOutOK
1673+ << " trdIn=" << trdInCov
1674+ << " trdInOK=" << trdInOK
1675+ << " chi2PhiTPCTRD=" << chi2PhiTPCTRD
1676+ << " chi2ZTPCTRD=" << chi2ZTPCTRD
1677+ // Track parameters at vertex (full TrackParCov)
1678+ << " tpcAtVtx=" << track
1679+ << " itstpcAtVtx=" << itstpcAtVtx
1680+ << " hasITSTPCAtVtx=" << hasITSTPCAtVtx
15661681 << " chi2match_ITSTPC=" << chi2match_ITSTPC
15671682 << " PID=" << trkOrig.getPID ().getID ()
15681683 // TPC cov at vertex (without vertex constrained)
0 commit comments