ATLAS Offline Software
Loading...
Searching...
No Matches
DetailedTrackTruthBuilder.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
9
13
17
18#include "TrkTrack/Track.h"
23
24#include <map>
25#include <queue>
26#include <list>
27#include <limits>
28
29#include <iostream>
30#include <iterator>
31#include <algorithm>
32
33namespace {
34
35 template<class Map> void printMap(const Map& m) {
36 std::cout<<"printMap(): [";
37 for (typename Map::const_iterator i=m.begin(); i!=m.end(); ++i) {
38 std::cout<<"("<<i->first<<","<<i->second<<"), ";
39 }
40 std::cout<<"]"<<std::endl;
41 }
42
43 struct SubDetPRDs {
44 std::set<Identifier> subDetHits[SubDetHitStatistics::NUM_SUBDETECTORS];
45 };
46
47 SubDetPRDs& operator+=(SubDetPRDs& a, const SubDetPRDs& b) {
48 for (unsigned i=0; i<SubDetHitStatistics::NUM_SUBDETECTORS; ++i) {
49 const std::set<Identifier>& bset = b.subDetHits[i];
50 for (std::set<Identifier>::const_iterator pb=bset.begin(); pb!=bset.end(); ++pb) {
51 a.subDetHits[i].insert(*pb);
52 }
53 }
54 return a;
55 }
56
57 SubDetHitStatistics makeSubDetHitStatistics(const SubDetPRDs& prds) {
59 for (unsigned i=0; i<SubDetHitStatistics::NUM_SUBDETECTORS; ++i) {
60 res[SubDetHitStatistics::SubDetType(i)] = prds.subDetHits[i].size();
61 }
62 return res;
63 }
64
65 // Truth trajectory sprouts
66 class Sprout : public std::list<HepMC::ConstGenParticlePtr> {
67 public:
68 SubDetPRDs stat;
69 };
70
71}
72
73
74namespace Trk {
75
76 //================================================================
78 {
79 ATH_CHECK( m_truthTrajBuilder.retrieve() );
80 ATH_CHECK( detStore()->retrieve(m_idHelper, "AtlasID") );
81
82 return StatusCode::SUCCESS;
83 }
84
85 //================================================================
88 const TrackCollection& tracks,
89 const std::vector<const PRD_MultiTruthCollection*>& prdTruth,
90 const EventContext& ctx) const
91 {
92 ATH_MSG_VERBOSE("DetailedTrackTruthBuilder::buildDetailedTrackTruth() ");
93
94 if (!output) { return; }
95
96 //----------------------------------------------------------------
97 // The caller can pass PRD truth collections in any order. Sort them out.
98
99 std::vector<const PRD_MultiTruthCollection*> orderedPRD_Truth(SubDetHitStatistics::NUM_SUBDETECTORS);
100 PRD_InverseTruth inverseTruth;
101
102 for ( const PRD_MultiTruthCollection* prdTruthColl : prdTruth ) {
103 if (prdTruthColl->empty()) {
104 continue;
105 }
106
107 SubDetHitStatistics::SubDetType subdet = findSubDetType(prdTruthColl->begin()->first);
108 ATH_MSG_DEBUG("Assign: "<<prdTruthColl<<" to "<<subdet);
110 orderedPRD_Truth[subdet] = prdTruthColl;
111 makeTruthToRecMap(inverseTruth,*prdTruthColl);
112 } else {
113 ATH_MSG_WARNING("Got unknown SubDetType in prdTruth ");
114 }
115 }
116 ATH_MSG_DEBUG("makeTruthToRecMap filling done");
117
118 //----------------------------------------------------------------
119 // Find associated truth for each track
120
121 for (unsigned itrack=0; itrack<tracks.size(); ++itrack) {
122 ElementLink<DataVector<Trk::Track> > ptrack(tracks, itrack);
123 addTrack(output, ptrack, orderedPRD_Truth, inverseTruth, ctx);
124 }
125
126 // DEBUG
127 // FIXME: in normal production jobs that does *a lot of* formatting only to discard the result...
128 ATH_MSG_DEBUG("Dumping output collection.\n"
129 " Entries with TruthTrajectories of more then one particle shown at the DEBUG level.\n"
130 " Use VERBOSE level for complete dump.");
131
132 for (DetailedTrackTruthCollection::const_iterator i=output->begin(); i!=output->end(); ++i) {
133 bool interesting = (i->second.trajectory().size() > 1);
134
135 msg(interesting ? MSG::DEBUG : MSG::VERBOSE)
136 <<"out: trk="<<i->first.index()<<" => "<<i->second<<endmsg;
137
138 if (interesting) {
139 const TruthTrajectory& t = i->second.trajectory();
140 msg(MSG::VERBOSE)<<"Particles on the trajectory:\n";
141 for (unsigned k=0; k<t.size(); ++k) {
142 msg(MSG::VERBOSE)<<t[k]<<"\n";
143 }
144 msg(MSG::VERBOSE)<<"\n"<<endmsg;
145 }
146
147 }
148
149 }
150
151
152 //================================================================
153 // Plagiarized from
154 // Tracking/TrkTools/TrkTruthCreatorTools/src/TrackTruthMaker.cxx
155 // (no way to reuse its private function PrepRawDataCollectionType() )
156
159 if (m_idHelper->is_pixel(id))
161 if (m_idHelper->is_sct(id))
163 if (m_idHelper->is_trt(id))
165 if (m_idHelper->is_mdt(id))
167 if (m_idHelper->is_rpc(id))
169 if (m_idHelper->is_tgc(id))
171 if (m_idHelper->is_stgc(id))
173 if (m_idHelper->is_mm(id))
175 if (m_idHelper->is_csc(id))
177
178
179 ATH_MSG_WARNING("findSubDetType(): UNKNOWN subdet for id="<<id);
180
182 }
183
184 namespace {
185 class ExtendedEventIndex {
186 public:
187 ExtendedEventIndex(const HepMcParticleLink &source, IProxyDict *proxy)
188 : m_eventIndex(source.eventIndex()),
189 m_isPosition(m_eventIndex == HepMcParticleLink::ExtendedBarCode::UNDEFINED)
190 {
191 if (m_isPosition) {
192 m_eventIndex = source.getEventPositionInCollection(proxy);
193 }
194 }
195
196 HepMcParticleLink makeLink(HepMcParticleLink::barcode_type other_particle_id, IProxyDict *proxy) {
197 return {other_particle_id, m_eventIndex, (m_isPosition ? HepMcParticleLink::IS_POSITION : HepMcParticleLink::IS_EVENTNUM ), HepMcParticleLink::IS_ID, proxy};
198 }
199
200 private:
202 bool m_isPosition;
203 };
204 }
205
206 //================================================================
208 const ElementLink<DataVector<Trk::Track> > &trackLink,
209 const std::vector<const PRD_MultiTruthCollection*>& orderedPRD_Truth,
210 const PRD_InverseTruth& inverseTruth,
211 const EventContext& ctx) const
212 {
213 const Trk::Track& track{**trackLink};
214 SubDetHitStatistics trackStat;
215 std::map<HepMcParticleLink,SubDetPRDs> pairStat; // stats for (track,GenParticle) for the current track
216 IProxyDict *proxy=ctx.getExtension<Atlas::ExtendedEventContext>().proxy();
217 //----------------------------------------------------------------
218 // loop over the RIO_OnTrack
219 for (const Trk::MeasurementBase* measurement : *track.measurementsOnTrack()) {
220 // not all MB are necessarily ROTs.
221 const Trk::RIO_OnTrack * riontrack = dynamic_cast<const Trk::RIO_OnTrack*>(measurement);
222
223 if (!riontrack) { // handle CompetingRIOsOnTrack case
224 const Trk::CompetingRIOsOnTrack* competing = dynamic_cast<const Trk::CompetingRIOsOnTrack*>(measurement);
225 if (competing) {
226 riontrack = & competing->rioOnTrack( competing->indexOfMaxAssignProb() );
227 }
228 }
229 if (!riontrack){
230 continue;
231 }
232 ATH_MSG_VERBOSE("Process ROT "<<(*riontrack));
233
234 // get the PrepRawData from the RIO_OnTrack
235 const Trk::PrepRawData* prd = riontrack->prepRawData();
236 if (!prd) {
237 ATH_MSG_WARNING("ROT without prd found...");
238 continue;
239 }
240 const Identifier& id = prd->identify();
242
244 ATH_MSG_WARNING("Invalid detector id "<<id);
245 continue;
246 }
247 if (!orderedPRD_Truth[subdet]) {
248 ATH_MSG_VERBOSE("No truth collection registered for "<<subdet);
249 continue;
250 }
251
252 ++trackStat[subdet];
253
254 using iprdt = PRD_MultiTruthCollection::const_iterator;
255 std::pair<iprdt, iprdt> range = orderedPRD_Truth[subdet]->equal_range(id);
256
257 int n=0;
258 // Loop over particles contributing to this cluster
259 for (iprdt i = range.first; i!= range.second; ++i) {
260 HepMC::ConstGenParticlePtr pa = (*i).second.cptr();
261 if (!pa) {
262 continue;
263 }
264
265 if (!i->second.isValid()) {
266 ATH_MSG_WARNING("Unexpected invalid HepMcParticleLink in PRD_MultiTruthCollection");
267 continue;
268 }
269 pairStat[i->second].subDetHits[subdet].insert(id);
270 ++n;
271 ATH_MSG_VERBOSE("PRD-ID:"<<id<<" subdet:"<<subdet<<" number:"<<n<<" particle link:"<<i->second);
272 }
273 if (n == 0) {
274 ATH_MSG_VERBOSE("--> no link, noise ? PRD-ID:"<<id<<" subdet:"<<subdet);
275 // add id 0 to pairs, we like to keep track of fake fakes
276 unsigned int UID(HepMC::UNDEFINED_ID);
277 unsigned int EV(0);
278 pairStat[HepMcParticleLink(UID,EV,HepMcParticleLink::IS_EVENTNUM,HepMcParticleLink::IS_ID)].subDetHits[subdet].insert(id);
279 }
280
281 } // Loop over measurements
282
283 if (msgLvl(MSG::VERBOSE)) {
284 msg(MSG::VERBOSE)<<"PRD truth particles = ";
285 for (std::map<HepMcParticleLink,SubDetPRDs>::const_iterator i=pairStat.begin(); i!=pairStat.end(); ++i) {
286 msg(MSG::VERBOSE)<<i->first<<",";
287 }
288 msg(MSG::VERBOSE)<<endmsg;
289 }
290
291 ATH_MSG_VERBOSE("Construct the stat structures....");
292 //----------------------------------------------------------------
293 // The stat structures are ready.
294 // Build truth trajectories for the track
295
296 std::set<HepMcParticleLink> seeds;
297 for (std::map<HepMcParticleLink,SubDetPRDs>::const_iterator i=pairStat.begin(); i!=pairStat.end(); ++i) {
298 if (i->first.isValid()) {
299 seeds.insert(i->first);
300 }
301 else {
302 // add id 0 particles, we like to keep track of fake fakes
303 TruthTrajectory traj;
304 traj.reserve(1);
305 traj.push_back(i->first);
306 ATH_MSG_VERBOSE("addTrack(): add id 0 hits (noise ?) to DetailedTrackTruthCollection.");
307
308 // noise/no truth hits on this track
309 SubDetHitStatistics noiseStat = makeSubDetHitStatistics(i->second);
310
311 // Only valid HepMcParticleLink make it into seeds and then into sprouts, and
312 // stored in the loop over sprouts below.
313 // Store output for noise/no truth particles here.
314 output->insert(std::make_pair(trackLink,
316 noiseStat,
317 trackStat,
318 noiseStat) ));
319 }
320 }
321
322 // Grow sprouts from the seeds
323 using SproutMap = std::map<HepMcParticleLink, Sprout>;
324 SproutMap sprouts;
325 while (!seeds.empty() ) {
326 ATH_MSG_VERBOSE("Remaining seeds in set: "<<seeds.size());
327 HepMcParticleLink link = *seeds.begin();
328 Sprout current_sprout;
329 std::queue<HepMC::ConstGenParticlePtr> tmp;
330 ExtendedEventIndex eventIndex(link, proxy);
331 HepMC::ConstGenParticlePtr current = link.cptr();
332 ATH_MSG_VERBOSE("Check link: "<<link);
333 const auto truthSuppressionStatus = link.getTruthSuppressionType();
334
335 unsigned nAncestor{0};
336 do {
337 HepMcParticleLink curlink( eventIndex.makeLink(HepMC::uniqueID(current), proxy));
338 curlink.setTruthSuppressionType(truthSuppressionStatus);
340 if (!nAncestor && !seeds.count(curlink)) {
341 ATH_MSG_WARNING("The first link should always point to the object itself.\nHowever "<<
342 link<<"=="<<curlink<<"\n evaluates to " <<(curlink==link)<<", getTruthSuppressionType: "
344 <<", id:"<<(curlink.id() == link.id())
345 <<", eventIndex: "<<(curlink.eventIndex() == link.eventIndex()));
346 ATH_MSG_WARNING("Remove the link itself from the set");
347 seeds.erase(link);
348
349 }
350 // remove the current particle from the list of particles to consider (if it is still there)
351 seeds.erase(curlink);
352
353 // Have we worked on this particle before?
354 SproutMap::iterator p_old = sprouts.find(curlink);
355 if (p_old != sprouts.end()) {
356 //merge the old sprout with the current one.
357 current_sprout.splice(current_sprout.end(), p_old->second);
358 current_sprout.stat += p_old->second.stat;
359 // and remove the entry for the old
360 sprouts.erase(p_old);
361 break; // the do-while(getMother()) loop
362 }
363 // No, this is a new particle. Try to extend the current truth trajectory.
364
365 // Add the particle to the current truth trajectory.
366 // New: with the current stricter cuts on mother-daughter
367 // we don't have to require that ancestors produce hits.
368
369 current_sprout.push_back(current);
370
371 std::map<HepMcParticleLink,SubDetPRDs>::iterator p_newstat = pairStat.find(curlink);
372 if (p_newstat != pairStat.end()) {
373 current_sprout.stat += p_newstat->second;
374 }
375
376
377 } while ( (current = m_truthTrajBuilder->getMother(current)) && ++nAncestor);
378
379 // Add the grown sprout to the list
380 sprouts.insert(std::make_pair(link, current_sprout));
381
382 } // while(!seeds.empty())
383
384 //----------------
385 // All seeds have been processed, and the upstream extensions of the
386 // sprouts are done. Extend the sprouts downstream to get the final
387 // truth trajectories and store the result.
388 //
389 // Note: so far the "sprouts" object mapped {last particle ==> sprout}
390 // Extending a sprout downstream will break this relationship,
391 // but at this point we don't care about it and will only use the
392 // value of the map, not the key.
393
394 for (SproutMap::iterator s=sprouts.begin(); s!=sprouts.end(); ++s) {
395
396 // Attempt to extend the TruthTrajectory sprout to the "outside".
397 // This may add only hits that are *not* on the current track.
398 // Thus no need to update stats track and stats common.
399
400 auto current = *s->second.begin();
401 while( (current = m_truthTrajBuilder->getDaughter(current)) ) {
402 s->second.push_front(current);
403 }
404
405 // Now we have info to build the final TruthTrajectory.
406 // FIXME: what is the current average size?
407 TruthTrajectory traj;
408 traj.reserve(2); // The average size is about 1.05. Hardcode that instead of using slow list::size().
409 for (Sprout::const_iterator ppart=s->second.begin(); ppart!=s->second.end(); ++ppart) {
410 traj.push_back(HepMcParticleLink(ExtendedEventIndex(s->first, proxy).makeLink(HepMC::uniqueID(*ppart), proxy)));
411 }
412
413 // Count PRDs on the TruthTrajectory
414 SubDetHitStatistics truthStat = countPRDsOnTruth(traj, inverseTruth);
415
416 ATH_MSG_VERBOSE("addTrack(): sprout length = "<<traj.size());
417 output->insert(std::make_pair(trackLink,
419 makeSubDetHitStatistics(s->second.stat),
420 trackStat,
421 truthStat) ));
422 }
423
424
425 ATH_MSG_VERBOSE("addTrack(): #sprouts = "<<sprouts.size()<<", output->size() = "<<output->size());
426 }
427 //================================================================
429 // invert the map from Identifier (reco hit) to HepMcParticleLink,
430 // to allow lookup of all Identifiers produced by a given HepMcParticleLink.
431 // the result is only used in countPRDsOnTruth. since that code ignores
432 // geantinos, don't bother to sort the geantinos here.
433 for ( const auto& i : rec2truth ) {
434 // i.first = Identifier
435 // i.second = HepMcParticleLink
436 auto pa = i.second.cptr();
437 if ( !pa ) { // skip noise
438 continue;
439 }
440 ATH_MSG_VERBOSE("Check geantino "<<MC::isGeantino(pa)<<", is_truth_suppressed_pileup:"
442
443 if ( MC::isGeantino(pa) && HepMC::is_truth_suppressed_pileup(i.second) ) {
444 continue;
445 } // skip geantinos
446 result.insert(std::make_pair(i.second, i.first));
447 }
448 }
449
450 //================================================================
452 const PRD_InverseTruth& inverseTruth) const
453 {
454 // Different particles from the same TruthTrajectory can contribute to the same cluster.
455 // We should be careful to avoid double-counting in such cases.
456
457
458 SubDetPRDs prds;
459 for (TruthTrajectory::const_iterator p = traj.begin(); p != traj.end(); ++p) {
460 // if this is a geantino (pile-up truth reduction), then we
461 // would sum over hits from all particles that arise from this
462 // pile-up collision. the result is useless. don't do it. in
463 // release 20, geantinos have pdg_id==999
464 if (!(*p).cptr()) {
465 ATH_MSG_WARNING( "HepMcParticleLink " << *p << " in truth trajectory does not point to a valid GenParticle.");
466 continue;
467 }
468 if ( MC::isGeantino(*p) ) { continue; }
469 using iter = PRD_InverseTruth::const_iterator;
470 std::pair<iter,iter> range = inverseTruth.equal_range(*p);
471 for (iter i = range.first; i != range.second; ++i) {
473
474 if (subdet<SubDetHitStatistics::NUM_SUBDETECTORS) prds.subDetHits[subdet].insert(i->second);
475 }
476 }
477
478 return makeSubDetHitStatistics(prds);
479 }
480
481 //================================================================
482
483} // namespace Trk
#define endmsg
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
An STL vector of pointers that by default owns its pointed-to elements.
ATLAS-specific HepMC functions.
std::pair< std::vector< unsigned int >, bool > res
static Double_t a
DataVector< Trk::Track > TrackCollection
This typedef represents a collection of Trk::Track objects.
Derived DataVector<T>.
Definition DataVector.h:795
size_type size() const noexcept
Returns the number of elements in the collection.
A PRD is mapped onto all contributing particles.
Base class for all CompetingRIOsOnTack implementations, extends the common MeasurementBase.
unsigned int indexOfMaxAssignProb() const
Index of the ROT with the highest assignment probability.
virtual const RIO_OnTrack & rioOnTrack(unsigned int) const =0
returns the RIO_OnTrack (also known as ROT) objects depending on the integer.
PublicToolHandle< Trk::ITruthTrajectoryBuilder > m_truthTrajBuilder
virtual void buildDetailedTrackTruth(DetailedTrackTruthCollection *output, const TrackCollection &tracks, const std::vector< const PRD_MultiTruthCollection * > &prdTruth, const EventContext &ctx) const override
See description for IDetailedTrackTruthBuilder::buildDetailedTrackTruth()
InverseMultiMap< PRD_MultiTruthCollection > PRD_InverseTruth
SubDetHitStatistics::SubDetType findSubDetType(const Identifier &id) const
void makeTruthToRecMap(PRD_InverseTruth &result, const PRD_MultiTruthCollection &rec2truth) const
SubDetHitStatistics countPRDsOnTruth(const TruthTrajectory &traj, const PRD_InverseTruth &inverseTruth) const
virtual StatusCode initialize() override
void addTrack(DetailedTrackTruthCollection *output, const ElementLink< DataVector< Trk::Track > > &track, const std::vector< const PRD_MultiTruthCollection * > &orderedPRD_Truth, const PRD_InverseTruth &inverseTruth, const EventContext &ctx) const
This class is the pure abstract base class for all fittable tracking measurements.
Identifier identify() const
return the identifier
Class to handle RIO On Tracks ROT) for InDet and Muons, it inherits from the common MeasurementBase.
Definition RIO_OnTrack.h:70
virtual const Trk::PrepRawData * prepRawData() const =0
returns the PrepRawData (also known as RIO) object to which this RIO_OnTrack is associated.
A TruthTrajectory is a chain of charged MC particles connected through the mother-daughter relationsh...
int uniqueID(const T &p)
constexpr int UNDEFINED_ID
bool is_truth_suppressed_pileup(const T &p)
Method to establish if a particle (or barcode) corresponds to truth-suppressed pile-up (TODO update t...
const GenParticle * ConstGenParticlePtr
Definition GenParticle.h:38
bool isGeantino(const T &p)
Ensure that the ATLAS eigen extensions are properly loaded.
ElementLink< T > makeLink(const SG::View *view, const SG::ReadHandle< T > &handle, size_t index)
Create EL to a collection in view.
Definition ViewHelper.h:309
MsgStream & msg
Definition testRead.cxx:32