Skip to content

Commit e869868

Browse files
TPC SCD: MC truth at the TRD (entrance and ideal tracklet positions)
For tracks with TRD residuals (TRD seeds and ITS-TPC map seeds whose most complete track has TRD), TrackDataMC now also holds the truth at the TRD entrance (first TRD track reference in time, sector frame) and, per layer, the true y and z at the x of the tracklet in the tracklet's sector frame, i.e. the frame of the stored TRD residual (nearest TRD track reference propagated with the workflow's material correction), for the true particle of the ITS-TPC part (ideal tracklets). TrackInterpolation records which ITS-TPC-TRD track gave the TRD residuals of each stored track (getTRDGIDsSuccess, aligned with the track data). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 2ce8a00 commit e869868

3 files changed

Lines changed: 81 additions & 11 deletions

File tree

‎Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TPCInterpolationSpec.cxx‎

Lines changed: 63 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -177,15 +177,16 @@ void TPCInterpolationDPL::fillMCTruth(const RecoContainer& recoData)
177177
{
178178
// MC truth for every stored TrackData: labels of the ITS-TPC part of the seed and of its ITS and TPC parts, the truth at
179179
// the ITS outer parameters (the ITS track reference nearest to TrackData::par, propagated to its x with the material
180-
// correction of the workflow and the mass of the true particle) and the truth at the TPC entrance (the first TPC track
181-
// reference in time, in the sector frame)
180+
// correction of the workflow and the mass of the true particle), the truth at the TPC entrance (the first TPC track
181+
// reference in time, in the sector frame) and, for TRD-matched seeds, the truth at the TRD entrance and the true
182+
// positions at the x of the TRD tracklets of the track (ideal tracklets)
182183
const auto& trkData = mInterpolation.getReferenceTracks();
183184
mTrackDataMC.clear();
184185
mTrackDataMC.resize(trkData.size());
185186
struct Lookup {
186-
o2::MCCompLabel lbl;
187-
uint32_t idx;
188-
bool its; // ITS outer (true) or TPC entrance (false)
187+
o2::MCCompLabel lbl{};
188+
uint32_t idx{0};
189+
uint8_t kind{0}; // 0: ITS outer, 1: TPC entrance, 2: TRD
189190
};
190191
std::vector<Lookup> lookups;
191192
lookups.reserve(2 * trkData.size());
@@ -208,10 +209,13 @@ void TPCInterpolationDPL::fillMCTruth(const RecoContainer& recoData)
208209
const auto& lblITS = mc.labelITS.isValid() ? mc.labelITS : mc.label;
209210
const auto& lblTPC = mc.labelTPC.isValid() ? mc.labelTPC : mc.label;
210211
if (lblITS.isValid()) {
211-
lookups.push_back({lblITS, uint32_t(i), true});
212+
lookups.push_back({lblITS, uint32_t(i), 0});
212213
}
213214
if (lblTPC.isValid()) {
214-
lookups.push_back({lblTPC, uint32_t(i), false});
215+
lookups.push_back({lblTPC, uint32_t(i), 1});
216+
}
217+
if (mInterpolation.getTRDGIDsSuccess()[i].isIndexSet() && lblTPC.isValid()) { // track with TRD residuals: the true particle of the ITS-TPC part at the TRD
218+
lookups.push_back({mc.label.isValid() ? mc.label : lblTPC, uint32_t(i), 2});
215219
}
216220
}
217221
// the reader loads the kinematics of a whole event (can be >100 MB): process event by event and release it right after
@@ -265,7 +269,7 @@ void TPCInterpolationDPL::fillMCTruth(const RecoContainer& recoData)
265269
const auto* pPDG = mcTrk ? O2DatabasePDG::Instance()->GetParticle(pdg) : nullptr;
266270
int charge = pPDG ? int(std::lround(pPDG->Charge() / 3.)) : 0; // TParticlePDG charge is in units of |e|/3
267271
auto refs = mMCReader->getTrackRefs(lbl.getSourceID(), lbl.getEventID(), lbl.getTrackID());
268-
if (lk.its) { // ITS outer: track reference of the ITS part nearest to TrackData::par
272+
if (lk.kind == 0) { // ITS outer: track reference of the ITS part nearest to TrackData::par
269273
mc.pdg = pdg;
270274
const o2::TrackReference* best = nullptr;
271275
float bestD2 = 1e30f;
@@ -291,7 +295,7 @@ void TPCInterpolationDPL::fillMCTruth(const RecoContainer& recoData)
291295
mc.flags |= TrackDataMC::HasITSOut;
292296
}
293297
}
294-
} else { // TPC entrance: first TPC track reference in time of the TPC part
298+
} else if (lk.kind == 1) { // TPC entrance: first TPC track reference in time of the TPC part
295299
if (!mc.labelITS.isValid() && !mc.label.isValid()) {
296300
mc.pdg = pdg; // no ITS lookup for this track
297301
}
@@ -321,6 +325,56 @@ void TPCInterpolationDPL::fillMCTruth(const RecoContainer& recoData)
321325
}
322326
}
323327
}
328+
} else if (charge) { // TRD: entrance (first TRD track reference in time) and the true positions at the tracklet x of each layer
329+
const o2::TrackReference* first = nullptr;
330+
for (const auto& ref : refs) {
331+
if (ref.getDetectorId() == DetID::TRD && (!first || ref.getTime() < first->getTime())) {
332+
first = &ref;
333+
}
334+
}
335+
if (!first) {
336+
continue;
337+
}
338+
mc.parTRDIn = refToPar(*first, charge, pdg, true);
339+
mc.flags |= TrackDataMC::HasTRDIn;
340+
const auto& trkTRD = recoData.getITSTPCTRDTrack<o2::trd::TrackTRD>(mInterpolation.getTRDGIDsSuccess()[lk.idx]); // the TRD track of the stored TRD residuals
341+
const auto trkltsCalib = recoData.getTRDCalibratedTracklets();
342+
const auto tracklets = recoData.getTRDTracklets();
343+
for (int iLayer = 0; iLayer < o2::trd::constants::NLAYER; iLayer++) {
344+
int trkltIdx = trkTRD.getTrackletIndex(iLayer);
345+
if (trkltIdx < 0) {
346+
continue;
347+
}
348+
const auto& sp = trkltsCalib[trkltIdx]; // tracklet x, y, z in its sector frame, as used for the TRD residual
349+
int sec = tracklets[trkltIdx].getDetector() / (o2::trd::constants::NLAYER * o2::trd::constants::NSTACK);
350+
float alpha = o2::math_utils::sector2Angle(sec);
351+
float cs = std::cos(alpha);
352+
float sn = std::sin(alpha);
353+
float gx = sp.getX() * cs - sp.getY() * sn;
354+
float gy = sp.getX() * sn + sp.getY() * cs;
355+
float gz = sp.getZ();
356+
const o2::TrackReference* best = nullptr;
357+
float bestD2 = 1e30f;
358+
for (const auto& ref : refs) {
359+
if (ref.getDetectorId() != DetID::TRD) {
360+
continue;
361+
}
362+
float dx = ref.X() - gx;
363+
float dy = ref.Y() - gy;
364+
float dz = ref.Z() - gz;
365+
float d2 = dx * dx + dy * dy + dz * dz;
366+
if (d2 < bestD2) {
367+
bestD2 = d2;
368+
best = &ref;
369+
}
370+
}
371+
auto par = refToPar(*best, charge, pdg, false);
372+
if (par.rotateParam(alpha) && prop->PropagateToXBxByBz(par, sp.getX(), 0.999f, o2::base::Propagator::MAX_STEP, matCorr)) {
373+
mc.yTRD[iLayer] = par.getY();
374+
mc.zTRD[iLayer] = par.getZ();
375+
mc.trdLayerMask |= uint8_t(1) << iLayer;
376+
}
377+
}
324378
}
325379
}
326380
if (curSrc >= 0) {

‎Detectors/TPC/calibration/SpacePoints/include/SpacePoints/TrackInterpolation.h‎

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -249,20 +249,26 @@ struct TrackData {
249249
struct TrackDataMC {
250250
enum Flags : uint8_t { HasITSOut = 0x1, ///< parITSOut is filled
251251
HasTPCIn = 0x2, ///< parTPCIn is filled
252-
FakeITSTPC = 0x4 }; ///< ITS and TPC parts of the track have different MC labels
252+
FakeITSTPC = 0x4, ///< ITS and TPC parts of the track have different MC labels
253+
HasTRDIn = 0x8 }; ///< parTRDIn is filled
253254
o2::MCCompLabel label{}; ///< MC label of the ITS-TPC part of the seeding track
254255
o2::MCCompLabel labelITS{}; ///< MC label of its ITS part
255256
o2::MCCompLabel labelTPC{}; ///< MC label of its TPC part
256257
o2::track::TrackPar parITSOut{}; ///< truth at x and alpha of TrackData::par, from the nearest ITS track reference (propagated with the material correction, true mass)
257258
o2::track::TrackPar parTPCIn{}; ///< truth at the first TPC track reference (sector frame)
258259
float distITSRef{-1.f}; ///< 3D distance between the ITS track reference used and TrackData::par in cm
259260
float distTPCRef{-1.f}; ///< distance (y,z) between parTPCIn propagated to the innermost TPC cluster of the track and that cluster in cm (large: wrong leg, looper, fake)
261+
o2::track::TrackPar parTRDIn{}; ///< truth at the first TRD track reference (sector frame), TRD-matched seeds only
262+
float yTRD[6] = {}; ///< truth y at the x of the TRD tracklet of each layer (tracklet sector frame), see trdLayerMask
263+
float zTRD[6] = {}; ///< truth z at the x of the TRD tracklet of each layer (tracklet sector frame), see trdLayerMask
264+
uint8_t trdLayerMask{0}; ///< bit i set: yTRD[i], zTRD[i] filled
260265
int pdg{0}; ///< PDG code of the MC particle of the ITS part (TPC part if no ITS label)
261266
uint8_t flags{0};
262267
bool hasITSOut() const { return flags & HasITSOut; }
263268
bool hasTPCIn() const { return flags & HasTPCIn; }
264269
bool isFakeITSTPC() const { return flags & FakeITSTPC; }
265-
ClassDefNV(TrackDataMC, 1);
270+
bool hasTRDIn() const { return flags & HasTRDIn; }
271+
ClassDefNV(TrackDataMC, 2);
266272
};
267273

268274
/// \class TrackInterpolation
@@ -445,6 +451,8 @@ class TrackInterpolation
445451
std::vector<TrackDataCompact>& getTrackDataCompact() { return mTrackDataCompact; }
446452
std::vector<TrackDataExtended>& getTrackDataExtended() { return mTrackDataExtended; }
447453
std::vector<TrackData>& getReferenceTracks() { return mTrackData; }
454+
/// ITS-TPC-TRD track whose tracklets gave the TRD residuals of each stored track (not set if none), aligned with getReferenceTracks()
455+
const std::vector<o2::dataformats::GlobalTrackID>& getTRDGIDsSuccess() const { return mTRDGIDsSuccess; }
448456

449457
void setLane(int lID, int nL)
450458
{
@@ -512,6 +520,7 @@ class TrackInterpolation
512520
// cache
513521
std::array<CacheStruct, constants::MAXGLOBALPADROW> mCache{{}}; ///< caching positions, covariances and angles for track extrapolations and interpolation
514522
std::vector<o2::dataformats::GlobalTrackID> mGIDsSuccess; ///< keep track of the GIDs which could be processed successfully
523+
std::vector<o2::dataformats::GlobalTrackID> mTRDGIDsSuccess; ///< ITS-TPC-TRD track used for the TRD residuals of each stored track (not set if none)
515524

516525
TrackValidationData mTrackValidation;
517526

‎Detectors/TPC/calibration/SpacePoints/src/TrackInterpolation.cxx‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -807,10 +807,12 @@ void TrackInterpolation::interpolateTrack(int iSeed)
807807
}
808808

809809
bool stopPropagation = !mExtDetResid;
810+
GTrackID gidTRDUsed{};
810811
if (!stopPropagation) {
811812
// do we have TRD residuals to add?
812813
trkWork = trkOuter;
813814
if (!allLost && gidTable[GTrackID::TRD].isIndexSet()) { // allLost: trkOuter is not a valid outer param
815+
gidTRDUsed = gidTable[GTrackID::ITSTPCTRD];
814816
const auto& trkTRD = mRecoCont->getITSTPCTRDTrack<o2::trd::TrackTRD>(gidTable[GTrackID::ITSTPCTRD]);
815817
for (int iLayer = 0; iLayer < o2::trd::constants::NLAYER; iLayer++) {
816818
std::array<float, 2> trkltTRDYZ{};
@@ -926,6 +928,7 @@ void TrackInterpolation::interpolateTrack(int iSeed)
926928
}
927929

928930
mGIDsSuccess.push_back(mGIDs[iSeed]);
931+
mTRDGIDsSuccess.push_back(gidTRDUsed);
929932
mTrackDataCompact.emplace_back(trackData.clIdx.getFirstEntry(), trackData.multStack, nClValidated, mGIDs[iSeed].getSource(), trackData.nExtDetResid, trackData.filterFlag);
930933
mTrackData.push_back(std::move(trackData));
931934
stored = true;
@@ -1187,12 +1190,14 @@ void TrackInterpolation::extrapolateTrack(int iSeed)
11871190
}
11881191

11891192
bool stopPropagation = !mExtDetResid;
1193+
GTrackID gidTRDUsed{};
11901194
if (!stopPropagation) {
11911195
// do we have TRD residuals to add?
11921196
int iSeedFull = mParentID[iSeed] == -1 ? iSeed : mParentID[iSeed];
11931197
auto gidFull = mGIDs[iSeedFull];
11941198
const auto& gidTableFull = mGIDtables[iSeedFull];
11951199
if (!refLost && gidTableFull[GTrackID::TRD].isIndexSet()) { // refLost: trkWork did not reach the TPC outer end
1200+
gidTRDUsed = gidTableFull[GTrackID::ITSTPCTRD];
11961201
const auto& trkTRD = mRecoCont->getITSTPCTRDTrack<o2::trd::TrackTRD>(gidTableFull[GTrackID::ITSTPCTRD]);
11971202
trackData.nTrkltsTRD = trkTRD.getNtracklets();
11981203
trackData.chi2TRD = trkTRD.getChi2();
@@ -1319,6 +1324,7 @@ void TrackInterpolation::extrapolateTrack(int iSeed)
13191324
mTrackData.push_back(std::move(trackData));
13201325
stored = true;
13211326
mGIDsSuccess.push_back(mGIDs[iSeed]);
1327+
mTRDGIDsSuccess.push_back(gidTRDUsed);
13221328
mTrackDataCompact.emplace_back(trackData.clIdx.getFirstEntry(), trackData.multStack, nClValidated, mGIDs[iSeed].getSource(), trackData.nExtDetResid, trackData.filterFlag);
13231329
if (mDumpTrackPoints) {
13241330
(*trackDataExtended).clIdx.setEntries(nClValidated);
@@ -1694,6 +1700,7 @@ void TrackInterpolation::reset()
16941700
mClRes.clear();
16951701
mDetInfoRes.clear();
16961702
mGIDsSuccess.clear();
1703+
mTRDGIDsSuccess.clear();
16971704
for (auto& vec : mTrackIndices) {
16981705
vec.clear();
16991706
}

0 commit comments

Comments
 (0)