ATLAS Offline Software
Loading...
Searching...
No Matches
InDetVertexTruthMatchTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
3*/
4
6
9
11using namespace InDetVertexTruthMatchUtils;
12
14 declareProperty("trackMatchProb", m_trkMatchProb = 0.5 );
15 declareProperty("vertexMatchWeight", m_vxMatchWeight = 0.7 );
16 declareProperty("trackPtCut", m_trkPtCut = 500. );
17}
18
20 ATH_MSG_INFO("Initializing");
21
22 return StatusCode::SUCCESS;
23}
24
26{
27 if (m_nBadLinks>0) {
28 ATH_MSG_INFO("Vertex fraction with invalid track particle links: " << std::setw(8) << static_cast<double>(m_nVtxWithBadLinks) / m_nVtx << "; invalid track particle link fraction " << static_cast<double>(m_nBadLinks) / m_nLinks << ".");
29 }
30 return StatusCode::SUCCESS;
31}
32
33namespace {
34//Helper methods for this file only
35
36//output typedef
37// this is defined like this in InDetTruthMatchUtils:
38// typedef std::pair<ElementLink<xAOD::TruthEventBaseContainer>, float> VertexTruthMatchInfo;
39// std::pair<ElementLink<>, T> is special templated pair in ElementLink.h even
40// pair of link to a truth event with relative weight of matched tracks
41
42
43// Create a truth map by decoarting truth particles with a back link to the truth event they live in
44// Needed because the track->truth assoc gives us the particles but they don't store event normally
45// Add as decoration to avoid full loop for every track ( this time only once per event )
46// Use a vector so any number of truth event collections can be used at once -- but the pointers need to be valid
47void createTruthMap(const std::vector<const xAOD::TruthEventBaseContainer *> & truthEventContainers ) {
48
49 static const xAOD::TruthParticle::Decorator<ElementLink<xAOD::TruthEventBaseContainer> > backLinkDecor("TruthEventLink");
50
51 for ( auto cit : truthEventContainers ) {
52
53 const xAOD::TruthEventBaseContainer & truthEvents = *cit;
54
55 for ( size_t i = 0; i < truthEvents.size(); ++i) {
56
57 for ( auto & tkit : truthEvents[i]->truthParticleLinks() ) { //std::vector<ElementLink...
58
60
61 if (elLink.isValid() && tkit.isValid()) {
62 backLinkDecor(**tkit) = elLink;
63 }
64
65 }
66
67 }
68
69 }
70
71}
72
73void createTrackTruthMap(const std::vector<const xAOD::TruthEventBaseContainer *> & truthEventContainers,
74 const xAOD::TrackParticleContainer & trackParticleContainer,
75 float matchCut)
76{
77
78 createTruthMap(truthEventContainers);
79
81 xAOD::TrackParticle::ConstAccessor<float> trk_truthProbAcc("truthMatchProbability");
82 static const xAOD::TruthParticle::Decorator<ElementLink<xAOD::TruthEventBaseContainer> > backLinkDecor("TruthEventLink");
83 static const xAOD::TrackParticle::Decorator<ElementLink<xAOD::TruthEventBaseContainer> > trackLinkDecor("TrackEventLink");
84
85
86 for (auto trk : trackParticleContainer)
87 {
88 {
89 if (trk_truthPartAcc.isAvailable(*trk) && trk_truthProbAcc.isAvailable(*trk)
90 && trk_truthPartAcc(*trk).isValid() && trk_truthProbAcc(*trk) >= matchCut)
91 {
92 const auto& truthParticle = trk_truthPartAcc(*trk);
93 if (backLinkDecor.isAvailable(**truthParticle) && backLinkDecor(**truthParticle).isValid())
94 {
95 trackLinkDecor(*trk) = backLinkDecor(**truthParticle);
96 }
97 }
98 }
99 }
100}
101
102//In the vector of match info, find the element corresponding to link and return its index; create a new one if necessary
103size_t indexOfMatchInfo( std::vector<VertexTruthMatchInfo> & matches, ElementLink<xAOD::TruthEventBaseContainer> & link ) {
104 for ( size_t i = 0; i < matches.size(); ++i ) {
105 if ( link.key() == std::get<0>(matches[i]).key() && link.index() == std::get<0>(matches[i]).index() )
106 return i;
107 }
108 // This is the first time we've seen this truth vertex, so make a new entry
109 matches.emplace_back( link, 0., 0. );
110 return matches.size() - 1;
111}
112
113
114//for sorting the container -> highest relative match weight first
115bool compareMatchPair(const VertexTruthMatchInfo& a, const VertexTruthMatchInfo& b ) { return std::get<1>(a) > std::get<1>(b); }
116
117}
118
119
122{
123 for (auto vtx : vxContainer)
124 {
125 for (const ElementLink<xAOD::TrackParticleContainer>& tpLink : vtx->trackParticleLinks())
126 {
127 if (tpLink.isValid())
128 {
129 return tpLink.getStorableObjectPointer();
130 }
131 }
132 }
133 return nullptr;
134}
135
137
138 ATH_MSG_DEBUG("Start vertex matching");
139 if (vxContainer.empty() || // reject empty vertex containers
140 (vxContainer.size() == 1 && vxContainer.at(0)->vertexType() == xAOD::VxType::NoVtx)){ // as well as containers containing only a dummy vertex
141 ATH_MSG_DEBUG("No vertices to match.");
142 return StatusCode::SUCCESS;
143 }
144 // Identify MC vertices to match to -- this is the collection for hard scatter
145 const xAOD::TruthEventBaseContainer * truthEvents = nullptr;
146 if ( evtStore()->contains<xAOD::TruthEventBaseContainer>( "TruthEvents" ) )
147 ATH_CHECK( evtStore()->retrieve( truthEvents, "TruthEvents" ) );
148 else
149 ATH_CHECK( evtStore()->retrieve( truthEvents, "TruthEvent" ) );
150
151 std::vector<const xAOD::TruthEventBaseContainer *> truthContainers;
152 truthContainers.push_back( truthEvents );
153
154 ATH_MSG_DEBUG("Found Hard Scatter collection");
155
156 // These are the pile-up truth -- don't want to fail if they don't exist
157 const xAOD::TruthEventBaseContainer * truthPileup = nullptr;
158 if ( evtStore()->contains<xAOD::TruthEventBaseContainer>( "TruthPileupEvents" ) )
159 ATH_CHECK( evtStore()->retrieve( truthPileup, "TruthPileupEvents" ) );
160 if (truthPileup)
161 truthContainers.push_back( truthPileup );
162
163 ATH_MSG_DEBUG("Found Pileup collection");
164
165 // Find the trackParticle container associated with our reconstructed vertices
166 // We could pass this, but it would break the original interface...
167 const xAOD::TrackParticleContainer* tkContainer = findTrackParticleContainer(vxContainer);
168 if (!tkContainer)
169 {
170 ATH_MSG_WARNING("Vertex container has no vertices with valid TrackParticle links");
171 return StatusCode::SUCCESS;
172 }
173
174 ATH_MSG_DEBUG("Found track collection");
175
176 // create the particle links to events to avoid excessive looping
177 // also decorate reconstructed tracks passing selection with truthEvent links
178 createTrackTruthMap( truthContainers, *tkContainer, m_trkMatchProb );
179
180 // Accessor for the links we just created
182
183 //setup decorators for truth matching info
184 static const xAOD::Vertex::Decorator<std::vector<VertexTruthMatchInfo> > matchInfoDecor("TruthEventMatchingInfos");
185 static const xAOD::Vertex::Decorator<std::vector<VertexTruthMatchInfo> > rawMatchInfoDecor("TruthEventRawMatchingInfos");
186 static const xAOD::Vertex::Decorator<VertexMatchType> matchTypeDecor("VertexMatchType");
187 static const xAOD::Vertex::Decorator<std::vector<ElementLink<xAOD::VertexContainer> > > splitPartnerDecor("SplitPartners");
188 static const xAOD::Vertex::Decorator<int> nHSTrkDecor("nHSTrk");
189
190 //setup accessors
191 // can switch to built in method in xAOD::Vertex once don't have to deal with changing names anymore
193 xAOD::Vertex::ConstAccessor<std::vector<float> > weightAcc("trackWeights");
194
196 xAOD::TrackParticle::ConstAccessor<float> trk_truthProbAcc("truthMatchProbability");
197
198 static const xAOD::TrackParticle::Decorator<ElementLink<xAOD::VertexContainer> > trk_recoVtx("RecoVertex");
199 static const xAOD::TrackParticle::Decorator<float> trk_wtVtx("WeightVertex");
200
201 //some variables to store
202 size_t ntracks;
204
205 ATH_MSG_DEBUG("Starting Loop on Vertices");
206
207 //=============================================================================
208 //First loop over vertices: get tracks, then TruthParticles, and store relative
209 //weights of contribution from each TruthEvent
210 //=============================================================================
211 size_t vxEntry = 0;
212 unsigned int n_bad_links = 0;
213 unsigned int n_links = 0;
214 unsigned int n_vx_with_bad_links = 0;
215
216 for ( auto vxit : vxContainer.stdcont() ) {
217 vxEntry++;
218 vxType = static_cast<xAOD::VxType::VertexType>( vxit->vertexType() );
219 if (vxType == xAOD::VxType::NoVtx) {
220 //skip dummy vertices -> match info will be empty vector if someone tries to access later
221 //type will be set to dummy
222 ATH_MSG_DEBUG("FOUND xAOD::VxType::NoVtx");
223 continue;
224 }
225
226
227 //create the vector we will add as matching info decoration later
228 std::vector<VertexTruthMatchInfo> matchinfo;
229 std::vector<VertexTruthMatchInfo> rawMatchinfo; //not normalized to one for each reco vertex
230
231 //if don't have track particles
232 if (!trkAcc.isAvailable(*vxit) || !weightAcc.isAvailable(*vxit) ) {
233 ATH_MSG_DEBUG("trackParticles or trackWeights not available, setting fake");
234 // Add invalid link for fakes
235 matchinfo.emplace_back( ElementLink<xAOD::TruthEventBaseContainer>(), 1., 0. );
236 matchInfoDecor( *vxit ) = matchinfo;
237 rawMatchinfo.emplace_back( ElementLink<xAOD::TruthEventBaseContainer>(), 1., 0. );
238 rawMatchInfoDecor( *vxit ) = rawMatchinfo;
239 nHSTrkDecor( *vxit ) = 0;
240 continue;
241 }
242
243 //things we need to do the matching
244 const xAOD::Vertex::TrackParticleLinks_t & trkParts = trkAcc( *vxit );
245 ntracks = trkParts.size();
246 const std::vector<float> & trkWeights = weightAcc( *vxit );
247
248 //double check
249 if ( trkWeights.size() != ntracks ) {
250 ATH_MSG_DEBUG("Vertex without same number of tracks and trackWeights, setting fake");
251 matchinfo.emplace_back( ElementLink<xAOD::TruthEventBaseContainer>(), 1., 0. );
252 matchInfoDecor( *vxit ) = matchinfo;
253 rawMatchinfo.emplace_back( ElementLink<xAOD::TruthEventBaseContainer>(), 1., 0. );
254 rawMatchInfoDecor( *vxit ) = rawMatchinfo;
255 nHSTrkDecor( *vxit ) = 0;
256 continue;
257 }
258
259 ATH_MSG_DEBUG("Matching new vertex at (" << vxit->x() << ", " << vxit->y() << ", " << vxit->z() << ")" << " with " << ntracks << " tracks, at index: " << vxit->index());
260
261 float totalWeight = 0.;
262 float totalFake = 0.;
263 int nHSTrk = 0;
264
265 unsigned vx_n_bad_links = 0;
266 //loop element link to track particle
267 for ( size_t t = 0; t < ntracks; ++t ) {
268 if (!trkParts[t].isValid()) {
269 ++vx_n_bad_links;
270 continue;
271 }
272 const xAOD::TrackParticle & trk = **trkParts[t];
273
274 totalWeight += trkWeights[t];
275 trk_recoVtx(trk) = ElementLink<xAOD::VertexContainer>(vxContainer, vxEntry - 1);
276 trk_wtVtx(trk) = trkWeights[t];
277
278 const ElementLink<xAOD::TruthParticleContainer> & truthPartLink = trk_truthPartAcc( trk );
279 float prob = trk_truthProbAcc( trk );
280
281 if (!truthPartLink.isValid()) continue;
282
283 if (prob > m_trkMatchProb) {
284 const xAOD::TruthParticle & truthPart = **truthPartLink;
285 //check if the truth particle is "good"
286 if ( pass( truthPart) ) {
287 ElementLink<xAOD::TruthEventBaseContainer> match = backLinkDecor( truthPart );
288 //check we have an actual link
289 if ( match.isValid() ) {
290 size_t matchIdx = indexOfMatchInfo( matchinfo, match );
291 std::get<1>(matchinfo[matchIdx]) += trkWeights[t];
292 std::get<2>(matchinfo[matchIdx]) += (trk.pt()/1000.) * (trk.pt()/1000.) * trkWeights[t];
293 matchIdx = indexOfMatchInfo( rawMatchinfo, match );
294 std::get<1>(rawMatchinfo[matchIdx]) += trkWeights[t];
295 std::get<2>(rawMatchinfo[matchIdx]) += (trk.pt()/1000.) * (trk.pt()/1000.) * trkWeights[t];
296 if((*match)->type() == xAOD::Type::TruthEvent && match.index() == 0) nHSTrk++;
297 } else {
298 totalFake += trkWeights[t];
299 }
300
301 } else {
302 //truth particle failed cuts -> add to fakes
303 totalFake += trkWeights[t];
304 }
305 } else {
306 //not valid or low matching probability -> add to fakes
307 totalFake += trkWeights[t];
308 }
309 }//end loop over tracks in vertex
310 n_links += ntracks;
311 n_bad_links += vx_n_bad_links;
312 if (vx_n_bad_links>0) {
313 ++n_vx_with_bad_links;
314 }
315
316 //finalize the match info vector
317 if ( totalWeight < 1e-12 ) { // in case we don't have any passing tracks we want to make sure labeled fake
318 ATH_MSG_DEBUG(" Declaring vertex fully fake (no passing tracks included)");
319 totalWeight = 1.;
320 totalFake = 1.;
321 }
322 if ( totalFake > 0. )
323 {
324 matchinfo.emplace_back( ElementLink<xAOD::TruthEventBaseContainer>(), totalFake, 0. );
325 rawMatchinfo.emplace_back( ElementLink<xAOD::TruthEventBaseContainer>(), totalFake, 0. );
326 }
327
328 for ( auto & mit : matchinfo ) {
329 std::get<1>(mit) /= totalWeight;
330 }
331 std::sort( matchinfo.begin(), matchinfo.end(), compareMatchPair );
332 std::sort( rawMatchinfo.begin(), rawMatchinfo.end(), compareMatchPair );
333 matchInfoDecor( *vxit ) = matchinfo;
334 rawMatchInfoDecor( *vxit ) = rawMatchinfo;
335 nHSTrkDecor( *vxit ) = nHSTrk;
336 }
337 m_nVtx += vxContainer.stdcont().size();
338 m_nVtxWithBadLinks += n_vx_with_bad_links;
339 m_nBadLinks += n_bad_links;
340 m_nLinks += n_links;
341
342 //After first loop, all vertices have been decorated with their vector of match info (link to TruthEvent paired with weight)
343 //now we want to use that information from the whole collection to assign types
344
345 //keep track of whether a type is assigned
346 //useful since looking for splits involves a double loop, and then setting types ahead in the collection
347 std::vector<bool> assignedType( vxContainer.size(), false );
348
349 for ( size_t i = 0; i < vxContainer.size(); ++i ) {
350
351 if ( assignedType[i] ) continue; // make sure we don't reclassify vertices already found in the split loop below
352
353 std::vector<VertexTruthMatchInfo> & info = matchInfoDecor( *vxContainer[i] );
354 if (info.empty()) {
355 matchTypeDecor( *vxContainer[i] ) = DUMMY;
356 } else if ( !std::get<0>(info[0]).isValid() ) {
357 matchTypeDecor( *vxContainer[i] ) = FAKE;
358 } else if ( std::get<1>(info[0]) > m_vxMatchWeight ) {
359 matchTypeDecor( *vxContainer[i] ) = MATCHED;
360 } else {
361 matchTypeDecor( *vxContainer[i] ) = MERGED;
362 }
363
364 //check for splitting
365 if ( matchTypeDecor( *vxContainer[i] ) == MATCHED || matchTypeDecor( *vxContainer[i] ) == MERGED ) {
366 std::vector<size_t> foundSplits;
367 for ( size_t j = i + 1; j < vxContainer.size(); ++j ) {
368 std::vector<VertexTruthMatchInfo> & info2 = matchInfoDecor( *vxContainer[j] );
369 //check second vertex is not dummy or fake, and that it has same elementlink as first vertex
370 //equality test is in code but doesnt seem to work for ElementLinks that I have?
371 //so i am just checking that the contianer key hash and the index are the same
372 if (matchTypeDecor( *vxContainer[j] ) == FAKE || matchTypeDecor( *vxContainer[j] ) == DUMMY) continue;
373 if (!info2.empty() && std::get<0>(info2[0]).isValid() && std::get<0>(info[0]).key() == std::get<0>(info2[0]).key() && std::get<0>(info[0]).index() == std::get<0>(info2[0]).index() ) {
374 //add split links; first between first one found and newest one
375 splitPartnerDecor( *vxContainer[i] ).emplace_back( vxContainer, j );
376 splitPartnerDecor( *vxContainer[j] ).emplace_back( vxContainer, i );
377 //then between any others we found along the way
378 for ( auto k : foundSplits ) { //k is a size_t in the vector of splits
379 splitPartnerDecor( *vxContainer[k] ).emplace_back( vxContainer, j );
380 splitPartnerDecor( *vxContainer[j] ).emplace_back( vxContainer, k );
381 }
382 //then keep track that we found this one
383 foundSplits.push_back(j);
384 } //if the two vertices match to same TruthEvent
385 }//inner loop over vertices
386
387 // Correct labelling of split vertices - keep highest sumpt2 vertex labelled as matched/merged
388 float maxSumpT2 = std::get<2>( matchInfoDecor( *vxContainer[i] )[0] );
389 size_t indexOfMax = i;
390 for ( auto l : foundSplits ) {
391 if ( std::get<2>( matchInfoDecor( *vxContainer[l] )[0] ) > maxSumpT2 ){
392 maxSumpT2 = std::get<2>( matchInfoDecor( *vxContainer[l] )[0] );
393 indexOfMax = l;
394 } else {
395 matchTypeDecor( *vxContainer[l] ) = SPLIT;
396 assignedType[l] = true;
397 }
398 }
399 if ( indexOfMax!=i ) matchTypeDecor( *vxContainer[i] ) = SPLIT;
400 } //if matched or merged
401 } //outer loop
402
403 //DEBUG MATCHING
404 if (msgLvl(MSG::DEBUG)) {
405 for (const auto &vxit : vxContainer.stdcont() ) {
406 ATH_MSG_DEBUG("Matched vertex (index " << (*vxit).index() << ") to type " << matchTypeDecor(*vxit) << " with following info of size " << matchInfoDecor(*vxit).size() << ":");
407 for (const auto &vit : matchInfoDecor(*vxit) ) {
408 if ( std::get<0>(vit).isValid() ) {
409 ATH_MSG_DEBUG(" GenEvent type " << (* std::get<0>(vit))->type() << ", index " << std::get<0>(vit).index() << " with relative weight " << std::get<1>(vit) );
410 } else {
411 ATH_MSG_DEBUG(" Fakes with relative weight " << std::get<1>(vit) );
412 }
413 }
414 if (matchTypeDecor(*vxit) == SPLIT) {
415 ATH_MSG_DEBUG(" Split partners are:");
416 for (const auto &split : splitPartnerDecor( *vxit ) ) {
417 if ( split.isValid() )
418 ATH_MSG_DEBUG(" Vertex " << split.index());
419 else
420 ATH_MSG_DEBUG(" ERROR");
421 }
422 }
423 }
424 }
425
426 return StatusCode::SUCCESS;
427
428}
429
430
431//Set up any cuts on either the tracks or truth particles to allow here
432//A failing track is removed from consideration entirely
433//If a passing track matches to a failing truth particle it will be considered "fake"
434
436
437 //remove the registered secondaries
438 return truthPart.pt() >= m_trkPtCut;
439
440}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_INFO(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
bool isValid(const T &p)
Av: we implement here an ATLAS-sepcific convention: all particles which are 99xxxxx are fine.
Definition AtlasPID.h:878
static Double_t a
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
ServiceHandle< StoreGateSvc > & evtStore()
bool msgLvl(const MSG::Level lvl) const
const T * at(size_type n) const
Access an element, as an rvalue.
const PtrVector & stdcont() const
Return the underlying std::vector of the container.
size_type size() const noexcept
Returns the number of elements in the collection.
bool empty() const noexcept
Returns true if the collection is empty.
std::atomic< unsigned int > m_nVtxWithBadLinks
std::atomic< unsigned int > m_nVtx
InDetVertexTruthMatchTool(const std::string &name)
virtual StatusCode matchVertices(const xAOD::VertexContainer &vxContainer) const override
std::atomic< unsigned int > m_nBadLinks
std::atomic< unsigned int > m_nLinks
bool pass(const xAOD::TruthParticle &truthPart) const
static const xAOD::TrackParticleContainer * findTrackParticleContainer(const xAOD::VertexContainer &vxContainer)
virtual StatusCode initialize() override final
Dummy implementation of the initialisation function.
virtual StatusCode finalize() override
bool isAvailable(const ELT &e) const
Test to see if this variable exists in the store.
SG::Decorator< T, ALLOC > Decorator
class to provide type-safe access to aux data.
Definition AuxElement.h:135
SG::ConstAccessor< T, ALLOC > ConstAccessor
Helper class to provide type-safe access to aux data.
Definition AuxElement.h:131
AsgTool(const std::string &name)
Constructor specifying the tool instance's name.
Definition AsgTool.cxx:58
virtual double pt() const override final
The transverse momentum ( ) of the particle.
virtual double pt() const override final
The transverse momentum ( ) of the particle.
std::vector< ElementLink< xAOD::TrackParticleContainer > > TrackParticleLinks_t
Type for the associated track particles.
Definition Vertex_v1.h:128
VxType::VertexType vertexType() const
The type of the vertex.
bool contains(const std::string &s, const std::string &regx)
does a string contain the substring
Definition hcg.cxx:114
std::vector< std::string > split(const std::string &s, const std::string &t=":")
Definition hcg.cxx:177
bool match(std::string s1, std::string s2)
match the individual directories of two strings
Definition hcg.cxx:357
std::tuple< ElementLink< xAOD::TruthEventBaseContainer >, float, float > VertexTruthMatchInfo
Definition index.py:1
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
@ TruthEvent
The object is a truth event.
Definition ObjectType.h:69
VertexType
Vertex types.
@ NoVtx
Dummy vertex. TrackParticle was not used in vertex fit.
TrackParticle_v1 TrackParticle
Reference the current persistent version:
VertexContainer_v1 VertexContainer
Definition of the current "Vertex container version".
TruthEventBaseContainer_v1 TruthEventBaseContainer
Declare the latest version of the truth event container.
TruthParticle_v1 TruthParticle
Typedef to implementation.
TrackParticleContainer_v1 TrackParticleContainer
Definition of the current "TrackParticle container version".