Skip to content

Commit d745182

Browse files
TPC SCD: MC origin of the residual tracks (mother, production vertex, sister tracks)
For the particle of the ITS-TPC part TrackDataMC now holds the mother label and PDG code (for primaries the generator-level parent), the production vertex, momentum and process, a primary flag, and sisterIdx: the index of another stored track with the same mother (cycling through all of them if more than two), e.g. to select both daughters of a K0s. pdg is now the PDG code of the particle of the ITS-TPC part, consistent with the origin and TRD fields. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent e869868 commit d745182

2 files changed

Lines changed: 55 additions & 10 deletions

File tree

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

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -178,15 +178,16 @@ void TPCInterpolationDPL::fillMCTruth(const RecoContainer& recoData)
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
180180
// 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)
181+
// reference in time, in the sector frame), for tracks with TRD residuals the truth at the TRD entrance and the true
182+
// positions at the x of the TRD tracklets of the track (ideal tracklets), and the origin of the particle of the ITS-TPC
183+
// part (mother, production vertex and process, other stored tracks with the same mother)
183184
const auto& trkData = mInterpolation.getReferenceTracks();
184185
mTrackDataMC.clear();
185186
mTrackDataMC.resize(trkData.size());
186187
struct Lookup {
187188
o2::MCCompLabel lbl{};
188189
uint32_t idx{0};
189-
uint8_t kind{0}; // 0: ITS outer, 1: TPC entrance, 2: TRD
190+
uint8_t kind{0}; // 0: ITS outer, 1: TPC entrance, 2: TRD, 3: origin
190191
};
191192
std::vector<Lookup> lookups;
192193
lookups.reserve(2 * trkData.size());
@@ -217,6 +218,9 @@ void TPCInterpolationDPL::fillMCTruth(const RecoContainer& recoData)
217218
if (mInterpolation.getTRDGIDsSuccess()[i].isIndexSet() && lblTPC.isValid()) { // track with TRD residuals: the true particle of the ITS-TPC part at the TRD
218219
lookups.push_back({mc.label.isValid() ? mc.label : lblTPC, uint32_t(i), 2});
219220
}
221+
if (lblTPC.isValid()) { // origin of the true particle of the ITS-TPC part
222+
lookups.push_back({mc.label.isValid() ? mc.label : lblTPC, uint32_t(i), 3});
223+
}
220224
}
221225
// the reader loads the kinematics of a whole event (can be >100 MB): process event by event and release it right after
222226
std::sort(lookups.begin(), lookups.end(), [](const Lookup& a, const Lookup& b) {
@@ -270,7 +274,6 @@ void TPCInterpolationDPL::fillMCTruth(const RecoContainer& recoData)
270274
int charge = pPDG ? int(std::lround(pPDG->Charge() / 3.)) : 0; // TParticlePDG charge is in units of |e|/3
271275
auto refs = mMCReader->getTrackRefs(lbl.getSourceID(), lbl.getEventID(), lbl.getTrackID());
272276
if (lk.kind == 0) { // ITS outer: track reference of the ITS part nearest to TrackData::par
273-
mc.pdg = pdg;
274277
const o2::TrackReference* best = nullptr;
275278
float bestD2 = 1e30f;
276279
auto xyzReco = trk.par.getXYZGlo();
@@ -296,9 +299,6 @@ void TPCInterpolationDPL::fillMCTruth(const RecoContainer& recoData)
296299
}
297300
}
298301
} else if (lk.kind == 1) { // TPC entrance: first TPC track reference in time of the TPC part
299-
if (!mc.labelITS.isValid() && !mc.label.isValid()) {
300-
mc.pdg = pdg; // no ITS lookup for this track
301-
}
302302
const o2::TrackReference* first = nullptr;
303303
for (const auto& ref : refs) {
304304
if (ref.getDetectorId() == DetID::TPC && (!first || ref.getTime() < first->getTime())) {
@@ -325,6 +325,27 @@ void TPCInterpolationDPL::fillMCTruth(const RecoContainer& recoData)
325325
}
326326
}
327327
}
328+
} else if (lk.kind == 3) { // origin: mother, production vertex and process
329+
if (!mcTrk) {
330+
continue;
331+
}
332+
mc.pdg = pdg;
333+
if (mcTrk->isPrimary()) {
334+
mc.flags |= TrackDataMC::IsPrimary;
335+
}
336+
mc.process = mcTrk->getProcess();
337+
mc.prodX = mcTrk->GetStartVertexCoordinatesX();
338+
mc.prodY = mcTrk->GetStartVertexCoordinatesY();
339+
mc.prodZ = mcTrk->GetStartVertexCoordinatesZ();
340+
mc.prodPx = mcTrk->GetStartVertexMomentumX();
341+
mc.prodPy = mcTrk->GetStartVertexMomentumY();
342+
mc.prodPz = mcTrk->GetStartVertexMomentumZ();
343+
int motherId = mcTrk->getMotherTrackId();
344+
if (motherId >= 0) {
345+
mc.motherLabel = o2::MCCompLabel(motherId, lbl.getEventID(), lbl.getSourceID());
346+
const auto* mother = mMCReader->getTrack(lbl.getSourceID(), lbl.getEventID(), motherId);
347+
mc.motherPdg = mother ? mother->GetPdgCode() : 0;
348+
}
328349
} else if (charge) { // TRD: entrance (first TRD track reference in time) and the true positions at the tracklet x of each layer
329350
const o2::TrackReference* first = nullptr;
330351
for (const auto& ref : refs) {
@@ -380,6 +401,18 @@ void TPCInterpolationDPL::fillMCTruth(const RecoContainer& recoData)
380401
if (curSrc >= 0) {
381402
mMCReader->releaseTracksForSourceAndEvent(curSrc, curEv);
382403
}
404+
// stored tracks with the same mother (e.g. both daughters of a K0s): each points to the next one, cyclically
405+
std::unordered_map<uint64_t, std::vector<uint32_t>> daughters;
406+
for (uint32_t i = 0; i < mTrackDataMC.size(); ++i) {
407+
if (mTrackDataMC[i].motherLabel.isSet()) {
408+
daughters[mTrackDataMC[i].motherLabel.getTrackEventSourceID()].push_back(i);
409+
}
410+
}
411+
for (const auto& [mother, idx] : daughters) {
412+
for (size_t k = 0; idx.size() > 1 && k < idx.size(); ++k) {
413+
mTrackDataMC[idx[k]].sisterIdx = idx[(k + 1) % idx.size()];
414+
}
415+
}
383416
}
384417

385418
void TPCInterpolationDPL::endOfStream(EndOfStreamContext& ec)

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

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,8 @@ struct TrackDataMC {
250250
enum Flags : uint8_t { HasITSOut = 0x1, ///< parITSOut is filled
251251
HasTPCIn = 0x2, ///< parTPCIn is filled
252252
FakeITSTPC = 0x4, ///< ITS and TPC parts of the track have different MC labels
253-
HasTRDIn = 0x8 }; ///< parTRDIn is filled
253+
HasTRDIn = 0x8, ///< parTRDIn is filled
254+
IsPrimary = 0x10 }; ///< the particle of the ITS-TPC part is a primary (MCTrack::isPrimary)
254255
o2::MCCompLabel label{}; ///< MC label of the ITS-TPC part of the seeding track
255256
o2::MCCompLabel labelITS{}; ///< MC label of its ITS part
256257
o2::MCCompLabel labelTPC{}; ///< MC label of its TPC part
@@ -262,13 +263,24 @@ struct TrackDataMC {
262263
float yTRD[6] = {}; ///< truth y at the x of the TRD tracklet of each layer (tracklet sector frame), see trdLayerMask
263264
float zTRD[6] = {}; ///< truth z at the x of the TRD tracklet of each layer (tracklet sector frame), see trdLayerMask
264265
uint8_t trdLayerMask{0}; ///< bit i set: yTRD[i], zTRD[i] filled
265-
int pdg{0}; ///< PDG code of the MC particle of the ITS part (TPC part if no ITS label)
266+
int pdg{0}; ///< PDG code of the particle of the ITS-TPC part (as for the origin and TRD fields)
267+
o2::MCCompLabel motherLabel{}; ///< MC label of the mother of the particle of the ITS-TPC part (for primaries the generator-level parent)
268+
int motherPdg{0}; ///< PDG code of that mother (0: none)
269+
float prodX{0.f}; ///< production vertex x of the particle of the ITS-TPC part (global, cm)
270+
float prodY{0.f}; ///< production vertex y (global, cm)
271+
float prodZ{0.f}; ///< production vertex z (global, cm)
272+
float prodPx{0.f}; ///< momentum at production x (global, GeV/c), e.g. to compare a track propagated to the vertex
273+
float prodPy{0.f}; ///< momentum at production y (global, GeV/c)
274+
float prodPz{0.f}; ///< momentum at production z (global, GeV/c)
275+
int sisterIdx{-1}; ///< index in the TrackData vector of another stored track with the same mother (cycling through all of them if more than two), -1: none
276+
uint8_t process{0}; ///< production process of the particle of the ITS-TPC part (TMCProcess)
266277
uint8_t flags{0};
267278
bool hasITSOut() const { return flags & HasITSOut; }
268279
bool hasTPCIn() const { return flags & HasTPCIn; }
269280
bool isFakeITSTPC() const { return flags & FakeITSTPC; }
270281
bool hasTRDIn() const { return flags & HasTRDIn; }
271-
ClassDefNV(TrackDataMC, 2);
282+
bool isPrimary() const { return flags & IsPrimary; }
283+
ClassDefNV(TrackDataMC, 3);
272284
};
273285

274286
/// \class TrackInterpolation

0 commit comments

Comments
 (0)