ATLAS Offline Software
Loading...
Searching...
No Matches
Reconstruction/VKalVrt/VrtSecInclusive/src/Utilities.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
5// Header include
9
11
16
17#include "TH1D.h"
18#include "TNtuple.h"
19#include "TTree.h"
20#include "TROOT.h"
21
22#include <iostream>
23#include <map>
24#include <vector>
25#include <deque>
26
27//-------------------------------------------------
28
29using namespace std;
30
31namespace VKalVrtAthena {
32
33 //____________________________________________________________________________________________________
35
36 bool is_pv_associated = false;
37 const xAOD::TrackParticle *trk_from_gsf;
38 // get ID track matched to GSF track
40 for( const auto* vtx : *vertices ) {
41 for( size_t iv = 0; iv < vtx->nTrackParticles(); iv++ ) {
42 const auto* pvtrk = vtx->trackParticle( iv );
43 if (!pvtrk) continue;
44 // when using lepton-only selection, also need to check if the ID track matched to the GSF track is associated to the PV
45 if ( (trk_from_gsf == pvtrk) or (trk == pvtrk) ) {
46 is_pv_associated = true;
47 break;
48 }
49 }
50 }
51 return is_pv_associated;
52 }
53
54 //____________________________________________________________________________________________________
55 double vtxVtxDistance( const Amg::Vector3D& v1, const Amg::Vector3D& v2 ) {
56 return (v1-v2).norm();
57 }
58
59
60 //____________________________________________________________________________________________________
61 double VrtSecInclusive::significanceBetweenVertices( const WrkVrt& v1, const WrkVrt& v2 ) const {
62 try {
63 const auto distance = v2.vertex - v1.vertex;
64 AmgSymMatrix(3) sumCov;
65
66 sumCov.fillSymmetric(0, 0, v1.vertexCov.at(0) + v2.vertexCov.at(0));
67 sumCov.fillSymmetric(1, 0, v1.vertexCov.at(1) + v2.vertexCov.at(1));
68 sumCov.fillSymmetric(1, 1, v1.vertexCov.at(2) + v2.vertexCov.at(2));
69 sumCov.fillSymmetric(2, 0, v1.vertexCov.at(3) + v2.vertexCov.at(3));
70 sumCov.fillSymmetric(2, 1, v1.vertexCov.at(4) + v2.vertexCov.at(4));
71 sumCov.fillSymmetric(2, 2, v1.vertexCov.at(5) + v2.vertexCov.at(5));
72
73 const double s2 = distance.transpose() * sumCov.inverse() * distance;
74
75 return s2 > 0. ? sqrt( s2 ) : AlgConsts::maxValue;
76 } catch(...) {
77 ATH_MSG_WARNING( " >>> " << __FUNCTION__ << ": detected covariance matrix broken exception" );
79 }
80 }
81
82 //____________________________________________________________________________________________________
83 template<>
84 void genSequence( const xAOD::Muon*, std::vector<unsigned>& trackTypes ) {
85 trackTypes = { xAOD::Muon::Primary,
86 xAOD::Muon::InnerDetectorTrackParticle,
87 xAOD::Muon::MuonSpectrometerTrackParticle,
88 xAOD::Muon::CombinedTrackParticle,
89 xAOD::Muon::ExtrapolatedMuonSpectrometerTrackParticle
90 };
91 }
92
93 template<>
94 void genSequence( const xAOD::Electron* electron, std::vector<unsigned>& trackTypes ) {
95 for( size_t i=0; i<electron->nTrackParticles(); i++ ) trackTypes.emplace_back( i );
96 }
97
98
99 //____________________________________________________________________________________________________
100 template<>
101 const xAOD::TrackParticle* getLeptonTrackParticle( const xAOD::Muon* muon, const unsigned& trackType ) {
102 return muon->trackParticle( static_cast<xAOD::Muon::TrackParticleType>( trackType ) );
103 }
104
105 template<>
106 const xAOD::TrackParticle* getLeptonTrackParticle( const xAOD::Electron* electron, const unsigned& trackType ) {
107 return electron->trackParticle( trackType );
108 }
109
110
111 //____________________________________________________________________________________________________
112 double VrtSecInclusive::distanceBetweenVertices( const WrkVrt& v1, const WrkVrt& v2 ) const {
113 return (v2.vertex - v1.vertex).norm();
114 }
115
116
117 //____________________________________________________________________________________________________
118 StatusCode VrtSecInclusive::disassembleVertex(std::vector<WrkVrt> *workVerticesContainer, const unsigned& iv )
119 {
120
121 auto& wrkvrt = workVerticesContainer->at(iv);
122
123 ATH_MSG_VERBOSE(" >> disassembleVertex(): begin: disassembling vertex[" << iv << "], workVerticesContainer.size() = " << workVerticesContainer->size() );
124 ATH_MSG_VERBOSE(" >> disassembleVertex(): Vertex: r = " << wrkvrt.vertex.perp() << ", z = " << wrkvrt.vertex.z() );
125
126 // Loop over the tracks associated to the vertex and slect the maximum chi2 track
127 const auto& ntrk = wrkvrt.selectedTrackIndices.size();
128 size_t maxChi2TrackIndex = AlgConsts::invalidUnsigned;
129
130 // If the size of the tracks is less than 2, this algorithm is meaningless.
131 if( wrkvrt.selectedTrackIndices.size() <= 2 ) return StatusCode::SUCCESS;
132
133 for( auto& index : wrkvrt.selectedTrackIndices ) {
134 const xAOD::TrackParticle* trk = m_selectedTracks.at( index );
135
136 ATH_MSG_VERBOSE(" >> disassembleVertex(): > track at vertex[" << iv << "]: "
137 << "index = " << trk->index()
138 << ", pT = " << trk->pt()
139 << ", phi = " << trk->phi()
140 << ", d0 = " << trk->d0()
141 << ", z0 = " << trk->z0());
142 }
143
144 // find the track with the maximum chi2
145 const auto& max = std::max_element( wrkvrt.Chi2PerTrk.begin(), wrkvrt.Chi2PerTrk.end() );
146
147 if( max == wrkvrt.Chi2PerTrk.end() ) return StatusCode::SUCCESS;
148
149 maxChi2TrackIndex = max - wrkvrt.Chi2PerTrk.begin();
150
151 // return if no track is found.
152 if(maxChi2TrackIndex == AlgConsts::invalidUnsigned ) return StatusCode::SUCCESS;
153
154
155 // define work variables
156 vector<const xAOD::NeutralParticle*> dummyNeutrals;
157
158 vector<WrkVrt> new_vertices;
159
160 // Loop over the tracks associated to the vertex other than the selected tracks
161 ATH_MSG_VERBOSE(" >> disassembleVertex(): Loop over the tracks associated to the vertex other than the selected tracks.");
162 for(size_t itrk=0; itrk<ntrk; itrk++) {
163
164 ATH_MSG_VERBOSE(" >> disassembleVertex(): > Loop itrk = " << itrk << " / " << ntrk );
165
166 // reject the selected track
167 if( itrk == maxChi2TrackIndex ) {
168 ATH_MSG_VERBOSE(" >> disassembleVertex(): > skipped." );
169 continue;
170 }
171
172 const size_t this_trk_id = wrkvrt.selectedTrackIndices[itrk];
173 const size_t selected_trk_id = wrkvrt.selectedTrackIndices[maxChi2TrackIndex];
174
175 ATH_MSG_VERBOSE(" >> disassembleVertex(): > this_trk_id = " << this_trk_id << ", selected_trk_id = " << selected_trk_id << ", alltrks_size = " << m_selectedTracks.size() );
176 if( this_trk_id >= m_selectedTracks.size() ) {
177 ATH_MSG_VERBOSE(" >> disassembleVertex(): > this_trk_id is invalid. continue!" );
178 continue;
179 }
180 if( selected_trk_id >= m_selectedTracks.size() ) {
181 ATH_MSG_VERBOSE(" >> disassembleVertex(): > selected_trk_id is invalid. continue!" );
182 continue;
183 }
184
185 ATH_MSG_VERBOSE(" >> disassembleVertex(): > Storing tracks to ListBaseTracks" );
186 ATH_MSG_VERBOSE(" >> disassembleVertex(): > m_selectedTracks.at( this_trk_id ) = " << m_selectedTracks.at( this_trk_id )->index() );
187 ATH_MSG_VERBOSE(" >> disassembleVertex(): > m_selectedTracks.at( this_trk_id ) = " << m_selectedTracks.at( selected_trk_id )->index() );
188
189 vector<const xAOD::TrackParticle*> ListBaseTracks;
190 ListBaseTracks.emplace_back( m_selectedTracks.at( this_trk_id ) );
191 ListBaseTracks.emplace_back( m_selectedTracks.at( selected_trk_id ) );
192
193 ATH_MSG_VERBOSE(" >> disassembleVertex(): > ListBaseTracks was stored." );
194
195 WrkVrt newvrt;
196 newvrt.selectedTrackIndices.emplace_back( this_trk_id );
197 newvrt.selectedTrackIndices.emplace_back( selected_trk_id );
198
199 // Fit the new vertex
200 ATH_MSG_VERBOSE(" >> disassembleVertex(): > Fast Fit" );
201
202 std::unique_ptr<Trk::IVKalState> state = m_fitSvc->makeState();
203 ATH_CHECK( m_fitSvc->VKalVrtFitFast( ListBaseTracks, newvrt.vertex, *state ) );
204
205 ATH_MSG_VERBOSE( " >> disassembleVertex(): > ApproxVertex: r = " << newvrt.vertex.perp() << ", z = " << newvrt.vertex.z() );
206
207 if( vtxVtxDistance( wrkvrt.vertex, newvrt.vertex ) > 10. )
208 {
209 m_fitSvc->setApproximateVertex( wrkvrt.vertex[0], wrkvrt.vertex[1], wrkvrt.vertex[2], *state );
210 }
211 else
212 {
213 m_fitSvc->setApproximateVertex( newvrt.vertex[0], newvrt.vertex[1], newvrt.vertex[2], *state );
214 }
215
216 ATH_MSG_VERBOSE(" >> disassembleVertex(): > Fit the new vertex" );
217 StatusCode sc = m_fitSvc->VKalVrtFit(ListBaseTracks,
218 dummyNeutrals,
219 newvrt.vertex,
220 newvrt.vertexMom,
221 newvrt.Charge,
222 newvrt.vertexCov,
223 newvrt.Chi2PerTrk,
224 newvrt.TrkAtVrt,
225 newvrt.Chi2,
226 *state);
227
228 if( sc.isFailure() ) continue;
229
230 newvrt.closestWrkVrtIndex = 0;
232
233 // register the new vertex to the vertex list
234 ATH_MSG_VERBOSE(" >> disassembleVertex(): > register the new vertex to the vertex list" );
235 new_vertices.emplace_back( newvrt );
236 }
237
238 // remove the selected track from the original vertex
239 wrkvrt.selectedTrackIndices.erase( wrkvrt.selectedTrackIndices.begin() + maxChi2TrackIndex ); //remove track
240 ATH_MSG_VERBOSE(" >> disassembleVertex(): removed the selected track from the original vertex. wrkvrt.selectedTrackIndices.size = " << wrkvrt.selectedTrackIndices.size() );
241
242 // refit the original vertex
243 ATH_MSG_VERBOSE(" >> disassembleVertex(): refit the original vertex" );
244
245 StatusCode sc = refitVertex( wrkvrt );
246 if( sc.isFailure() ) {
247 // WARNING CODE ATLASRECTS-3145::001 refitVertex Failure, vertex lost
248 ATH_MSG_WARNING("ATLASRECTS-3145::001" );
249 return StatusCode::SUCCESS;
250 }
251 // end of workaround
252
253 for( const auto& vertex : new_vertices ) {
254 ATH_MSG_VERBOSE(" >> disassembleVertex(): > emplace_back new vertex" );
255 workVerticesContainer->emplace_back( vertex );
256 }
257
258 ATH_MSG_VERBOSE(" >> disassembleVertex(): end. workVerticesContainer.size() = " << workVerticesContainer->size() );
259 return StatusCode::SUCCESS;
260 }
261
262
263
264 //____________________________________________________________________________________________________
266 {
267 //
268 // Iterate track removal until vertex get good Chi2
269 //
270
271 auto fitQuality_begin = vertex.fitQuality();
272
273 auto removeCounter = 0;
274
275 if( vertex.nTracksTotal() <= 2 ) return 0.;
276
277 {
278 WrkVrt backup = vertex;
279 StatusCode sc = refitVertexWithSuggestion( vertex, vertex.vertex );
280 if( sc.isFailure() ) {
281 vertex = backup;
282 return 0;
283 }
284 }
285
286 double chi2Probability = TMath::Prob( vertex.Chi2, vertex.ndof() );
287
288 while (chi2Probability < m_improveChi2ProbThreshold ) {
289 if( vertex.nTracksTotal() == 2 ) return chi2Probability;
290
291 WrkVrt vertex_backup = vertex;
292
293 auto maxChi2 = std::max_element( vertex.Chi2PerTrk.begin(), vertex.Chi2PerTrk.end() );
294 size_t index = maxChi2 - vertex.Chi2PerTrk.begin();
295
296
297 ATH_MSG_DEBUG( " >>> " << __FUNCTION__ << ": worst chi2 trk index = " << index << ", #trks = " << vertex.Chi2PerTrk.size() );
298
299 if( index < vertex.selectedTrackIndices.size() ) {
300 vertex.selectedTrackIndices.erase( vertex.selectedTrackIndices.begin() + index ); //remove track
301 removeCounter++;
302 } else {
303 index -= vertex.selectedTrackIndices.size();
304 if( index >= vertex.associatedTrackIndices.size() ) {
305 ATH_MSG_WARNING( " >>> " << __FUNCTION__ << ": invalid index" );
306 break;
307 }
308 vertex.associatedTrackIndices.erase( vertex.associatedTrackIndices.begin() + index ); //remove track
309 removeCounter++;
310 }
311
312 StatusCode sc = refitVertexWithSuggestion( vertex, vertex.vertex );
313
314 if( sc.isFailure() || vertex_backup.fitQuality() < vertex.fitQuality() ) {
315 vertex = vertex_backup;
316 chi2Probability = 0;
317 break;
318 }
319
320 chi2Probability = TMath::Prob( vertex.Chi2, vertex.ndof() );
321 }
322
323 auto fitQuality_end = vertex.fitQuality();
324
325 if( 0 == removeCounter ) {
326 ATH_MSG_DEBUG( " >>> " << __FUNCTION__ << ": no improvement was found." );
327 } else {
328 ATH_MSG_DEBUG( " >>> " << __FUNCTION__ << ": Removed " << removeCounter << " tracks; Fit quality improvement: " << fitQuality_begin << " ==> " << fitQuality_end );
329 }
330
331 return chi2Probability;
332 }
333
334
335
336 //____________________________________________________________________________________________________
337 void VrtSecInclusive::removeTrackFromVertex(std::vector<WrkVrt> *workVerticesContainer,
338 std::vector< std::deque<long int> > *TrkInVrt,
339 const long int & trackIndexToRemove,
340 const long int & SelectedVertex)
341 {
342
343 auto& wrkvrt = workVerticesContainer->at(SelectedVertex);
344 auto& tracks = wrkvrt.selectedTrackIndices;
345
346 {
347 auto end = std::remove_if( tracks.begin(), tracks.end(), [&](long int index) { return index == trackIndexToRemove; } );
348 tracks.erase( end, tracks.end() );
349 }
350
351 {
352 for( auto& trks : *TrkInVrt ) {
353 auto end = std::remove_if( trks.begin(), trks.end(), [&](long int index) { return index == trackIndexToRemove; } );
354 trks.erase( end, trks.end() );
355 }
356 }
357
358
359 // Check if track is removed from two-track vertex => then sharing of track left should also be decreased
360 if( wrkvrt.selectedTrackIndices.size() == 1 ) {
361
362 const auto& leftTrackIndex = *( tracks.begin() );
363 auto& list = TrkInVrt->at(leftTrackIndex);
364 auto end = std::remove_if( list.begin(), list.end(), [&](long int index) { return index == trackIndexToRemove; } );
365 list.erase( end, list.end() );
366
367 }
368
369 }
370
371
372
373 //____________________________________________________________________________________________________
374 double VrtSecInclusive::findMinVerticesPair( std::vector<WrkVrt> *workVerticesContainer, std::pair<unsigned, unsigned>& indexPair, const VrtSecInclusive::AlgForVerticesPair& algorithm )
375 {
376 //
377 // Minimal normalized vertex-vertex distance
378 //
379
380 for( auto& workVertex : *workVerticesContainer ) {
381 workVertex.closestWrkVrtValue = AlgConsts::maxValue;
382 workVertex.closestWrkVrtIndex = 0;
383 }
384
386
387 for( auto iv = workVerticesContainer->begin(); iv != workVerticesContainer->end(); ++iv ) {
388 if( (*iv).selectedTrackIndices.size()< 2) continue; /* Bad vertices */
389
390 auto i_index = iv - workVerticesContainer->begin();
391
392 for( auto jv = std::next(iv); jv != workVerticesContainer->end(); ++jv ) {
393 if( (*jv).selectedTrackIndices.size()< 2) continue; /* Bad vertices */
394
395 auto j_index = iv - workVerticesContainer->begin();
396
397 double value = (this->*algorithm)( (*iv), (*jv) );
398
399 if( value < minValue ){
400 minValue = value;
401 indexPair.first = i_index;
402 indexPair.second = j_index;
403 }
404 if( value < (*iv).closestWrkVrtValue ) {(*iv).closestWrkVrtValue = value; (*iv).closestWrkVrtIndex = j_index; }
405 if( value < (*jv).closestWrkVrtValue ) {(*jv).closestWrkVrtValue = value; (*jv).closestWrkVrtIndex = i_index; }
406 }
407 }
408
409 return minValue;
410 }
411
412
413 //____________________________________________________________________________________________________
414 double VrtSecInclusive::findMinVerticesNextPair( std::vector<WrkVrt> *workVerticesContainer, std::pair<unsigned, unsigned>& indexPair )
415 {
416 //
417 // Give minimal distance between nonmodifed yet vertices
418 //
419
420 indexPair.first = 0;
421 indexPair.second = 0;
422
424
425 for(unsigned iv=0; iv<workVerticesContainer->size()-1; iv++) {
426 auto& vertex = workVerticesContainer->at(iv);
427
428 if( vertex.selectedTrackIndices.size() < 2) continue; /* Bad vertex */
429 if( vertex.closestWrkVrtIndex == 0 ) continue; /* Used vertex */
430
431 if( vertex.closestWrkVrtValue < minValue ) {
432
433 unsigned jv = vertex.closestWrkVrtIndex;
434
435 // Close vertex to given [iv] one is modified already
436 if( workVerticesContainer->at(jv).closestWrkVrtIndex == 0 ) continue;
437
438 minValue = vertex.closestWrkVrtValue;
439
440 indexPair.first = iv;
441 indexPair.second = jv;
442
443 }
444 }
445
446 return minValue;
447 }
448
449
450
451 //____________________________________________________________________________________________________
453 {
454 //
455 // Merge two close vertices into one (first) and set NTr=0 for second vertex
456 //
457
458 // firstly, take a backup of the original vertices
459 auto v1_bak = v1;
460 auto v2_bak = v2;
461
462 for( auto& index : v2.selectedTrackIndices ) { v1.selectedTrackIndices.emplace_back( index ); }
463
464 // Cleaning
465 deque<long int>::iterator TransfEnd;
466 sort( v1.selectedTrackIndices.begin(), v1.selectedTrackIndices.end() );
467 TransfEnd = unique(v1.selectedTrackIndices.begin(), v1.selectedTrackIndices.end() );
468 v1.selectedTrackIndices.erase( TransfEnd, v1.selectedTrackIndices.end());
469 //
470 //----------------------------------------------------------
471 v2.selectedTrackIndices.clear(); //Clean dropped vertex
472 v2.closestWrkVrtValue = AlgConsts::maxValue; //Clean dropped vertex
473 v2.closestWrkVrtIndex = 0; //Clean dropped vertex
474 v2.isGood = false; //Clean dropped vertex
475
476 v1.closestWrkVrtValue = AlgConsts::maxValue; //Clean new vertex
477 v1.closestWrkVrtIndex = 0; //Clean new vertex
478 v1.isGood = true; //Clean new vertex
479
480 StatusCode sc = refitVertex( v1 );
481 if( sc.isFailure() ) {
482 v1 = v1_bak;
483 v2 = v2_bak;
484
485 ATH_MSG_DEBUG(" >>> " << __FUNCTION__ << ": failure in merging" );
486
487 return StatusCode::FAILURE;
488 }
489
490 return StatusCode::SUCCESS;
491 }
492
493
494
495 //____________________________________________________________________________________________________
496 StatusCode VrtSecInclusive::refitVertex( WrkVrt& workVertex )
497 {
498 std::unique_ptr<Trk::IVKalState> state = m_fitSvc->makeState();
499 return refitVertex (workVertex, *state);
500 }
501
502
503
504 //____________________________________________________________________________________________________
505 StatusCode VrtSecInclusive::refitVertex( WrkVrt& workVertex,
506 Trk::IVKalState& istate)
507 {
508
509 //
510 vector<const xAOD::NeutralParticle*> dummyNeutrals;
511
512 int nth = workVertex.selectedTrackIndices.size();
513
514 if(nth<2) {
515 workVertex.isGood = false;
516 return StatusCode::SUCCESS;
517 }
518
519 vector<const xAOD::TrackParticle*> ListBaseTracks;
520
521 workVertex.Chi2PerTrk.clear();
522
523 for( const auto& index : workVertex.selectedTrackIndices ) {
524 ListBaseTracks.emplace_back( m_selectedTracks.at( index ) );
525 workVertex.Chi2PerTrk.emplace_back( AlgConsts::chi2PerTrackInitValue );
526 }
527
528 for( const auto& index : workVertex.associatedTrackIndices ) {
529 ListBaseTracks.emplace_back( m_associatedTracks.at( index ) );
530 workVertex.Chi2PerTrk.emplace_back( AlgConsts::chi2PerTrackInitValue );
531 }
532
533 auto& vertexPos = workVertex.vertex;
534
535 m_fitSvc->setApproximateVertex( vertexPos.x(), vertexPos.y(), vertexPos.z(), istate );
536
537 ATH_MSG_VERBOSE( " >>> refitVertex: ListBaseTracks.size = " << ListBaseTracks.size()
538 << ", #selectedBaseTracks = " << workVertex.selectedTrackIndices.size()
539 << ", #assocTracks = " << workVertex.associatedTrackIndices.size() );
540 for( const auto *trk : ListBaseTracks ) {
541 ATH_MSG_VERBOSE( " >>> refitVertex: track index = " << trk->index() );
542 }
543
544 ATH_MSG_VERBOSE( " >>> refitVertex: m_fitSvc is reset." );
545
546 Amg::Vector3D initVertex;
547
548 StatusCode sc = m_fitSvc->VKalVrtFitFast( ListBaseTracks, initVertex, istate );/* Fast crude estimation */
549 if(sc.isFailure()) ATH_MSG_DEBUG(" >>> refitVertex: fast crude estimation failed.");
550 ATH_MSG_VERBOSE( " >>> refitVertex: Fast VKalVrtFit succeeded. vertex (r,z) = (" << initVertex.perp() << ", " << initVertex.z() << ", " << ")" );
551
552 if( vtxVtxDistance( initVertex, vertexPos ) > 10. ) {
553
554 m_fitSvc->setApproximateVertex( vertexPos.x(), vertexPos.y(), vertexPos.z(), istate );
555
556 } else {
557
558 m_fitSvc->setApproximateVertex( initVertex.x(), initVertex.y(), initVertex.z(), istate );
559
560 }
561
562 ATH_MSG_VERBOSE( " >>> refitVertex: approx vertex is set. Now going to perform fitting..." );
563
564 StatusCode SC=m_fitSvc->VKalVrtFit(ListBaseTracks,dummyNeutrals,
565 workVertex.vertex,
566 workVertex.vertexMom,
567 workVertex.Charge,
568 workVertex.vertexCov,
569 workVertex.Chi2PerTrk,
570 workVertex.TrkAtVrt,
571 workVertex.Chi2,
572 istate);
573
574 auto& cov = workVertex.vertexCov;
575
576 if(SC.isFailure()) ATH_MSG_DEBUG(" >>> refitVertex: SC in refitVertex returned failure ");
577 ATH_MSG_VERBOSE(" >>> refitVertex "<<SC<<", "<<ListBaseTracks.size()<<","<<workVertex.Chi2PerTrk.size());
578 ATH_MSG_VERBOSE( " >>> refitVertex: succeeded in fitting. New vertex pos (r,z) = (" << vertexPos.perp() << ", " << vertexPos.z() << ")" );
579 ATH_MSG_VERBOSE( " >>> refitVertex: New vertex cov = (" << cov.at(0) << ", " << cov.at(1) << ", " << cov.at(2) << ", " << cov.at(3) << ", " << cov.at(4) << ", " << cov.at(5) << ")" );
580
581 return SC;
582 }
583
584 //____________________________________________________________________________________________________
585 StatusCode VrtSecInclusive::refitVertexWithSuggestion( WrkVrt& workVertex, const Amg::Vector3D& suggestedPosition )
586 {
587 std::unique_ptr<Trk::IVKalState> state = m_fitSvc->makeState();
588 return refitVertexWithSuggestion (workVertex, suggestedPosition, *state);
589 }
590
591
592 //____________________________________________________________________________________________________
594 const Amg::Vector3D& suggestedPosition,
595 Trk::IVKalState& istate )
596 {
597
598 //
599 vector<const xAOD::NeutralParticle*> dummyNeutrals;
600
601 int nth = workVertex.selectedTrackIndices.size();
602
603 if(nth<2) {
604 workVertex.isGood = false;
605 return StatusCode::SUCCESS;
606 }
607
608 vector<const xAOD::TrackParticle*> ListBaseTracks;
609
610 workVertex.Chi2PerTrk.clear();
611
612 for( const auto& index : workVertex.selectedTrackIndices ) {
613 ListBaseTracks.emplace_back( m_selectedTracks.at( index ) );
614 workVertex.Chi2PerTrk.emplace_back( AlgConsts::chi2PerTrackInitValue );
615 }
616
617 for( const auto& index : workVertex.associatedTrackIndices ) {
618 ListBaseTracks.emplace_back( m_associatedTracks.at( index ) );
619 workVertex.Chi2PerTrk.emplace_back( AlgConsts::chi2PerTrackInitValue );
620 }
621
622 auto& vertexPos = workVertex.vertex;
623
624 m_fitSvc->setApproximateVertex( suggestedPosition.x(), suggestedPosition.y(), suggestedPosition.z(), istate );
625
626 ATH_MSG_VERBOSE( " >>> " << __FUNCTION__ <<": ListBaseTracks.size = " << ListBaseTracks.size()
627 << ", #selectedBaseTracks = " << workVertex.selectedTrackIndices.size()
628 << ", #assocTracks = " << workVertex.associatedTrackIndices.size() );
629 for( const auto *trk : ListBaseTracks ) {
630 ATH_MSG_VERBOSE( " >>> " << __FUNCTION__ << ": track index = " << trk->index() );
631 }
632
633 ATH_MSG_VERBOSE( " >>> " << __FUNCTION__ << ": m_fitSvc is reset." );
634
635 ATH_MSG_VERBOSE( " >>> " << __FUNCTION__ << ": approx vertex is set. Now going to perform fitting..." );
636
637 StatusCode SC=m_fitSvc->VKalVrtFit(ListBaseTracks,dummyNeutrals,
638 workVertex.vertex,
639 workVertex.vertexMom,
640 workVertex.Charge,
641 workVertex.vertexCov,
642 workVertex.Chi2PerTrk,
643 workVertex.TrkAtVrt,
644 workVertex.Chi2,
645 istate);
646
647 auto& cov = workVertex.vertexCov;
648
649 if( SC.isFailure() ) ATH_MSG_VERBOSE(" >>> " << __FUNCTION__ << ": SC in refitVertex returned failure ");
650 ATH_MSG_VERBOSE(" >>> " << __FUNCTION__ << ": "<<SC<<", "<<ListBaseTracks.size()<<","<<workVertex.Chi2PerTrk.size());
651
652 if( SC.isSuccess() ) {
653 ATH_MSG_VERBOSE( " >>> " << __FUNCTION__ << ": succeeded in fitting. New vertex pos = (" << vertexPos.x() << ", " << vertexPos.y() << ", " << vertexPos.z() << ")" );
654 ATH_MSG_VERBOSE( " >>> " << __FUNCTION__ << ": New vertex cov = (" << cov.at(0) << ", " << cov.at(1) << ", " << cov.at(2) << ", " << cov.at(3) << ", " << cov.at(4) << ", " << cov.at(5) << ")" );
655 }
656
657 return SC;
658 }
659
660
661 //____________________________________________________________________________________________________
662 size_t VrtSecInclusive::nTrkCommon( std::vector<WrkVrt> *workVerticesContainer, const std::pair<unsigned, unsigned>& pairIndex)
663 {
664 //
665 // Number of common tracks for 2 vertices
666 //
667
668 auto& trackIndices1 = workVerticesContainer->at( pairIndex.first ).selectedTrackIndices;
669 auto& trackIndices2 = workVerticesContainer->at( pairIndex.second ).selectedTrackIndices;
670
671 if( trackIndices1.size() < 2 ) return 0;
672 if( trackIndices2.size() < 2 ) return 0;
673
674 size_t nTrkCom = 0;
675
676 for( auto& index : trackIndices1 ) {
677 if( std::find(trackIndices2.begin(),trackIndices2.end(), index) != trackIndices2.end()) nTrkCom++;
678 }
679
680 return nTrkCom;
681 }
682
683
684
685//____________________________________________________________________________________________________
687
688 //--------------------------------------------------------
689 // Primary vertex extraction from TES
690 //
691
692 ATH_CHECK( evtStore()->retrieve( m_primaryVertices, "PrimaryVertices") );
693
694 if( m_FillNtuple ) m_ntupleVars->get<unsigned int>( "NumPV" ) = 0;
695 m_thePV = nullptr;
696
697 ATH_MSG_DEBUG( "processPrimaryVertices(): pv_size = " << m_primaryVertices->size() );
698
699 // Loop over PV container and get number of tracks of each PV
700
701 for( const auto *vertex : *m_primaryVertices ) {
702
703 // Hide (2015-04-21): xAOD::Vertex may contain several types of vertices
704 // e.g. if VertexType==NoVtx, this is a dummy vertex.
705 // We only need to extract primary vertices here, and skip otherwise.
706
707 if( xAOD::VxType::PriVtx != vertex->vertexType() ) continue;
708
709 // Not considering pile-up; pick-up the first PV
710 m_thePV = vertex;
711
712 if( m_FillNtuple ) {
713
714 if( 0 == m_ntupleVars->get<unsigned int>( "NumPV" ) ) {
715
716 m_ntupleVars->get<double>( "PVX" ) = vertex->x();
717 m_ntupleVars->get<double>( "PVY" ) = vertex->y();
718 m_ntupleVars->get<double>( "PVZ" ) = vertex->z();
719 m_ntupleVars->get<unsigned int>( "PVType" ) = vertex->vertexType();
720
721 // number of tracks associated to the PV
722 m_ntupleVars->get<unsigned int>( "NTrksPV" ) = vertex->nTrackParticles();
723 }
724
725 m_ntupleVars->get<unsigned int>( "NumPV" )++;
726
727 m_ntupleVars->get< vector<int> > ( "NdofTrksPV" ) .emplace_back( vertex->numberDoF() );
728 m_ntupleVars->get< vector<double> >( "PVZpile" ) .emplace_back( vertex->position().z() );
729 }
730
731 ATH_MSG_DEBUG("PrimVertex x/y/z/nDOF "
732 << vertex->x() << ","
733 << vertex->y() << ","
734 << vertex->z() << ","
735 << vertex->numberDoF() );
736
737 }
738
739 // Use the dummy PV if no PV is composed
740 if( !m_thePV ) {
741 ATH_MSG_DEBUG("No Reconstructed PV was found. Using the dummy PV instead.");
742 for( const auto *vertex : *m_primaryVertices ) {
743 if( xAOD::VxType::NoVtx != vertex->vertexType() ) continue;
744
745 if( m_FillNtuple ) {
746 // Not considering pile-up; pick-up the first PV
747 if( 0 == m_ntupleVars->get<unsigned int>( "NumPV" ) ) {
748 m_thePV = vertex;
749
750 m_ntupleVars->get<double>( "PVX" ) = vertex->x();
751 m_ntupleVars->get<double>( "PVY" ) = vertex->y();
752 m_ntupleVars->get<double>( "PVZ" ) = vertex->z();
753 m_ntupleVars->get<unsigned int>( "PVType" ) = vertex->vertexType();
754
755 // number of tracks associated to the PV
756 m_ntupleVars->get<unsigned int>( "NTrksPV" ) = vertex->nTrackParticles();
757 }
758 }
759 }
760 }
761
762 // if thePV is null, the PV is not found.
763 if( !m_thePV ) {
764 ATH_MSG_DEBUG("No PV is found in the PV collection!");
765 return StatusCode::FAILURE;
766 }
767
768 ATH_MSG_DEBUG(" Primary vertex successful. thePV = " << m_thePV );
769
770 return StatusCode::SUCCESS;
771 }
772
773
774 //____________________________________________________________________________________________________
775 void VrtSecInclusive::trackClassification(std::vector<WrkVrt> *workVerticesContainer, std::map<long int, std::vector<long int> >& trackToVertexMap )
776 {
777 // Fill TrkInVrt with vertex IDs of each track
778
779 trackToVertexMap.clear();
780
781 for( size_t iv = 0; iv<workVerticesContainer->size(); iv++ ) {
782
783 WrkVrt& vertex = workVerticesContainer->at(iv);
784
785 auto& trackIndices = vertex.selectedTrackIndices;
786 if( !vertex.isGood ) continue;
787 if( trackIndices.size() < 2 ) continue;
788
789 for( auto& index : trackIndices ) {
790 trackToVertexMap[index].emplace_back( iv );
791 }
792 }
793
794 for( auto& pair: trackToVertexMap ) {
795 std::string msg = Form("track index [%ld]: vertices = (", pair.first);
796 for( auto& v : pair.second ) {
797 msg += Form("%ld, ", v);
798 }
799 msg += ")";
800 if( pair.second.size() >=2 ) ATH_MSG_VERBOSE(" >> " << __FUNCTION__ << ": " << msg );
801 }
802
803 }
804
805
806 //____________________________________________________________________________________________________
807 double VrtSecInclusive::findWorstChi2ofMaximallySharedTrack(std::vector<WrkVrt> *workVerticesContainer,
808 std::map<long int, std::vector<long int> >& trackToVertexMap,
809 long int & maxSharedTrack,
810 long int & worstMatchingVertex)
811 {
812
813 double worstChi2 = AlgConsts::invalidFloat;
814
815 // Find the track index that has the largest shared vertices
816 auto maxSharedTrackToVertices = std::max_element( trackToVertexMap.begin(), trackToVertexMap.end(), []( auto& p1, auto& p2 ) { return p1.second.size() < p2.second.size(); } );
817
818 if( maxSharedTrackToVertices == trackToVertexMap.end() ) return worstChi2;
819
820 ATH_MSG_VERBOSE( " > " << __FUNCTION__ << ": max-shared track index = " << maxSharedTrackToVertices->first << ", number of shared vertices = " << maxSharedTrackToVertices->second.size() );
821
822 if( maxSharedTrackToVertices->second.size() < 2 ) return worstChi2;
823
824 // map of vertex index and the chi2 of the track for the maxSharedTrack
825 std::map<long int, double> vrtChi2Map;
826
827 // loop over vertices for the largest shared track
828 for( auto& iv : maxSharedTrackToVertices->second ) {
829 ATH_MSG_VERBOSE( " > " << __FUNCTION__ << ": loop over vertices: vertex index " << iv );
830
831 auto& wrkvrt = workVerticesContainer->at( iv );
832 auto& trackIndices = wrkvrt.selectedTrackIndices;
833
834 // find the index of the track
835 auto index = std::find_if( trackIndices.begin(), trackIndices.end(), [&]( auto& index ) { return index == maxSharedTrackToVertices->first; } );
836 if( index == trackIndices.end() ) {
837 ATH_MSG_WARNING(" >> " << __FUNCTION__ << ": index not found (algorithm inconsistent)" );
838 return worstChi2;
839 }
840
841 auto& chi2 = wrkvrt.Chi2PerTrk.at( index - trackIndices.begin() );
842
843 vrtChi2Map.emplace( std::pair<long int, double>(iv, chi2) );
844 }
845
846 auto worstVrtChi2Pair = std::max_element( vrtChi2Map.begin(), vrtChi2Map.end(), []( auto& p1, auto& p2 ) { return p1.second < p2.second; } );
847
848 if( worstVrtChi2Pair == vrtChi2Map.end() ) {
849 ATH_MSG_WARNING(" >> " << __FUNCTION__ << ": max_element of vrtChi2Map not found" );
850 return worstChi2;
851 }
852
853 maxSharedTrack = maxSharedTrackToVertices->first;
854 worstMatchingVertex = worstVrtChi2Pair->first;
855 worstChi2 = worstVrtChi2Pair->second;
856
857 return worstChi2;
858 }
859
860
861 //____________________________________________________________________________________________________
862 void VrtSecInclusive::printWrkSet(const std::vector<WrkVrt> *workVerticesContainer, const std::string& name)
863 {
864 ATH_MSG_DEBUG( " >> " << __FUNCTION__ << ": ===============================================================" );
865 ATH_MSG_DEBUG( " >> " << __FUNCTION__ << ": " << name << ": #vertices = " << workVerticesContainer->size() );
866
867 std::set<const xAOD::TrackParticle*> usedTracks;
868
869 auto concatenateIndicesToString = []( auto indices, auto& collection ) -> std::string {
870 if( 0 == indices.size() ) return "";
871 return std::accumulate( std::next(indices.begin()), indices.end(), std::to_string( indices.at(0) ),
872 [&collection]( const std::string& str, auto& index ) { return str + ", " + std::to_string( collection.at(index)->index() ); } );
873 };
874
875 std::map<const xAOD::TruthVertex*, bool> previous;
876
877 for( auto& pair : m_matchMap ) { previous.emplace( pair.first, pair.second ); }
878
879 m_matchMap.clear();
880 for( const auto* truthVertex : m_tracingTruthVertices ) { m_matchMap.emplace( truthVertex, false ); }
881
882 for(size_t iv=0; iv<workVerticesContainer->size(); iv++) {
883 const auto& wrkvrt = workVerticesContainer->at(iv);
884
885 if( wrkvrt.nTracksTotal() < 2 ) continue;
886
887 std::string sels = concatenateIndicesToString( wrkvrt.selectedTrackIndices, m_selectedTracks );
888 std::string assocs = concatenateIndicesToString( wrkvrt.associatedTrackIndices, m_associatedTracks );
889
890 for( const auto& index : wrkvrt.selectedTrackIndices ) { usedTracks.insert( m_selectedTracks.at(index) ); }
891 for( const auto& index : wrkvrt.associatedTrackIndices ) { usedTracks.insert( m_associatedTracks.at(index) ); }
892
893 ATH_MSG_DEBUG( " >> " << __FUNCTION__ << ": " << name << " vertex [" << iv << "]: " << &wrkvrt
894 << ", isGood = " << (wrkvrt.isGood? "true" : "false")
895 << ", #ntrks(tot, sel, assoc) = (" << wrkvrt.nTracksTotal() << ", " << wrkvrt.selectedTrackIndices.size() << ", " << wrkvrt.associatedTrackIndices.size() << "), "
896 << ", chi2/ndof = " << wrkvrt.fitQuality()
897 << ", (r, z) = (" << wrkvrt.vertex.perp()
898 << ", " << wrkvrt.vertex.z() << ")"
899 << ", sels = { " << sels << " }"
900 << ", assocs = { " << assocs << " }" );
901
902 // Truth match condition
903 for( const auto* truthVertex : m_tracingTruthVertices ) {
904
905
906 Amg::Vector3D vTruth( truthVertex->x(), truthVertex->y(), truthVertex->z() );
907 Amg::Vector3D vReco ( wrkvrt.vertex.x(), wrkvrt.vertex.y(), wrkvrt.vertex.z() );
908
909 const auto distance = vReco - vTruth;
910
911 AmgSymMatrix(3) cov;
912 cov.fillSymmetric( 0, 0, wrkvrt.vertexCov.at(0) );
913 cov.fillSymmetric( 1, 0, wrkvrt.vertexCov.at(1) );
914 cov.fillSymmetric( 1, 1, wrkvrt.vertexCov.at(2) );
915 cov.fillSymmetric( 2, 0, wrkvrt.vertexCov.at(3) );
916 cov.fillSymmetric( 2, 1, wrkvrt.vertexCov.at(4) );
917 cov.fillSymmetric( 2, 2, wrkvrt.vertexCov.at(5) );
918
919 const double s2 = distance.transpose() * cov.inverse() * distance;
920
921 if( distance.norm() < 2.0 || s2 < 100. ) m_matchMap.at( truthVertex ) = true;
922
923 }
924
925 }
926
927 ATH_MSG_DEBUG( " >> " << __FUNCTION__ << ": number of used tracks = " << usedTracks.size() );
928
929 if( !previous.empty() && previous.size() == m_matchMap.size() ) {
930 for( auto& pair : m_matchMap ) {
931 if( previous.find( pair.first ) == previous.end() ) continue;
932 if( pair.second != previous.at( pair.first ) ) {
933 ATH_MSG_DEBUG( " >> " << __FUNCTION__ << ": Match flag has changed: (r, z) = (" << pair.first->perp() << ", " << pair.first->z() << ")" );
934 }
935 }
936 }
937
938 if( m_FillHist ) {
939 for( auto& pair : m_matchMap ) {
940 if( pair.second ) m_hists["nMatchedTruths"]->Fill( m_vertexingAlgorithmStep+2, pair.first->perp() );
941 }
942 }
943
944 std::string msg;
945 for( const auto* trk : usedTracks ) { msg += Form("%ld, ", trk->index() ); }
946
947 ATH_MSG_DEBUG( " >> " << __FUNCTION__ << ": used tracks = " << msg );
948 ATH_MSG_DEBUG( " >> " << __FUNCTION__ << ": ===============================================================" );
949
950 }
951
952
953 //____________________________________________________________________________________________________
955 summary.numIBLHits = 0;
956 summary.numBLayerHits = 0;
957 summary.numPixelHits = 0;
958 summary.numSctHits = 0;
959 summary.numTrtHits = 0;
960
961 trk->summaryValue( summary.numIBLHits, xAOD::numberOfInnermostPixelLayerHits );
962 trk->summaryValue( summary.numBLayerHits, xAOD::numberOfNextToInnermostPixelLayerHits );
963 trk->summaryValue( summary.numPixelHits, xAOD::numberOfPixelHits );
964 trk->summaryValue( summary.numSctHits, xAOD::numberOfSCTHits );
965 trk->summaryValue( summary.numTrtHits, xAOD::numberOfTRTHits );
966 }
967
968
969
970 //____________________________________________________________________________________________________
972
973 auto* pattern = new ExtrapolatedPattern;
974 const EventContext& ctx = Gaudi::Hive::currentContext();
975 std::vector<std::unique_ptr<Trk::TrackParameters>> paramsVector =
976 m_extrapolator->extrapolateBlindly(ctx, trk->perigeeParameters(), direction);
977
979
980 auto nDisabled = 0;
981
982 for( auto& params : paramsVector ) {
983
984 const TVector3 position( params->position().x(), params->position().y(), params->position().z() );
985
986 if( prevPos == position ) {
987 continue;
988 }
989
990 prevPos = position;
991
992 const auto* detElement = params->associatedSurface().associatedDetectorElement();
993
994 if( detElement ) {
995
996 enum { Pixel = 1, SCT = 2 };
997
998 const auto& id = detElement->identify();
999 Flag good = false;
1000
1001 if( m_atlasId->is_pixel(id) ) {
1002
1003 auto idHash = m_pixelId->wafer_hash( id );
1004 good = m_pixelCondSummaryTool->isGood( idHash, ctx );
1005
1006 pattern->emplace_back( std::make_tuple( position, Pixel, m_pixelId->barrel_ec(id), m_pixelId->layer_disk(id), good ) );
1007
1008 } else if( m_atlasId->is_sct(id) ) {
1009
1010 auto idHash = m_sctId->wafer_hash( id );
1011 good = m_sctCondSummaryTool->isGood( idHash, ctx );
1012
1013 pattern->emplace_back( std::make_tuple( position, SCT, m_sctId->barrel_ec(id), m_sctId->layer_disk(id), good ) );
1014
1015 }
1016
1017 if( !pattern->empty() ) {
1018
1019 ATH_MSG_VERBOSE(" >> " << __FUNCTION__ << ", track " << trk << ": position = (" << position.Perp() << ", " << position.z() << ", " << position.Phi() << "), detElement ID = " << id << ", good = " << good
1020 << ": (det, bec, layer) = (" << std::get<1>( pattern->back() ) << ", " << std::get<2>( pattern->back() ) << ", " << std::get<3>( pattern->back() ) << ")" );
1021
1022 if( !good ) nDisabled++;
1023 }
1024
1025 }
1026
1027 }
1028
1029 if( m_FillHist ) {
1030 m_hists["disabledCount"]->Fill( nDisabled );
1031 }
1032
1033 return pattern;
1034
1035 }
1036
1037
1038 //____________________________________________________________________________________________________
1040 {
1041
1042 if( m_extrapolatedPatternBank.find( trk ) == m_extrapolatedPatternBank.end() ) {
1043
1044 std::unique_ptr<ExtrapolatedPattern> exPattern_along( extrapolatedPattern( trk, Trk::alongMomentum ) );
1045 std::unique_ptr<ExtrapolatedPattern> exPattern_oppos( extrapolatedPattern( trk, Trk::oppositeMomentum ) );
1046
1047 m_extrapolatedPatternBank.emplace( trk, std::make_pair( std::move(exPattern_along), std::move(exPattern_oppos) ) );
1048
1049 }
1050
1051 auto& exPattern = m_extrapolatedPatternBank.at( trk );
1052
1053 using LayerCombination = std::vector<int>;
1054
1055 std::map<LayerCombination, unsigned> layerMap;
1056 if( layerMap.empty() ) {
1057 layerMap[ { 1, 0, 0 } ] = Trk::pixelBarrel0;
1058 layerMap[ { 1, 0, 1 } ] = Trk::pixelBarrel1;
1059 layerMap[ { 1, 0, 2 } ] = Trk::pixelBarrel2;
1060 layerMap[ { 1, 0, 3 } ] = Trk::pixelBarrel3;
1061
1062 layerMap[ { 1, 2, 0 } ] = Trk::pixelEndCap0;
1063 layerMap[ { 1, 2, 1 } ] = Trk::pixelEndCap1;
1064 layerMap[ { 1, 2, 2 } ] = Trk::pixelEndCap2;
1065 layerMap[ { 1,-2, 0 } ] = Trk::pixelEndCap0;
1066 layerMap[ { 1,-2, 1 } ] = Trk::pixelEndCap1;
1067 layerMap[ { 1,-2, 2 } ] = Trk::pixelEndCap2;
1068
1069 layerMap[ { 2, 0, 0 } ] = Trk::sctBarrel0;
1070 layerMap[ { 2, 0, 1 } ] = Trk::sctBarrel1;
1071 layerMap[ { 2, 0, 2 } ] = Trk::sctBarrel2;
1072 layerMap[ { 2, 0, 3 } ] = Trk::sctBarrel3;
1073
1074 layerMap[ { 2, 2, 0 } ] = Trk::sctEndCap0;
1075 layerMap[ { 2, 2, 1 } ] = Trk::sctEndCap1;
1076 layerMap[ { 2, 2, 2 } ] = Trk::sctEndCap2;
1077 layerMap[ { 2, 2, 3 } ] = Trk::sctEndCap3;
1078 layerMap[ { 2, 2, 4 } ] = Trk::sctEndCap4;
1079 layerMap[ { 2, 2, 5 } ] = Trk::sctEndCap5;
1080 layerMap[ { 2, 2, 6 } ] = Trk::sctEndCap6;
1081 layerMap[ { 2, 2, 7 } ] = Trk::sctEndCap7;
1082 layerMap[ { 2, 2, 8 } ] = Trk::sctEndCap8;
1083 layerMap[ { 2,-2, 0 } ] = Trk::sctEndCap0;
1084 layerMap[ { 2,-2, 1 } ] = Trk::sctEndCap1;
1085 layerMap[ { 2,-2, 2 } ] = Trk::sctEndCap2;
1086 layerMap[ { 2,-2, 3 } ] = Trk::sctEndCap3;
1087 layerMap[ { 2,-2, 4 } ] = Trk::sctEndCap4;
1088 layerMap[ { 2,-2, 5 } ] = Trk::sctEndCap5;
1089 layerMap[ { 2,-2, 6 } ] = Trk::sctEndCap6;
1090 layerMap[ { 2,-2, 7 } ] = Trk::sctEndCap7;
1091 layerMap[ { 2,-2, 8 } ] = Trk::sctEndCap8;
1092 }
1093
1094 enum { position=0, detector=1, bec=2, layer=3, isGood=4 };
1095
1096 // Lambda!
1097 auto getDetectorType = [&]( const ExtrapolatedPoint& point ) -> unsigned {
1098
1099 const LayerCombination comb { std::get<detector>( point ), std::get<bec>( point ), std::get<layer>( point ) };
1100
1101 for( auto& pair : layerMap ) {
1102 if( pair.first == comb ) {
1103 return pair.second;
1104 }
1105 }
1106
1108 };
1109
1110 enum { kShouldNotHaveHit, kShouldHaveHit, kMayHaveHit };
1111 std::vector<unsigned> expectedHitPattern(Trk::numberOfDetectorTypes, kShouldNotHaveHit);
1112
1113 auto minExpectedRadius = AlgConsts::maxValue;
1114
1115 // Loop over extrapolated points (along direction)
1116 auto& exPattern_along = *( exPattern.first );
1117
1118 for( auto itr = exPattern_along.begin(); itr != exPattern_along.end(); ++itr ) {
1119 if( std::next( itr ) == exPattern_along.end() ) continue;
1120
1121 const auto& point = *itr;
1122 const auto& nextPoint = *( std::next( itr ) );
1123
1124 ATH_MSG_VERBOSE( " > " << __FUNCTION__ << ": isGood = " << std::get<isGood>( point ) );
1125
1126 const auto& thisPos = std::get<position>( point );
1127 const auto& nextPos = std::get<position>( nextPoint );
1128
1129 auto sectionVector = nextPos - thisPos;
1130 auto vertexVector = TVector3( vertex.x(), vertex.y(), vertex.z() ) - thisPos;
1131
1132
1133 const auto& detectorType = getDetectorType( point );
1134
1135 ATH_MSG_VERBOSE( " > " << __FUNCTION__ << ": detType = " << detectorType );
1136
1137 if( detectorType == AlgConsts::invalidUnsigned ) continue;
1138 if( detectorType >= Trk::numberOfDetectorTypes ) continue;
1139
1140 // if the vertex is nearby (within 10 mm), the hit may be presnet ("X")
1141 if( vertexVector.Mag() < 10. ) {
1142 expectedHitPattern.at( detectorType ) = kMayHaveHit;
1143 continue;
1144 }
1145
1146 // if the front-end module is not active, then the hit is not expected,
1147 // which means the hit may be present
1148 if( !static_cast<bool>(std::get<isGood>( point )) ) {
1149 expectedHitPattern.at( detectorType ) = kMayHaveHit;
1150 continue;
1151 }
1152
1153 // if the inner product of the above two vectors is positive,
1154 // then point is inner than the vertex.
1155 // Else, the point is outer than the vertex and expect to have hits
1156 // when the track is originated from the vertex.
1157
1158 if( sectionVector.Mag() == 0. ) continue;
1159
1160 ATH_MSG_VERBOSE( " > " << __FUNCTION__
1161 << ": hitPos = (" << thisPos.Perp() << ", " << thisPos.z() << ", " << thisPos.Phi() << ")"
1162 << ", sectionVec = (" << sectionVector.Perp() << ", " << sectionVector.z() << ", " << sectionVector.Phi() << ")"
1163 << ", vertexVec = (" << vertexVector.Perp() << ", " << vertexVector.z() << ", " << vertexVector.Phi() << ")"
1164 << ", cos(s,v) = " << sectionVector * vertexVector / ( sectionVector.Mag() * vertexVector.Mag() + AlgConsts::infinitesimal ) );
1165
1166 if( sectionVector * vertexVector > 0. ) continue;
1167
1168 if( minExpectedRadius > thisPos.Perp() ) minExpectedRadius = thisPos.Perp();
1169
1170 // now, the hit is expected to present.
1171
1172 expectedHitPattern.at( detectorType ) = kShouldHaveHit;
1173 }
1174
1175 // Loop over extrapolated points (opposite direction)
1176 auto& exPattern_oppos = *( exPattern.second );
1177 bool oppositeFlag = false;
1178
1179 for( auto itr = exPattern_oppos.begin(); itr != exPattern_oppos.end(); ++itr ) {
1180 if( std::next( itr ) == exPattern_oppos.end() ) continue;
1181
1182 const auto& point = *itr;
1183 const auto& nextPoint = *( std::next( itr ) );
1184
1185 const auto& thisPos = std::get<position>( point );
1186 const auto& nextPos = std::get<position>( nextPoint );
1187
1188 auto sectionVector = nextPos - thisPos;
1189 auto vertexVector = TVector3( vertex.x(), vertex.y(), vertex.z() ) - thisPos;
1190
1191 const auto& detectorType = getDetectorType( point );
1192
1193 ATH_MSG_VERBOSE( " > " << __FUNCTION__ << ": detType = " << detectorType );
1194
1195 ATH_MSG_DEBUG( " > " << __FUNCTION__
1196 << ": hitPos = (" << thisPos.Perp() << ", " << thisPos.z() << ", " << thisPos.Phi() << ")"
1197 << ", vertex = (" << vertex.perp() << ", " << vertex.z() << ", " << vertex.phi() << ")"
1198 << ", cos(s,v) = " << sectionVector * vertexVector / ( sectionVector.Mag() * vertexVector.Mag() + AlgConsts::infinitesimal ) );
1199
1200 if( detectorType == AlgConsts::invalidUnsigned ) continue;
1201 if( detectorType >= Trk::numberOfDetectorTypes ) continue;
1202
1203 if( sectionVector * vertexVector < 0. ) {
1204 oppositeFlag = true;
1205 }
1206 }
1207
1208 // If the first expected point's radius is smaller than the vertex radius,
1209 // it's the case that the vertex was reconstructed in the opposite phi-direction
1210 // to the track outgoing direction. Such a case should be rejected.
1211 // bool oppositeFlag = ( minExpectedRadius < vertex.perp() );
1212
1213 std::string msg = "Expected hit pattern: ";
1214 for( unsigned i=0; i<Trk::numberOfDetectorTypes; i++) {
1215 msg += Form("%s", expectedHitPattern.at(i) < kMayHaveHit? Form("%u", expectedHitPattern.at(i)) : "X" );
1216 }
1217 ATH_MSG_DEBUG( " > " << __FUNCTION__ << ": " << msg );
1218
1219 msg = "Recorded hit pattern: ";
1220 for( unsigned i=0; i<Trk::numberOfDetectorTypes; i++) {
1221 msg += Form("%u", ( trk->hitPattern() >> i ) & 1 );
1222 }
1223 ATH_MSG_DEBUG( " > " << __FUNCTION__ << ": " << msg );
1224
1225 std::vector<unsigned> matchedLayers;
1226
1227 for( unsigned i=0; i<Trk::numberOfDetectorTypes; i++) {
1228 const unsigned recordedPattern = ( (trk->hitPattern()>>i) & 1 );
1229
1230 if( expectedHitPattern.at(i) == kMayHaveHit ) {
1231 matchedLayers.emplace_back( i );
1232 } else if( expectedHitPattern.at(i) == kShouldHaveHit ) {
1233 if( expectedHitPattern.at(i) != recordedPattern ) {
1234 break;
1235 } else {
1236 matchedLayers.emplace_back( i );
1237 }
1238 } else {
1239 if( expectedHitPattern.at(i) != recordedPattern ) {
1240 break;
1241 }
1242 }
1243
1244 }
1245
1246 uint8_t PixelHits = 0;
1247 uint8_t SctHits = 0;
1248 uint8_t TRTHits = 0;
1249 if( !(trk->summaryValue( PixelHits, xAOD::numberOfPixelHits ) ) ) PixelHits =0;
1250 if( !(trk->summaryValue( SctHits, xAOD::numberOfSCTHits ) ) ) SctHits =0;
1251 if( !(trk->summaryValue( TRTHits, xAOD::numberOfTRTHits ) ) ) TRTHits =0;
1252
1253 auto dphi = trk->phi() - vertex.phi();
1254 while( dphi > TMath::Pi() ) dphi -= TMath::TwoPi();
1255 while( dphi < -TMath::Pi() ) dphi += TMath::TwoPi();
1256
1257 ATH_MSG_DEBUG( " > " << __FUNCTION__ << ": vtx phi = " << vertex.phi() << ", track phi = " << trk->phi() << ", dphi = " << dphi
1258 << ", oppositeFlag = " << oppositeFlag
1259 << ", nPixelHits = " << static_cast<int>(PixelHits)
1260 << ", nSCTHits = " << static_cast<int>(SctHits)
1261 << ", nTRTHits = " << static_cast<int>(TRTHits)
1262 << ", nMatchedLayers = " << matchedLayers.size() );
1263
1264 if( PixelHits == 0 && vertex.perp() > 300. ) {
1265 ATH_MSG_DEBUG( " > " << __FUNCTION__ << ": vertex r > 300 mm, w/o no pixel hits" );
1266 }
1267
1268
1269 // Requires the first 2 layers with the hit matches.
1270 if( matchedLayers.size() < 2 ) return false;
1271
1272 // In case of the first matched layer is not within pixel barrel, requires the first 4 layers with the hit match
1273 if( matchedLayers.at(0) >= Trk::pixelEndCap0 ) {
1274 if( matchedLayers.size() < 4 ) return false;
1275 }
1276
1277 // Sometimes the vertex is reconstructed at the opposite phi direction.
1278 // In this case, the pattern match may pass.
1279 // This can be avoided by requiring that the
1280 if( oppositeFlag ) return false;
1281
1282 // The following condition should apply for vertices outer than IBL.
1283 if( false /*matchedLayers.at(0) > Trk::pixelBarrel0*/ ) {
1284
1285 // If the dphi (defined above) is opposite, reject.
1286 if( fabs( dphi ) > TMath::Pi()/2.0 ) return false;
1287
1288 // If the track is not within the forward hemisphere to the vertex, reject.
1289 TVector3 trkP; trkP.SetPtEtaPhi( trk->pt(), trk->eta(), trk->phi() );
1290 TVector3 vtx; vtx.SetXYZ( vertex.x(), vertex.y(), vertex.z() );
1291 if( trkP.Dot( vtx ) < 0. ) return false;
1292
1293 }
1294
1295 return true;
1296 }
1297
1298
1299 //____________________________________________________________________________________________________
1300 bool VrtSecInclusive::patternCheckRun2( const uint32_t& pattern, const Amg::Vector3D& vertex ) {
1301
1302 //
1303 // rough guesses for active layers:
1304 // BeamPipe: 23.5-24.3
1305 // IBL: 31.0-38.4
1306 // Pix0 (BLayer): 47.7-54.4, Pix1: 85.5-92.2, Pix2: 119.3-126.1
1307 // Sct0: 290-315, Sct1: 360-390, Sct2: 430-460, Sct3:500-530
1308 //
1309
1310 const double rad = vertex.perp();
1311 const double absz = fabs( vertex.z() );
1312
1313 // vertex area classification
1314 enum vertexArea {
1315 insideBeamPipe,
1316
1317 insidePixelBarrel0,
1318 aroundPixelBarrel0,
1319
1320 outsidePixelBarrel0_and_insidePixelBarrel1,
1321 aroundPixelBarrel1,
1322
1323 outsidePixelBarrel1_and_insidePixelBarrel2,
1324 aroundPixelBarrel2,
1325
1326 outsidePixelBarrel2_and_insidePixelBarrel3,
1327 aroundPixelBarrel3,
1328
1329 outsidePixelBarrel3_and_insideSctBarrel0,
1330 aroundSctBarrel0,
1331
1332 outsideSctBarrel0_and_insideSctBarrel1,
1333 aroundSctBarrel1,
1334 };
1335
1336 // Mutually exclusive vertex position pattern
1337 int vertex_pattern = 0;
1338 if( rad < 23.50 ) {
1339 vertex_pattern = insideBeamPipe;
1340
1341 } else if( rad < 31.0 && absz < 331.5 ) {
1342 vertex_pattern = insidePixelBarrel0;
1343
1344 } else if( rad < 38.4 && absz < 331.5 ) {
1345 vertex_pattern = aroundPixelBarrel0;
1346
1347 } else if( rad < 47.7 && absz < 400.5 ) {
1348 vertex_pattern = outsidePixelBarrel0_and_insidePixelBarrel1;
1349
1350 } else if( rad < 54.4 && absz < 400.5 ) {
1351 vertex_pattern = aroundPixelBarrel1;
1352
1353 } else if( rad < 85.5 && absz < 400.5 ) {
1354 vertex_pattern = outsidePixelBarrel1_and_insidePixelBarrel2;
1355
1356 } else if( rad < 92.2 && absz < 400.5 ) {
1357 vertex_pattern = aroundPixelBarrel2;
1358
1359 } else if( rad < 119.3 && absz < 400.5 ) {
1360 vertex_pattern = outsidePixelBarrel2_and_insidePixelBarrel3;
1361
1362 } else if( rad < 126.1 && absz < 400.5 ) {
1363 vertex_pattern = aroundPixelBarrel3;
1364
1365 } else if( rad < 290 && absz < 749.0 ) {
1366 vertex_pattern = outsidePixelBarrel3_and_insideSctBarrel0;
1367
1368 } else if( rad < 315 && absz < 749.0 ) {
1369 vertex_pattern = aroundSctBarrel0;
1370
1371 } else if( rad < 360 && absz < 749.0 ) {
1372 vertex_pattern = outsideSctBarrel0_and_insideSctBarrel1;
1373
1374 } else if( rad < 390 && absz < 749.0 ) {
1375 vertex_pattern = aroundSctBarrel1;
1376
1377 } else {
1378 }
1379
1380 unsigned nPixelLayers { 0 };
1381 {
1382 if ( pattern & (1 << Trk::pixelBarrel0) ) nPixelLayers++;
1383 if ( pattern & (1 << Trk::pixelBarrel1) ) nPixelLayers++;
1384 if ( pattern & (1 << Trk::pixelBarrel2) ) nPixelLayers++;
1385 if ( pattern & (1 << Trk::pixelBarrel3) ) nPixelLayers++;
1386 if ( pattern & (1 << Trk::pixelEndCap0) ) nPixelLayers++;
1387 if ( pattern & (1 << Trk::pixelEndCap1) ) nPixelLayers++;
1388 if ( pattern & (1 << Trk::pixelEndCap2) ) nPixelLayers++;
1389 }
1390
1392 if( vertex_pattern == insideBeamPipe ) {
1393
1394 if( ! (pattern & (1<<Trk::pixelBarrel0)) ) return false;
1395 if( nPixelLayers < 3 ) return false;
1396
1397
1398 } else if( vertex_pattern == insidePixelBarrel0 ) {
1399
1400 if( ! (pattern & (1<<Trk::pixelBarrel0)) ) return false;
1401 if( nPixelLayers < 3 ) return false;
1402 }
1403
1404
1405 else if( vertex_pattern == aroundPixelBarrel0 ) {
1406
1407 // require nothing for PixelBarrel0
1408 if( ! (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1409 if( nPixelLayers < 2 ) return false;
1410 }
1411
1412
1413 else if( vertex_pattern == outsidePixelBarrel0_and_insidePixelBarrel1 ) {
1414
1415 if( (pattern & (1<<Trk::pixelBarrel0)) ) return false;
1416 if( ! (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1417 if( nPixelLayers < 2 ) return false;
1418 }
1419
1420
1421 else if( vertex_pattern == aroundPixelBarrel1 ) {
1422
1423 if( (pattern & (1<<Trk::pixelBarrel0)) ) return false;
1424 // require nothing for PixelBarrel
1425 if( ! (pattern & (1<<Trk::pixelBarrel2)) ) return false;
1426 if( nPixelLayers < 2 ) return false;
1427 }
1428
1429
1430 else if( vertex_pattern == outsidePixelBarrel1_and_insidePixelBarrel2 ) {
1431
1432 if( (pattern & (1<<Trk::pixelBarrel0)) ) return false;
1433 if( (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1434 if( ! (pattern & (1<<Trk::pixelBarrel2)) ) return false;
1435 if( nPixelLayers < 2 ) return false;
1436 }
1437
1438
1439 else if( vertex_pattern == aroundPixelBarrel2 ) {
1440
1441 if( (pattern & (1<<Trk::pixelBarrel0)) ) return false;
1442 if( (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1443 // require nothing for PixelBarrel2
1444 if( ! (pattern & (1<<Trk::pixelBarrel3)) ) return false;
1445 }
1446
1447
1448 else if( vertex_pattern == outsidePixelBarrel2_and_insidePixelBarrel3 ) {
1449
1450 if( (pattern & (1<<Trk::pixelBarrel0)) ) return false;
1451 if( (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1452 if( (pattern & (1<<Trk::pixelBarrel2)) ) return false;
1453 if( ! (pattern & (1<<Trk::pixelBarrel3)) ) return false;
1454 }
1455
1456 else if( vertex_pattern == aroundPixelBarrel3 ) {
1457
1458 if( (pattern & (1<<Trk::pixelBarrel0)) ) return false;
1459 if( (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1460 if( (pattern & (1<<Trk::pixelBarrel2)) ) return false;
1461 // require nothing for PixelBarrel3
1462 if( ! (pattern & (1<<Trk::sctBarrel0)) ) return false;
1463 }
1464
1465
1466 else if( vertex_pattern == outsidePixelBarrel3_and_insideSctBarrel0 ) {
1467
1468 if( (pattern & (1<<Trk::pixelBarrel0)) ) return false;
1469 if( (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1470 if( (pattern & (1<<Trk::pixelBarrel2)) ) return false;
1471 if( (pattern & (1<<Trk::pixelBarrel3)) ) return false;
1472 if( ! (pattern & (1<<Trk::sctBarrel0)) ) return false;
1473 }
1474
1475
1476 else if( vertex_pattern == aroundSctBarrel0 ) {
1477
1478 if( (pattern & (1<<Trk::pixelBarrel0)) ) return false;
1479 if( (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1480 if( (pattern & (1<<Trk::pixelBarrel2)) ) return false;
1481 if( (pattern & (1<<Trk::pixelBarrel3)) ) return false;
1482 // require nothing for SctBarrel0
1483 if( ! (pattern & (1<<Trk::sctBarrel1)) ) return false;
1484 }
1485
1486
1487 else if( vertex_pattern == outsideSctBarrel0_and_insideSctBarrel1 ) {
1488
1489 if( (pattern & (1<<Trk::pixelBarrel0)) ) return false;
1490 if( (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1491 if( (pattern & (1<<Trk::pixelBarrel2)) ) return false;
1492 if( (pattern & (1<<Trk::pixelBarrel3)) ) return false;
1493 if( (pattern & (1<<Trk::sctBarrel0)) ) return false;
1494 if( ! (pattern & (1<<Trk::sctBarrel1)) ) return false;
1495 }
1496
1497
1498 else if( vertex_pattern == aroundSctBarrel1 ) {
1499 if( (pattern & (1<<Trk::pixelBarrel0)) ) return false;
1500 if( (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1501 if( (pattern & (1<<Trk::pixelBarrel2)) ) return false;
1502 if( (pattern & (1<<Trk::pixelBarrel3)) ) return false;
1503 if( (pattern & (1<<Trk::sctBarrel0)) ) return false;
1504 // require nothing for SctBarrel1
1505 if( ! (pattern & (1<<Trk::sctBarrel2)) ) return false;
1506 }
1508
1509 return true;
1510
1511 }
1512
1513 //____________________________________________________________________________________________________
1514 bool VrtSecInclusive::patternCheckRun2OuterOnly( const uint32_t& pattern, const Amg::Vector3D& vertex ) {
1515
1516 //
1517 // rough guesses for active layers:
1518 // BeamPipe: 23.5-24.3
1519 // IBL: 31.0-38.4
1520 // Pix0 (BLayer): 47.7-54.4, Pix1: 85.5-92.2, Pix2: 119.3-126.1
1521 // Sct0: 290-315, Sct1: 360-390, Sct2: 430-460, Sct3:500-530
1522 //
1523
1524 const double rad = vertex.perp();
1525 const double absz = fabs( vertex.z() );
1526
1527 // vertex area classification
1528 enum vertexArea {
1529 insideBeamPipe,
1530
1531 insidePixelBarrel0,
1532 aroundPixelBarrel0,
1533
1534 outsidePixelBarrel0_and_insidePixelBarrel1,
1535 aroundPixelBarrel1,
1536
1537 outsidePixelBarrel1_and_insidePixelBarrel2,
1538 aroundPixelBarrel2,
1539
1540 outsidePixelBarrel2_and_insidePixelBarrel3,
1541 aroundPixelBarrel3,
1542
1543 outsidePixelBarrel3_and_insideSctBarrel0,
1544 aroundSctBarrel0,
1545
1546 outsideSctBarrel0_and_insideSctBarrel1,
1547 aroundSctBarrel1,
1548 };
1549
1550 // Mutually exclusive vertex position pattern
1551 int vertex_pattern = 0;
1552 if( rad < 23.50 ) {
1553 vertex_pattern = insideBeamPipe;
1554
1555 } else if( rad < 31.0 && absz < 331.5 ) {
1556 vertex_pattern = insidePixelBarrel0;
1557
1558 } else if( rad < 38.4 && absz < 331.5 ) {
1559 vertex_pattern = aroundPixelBarrel0;
1560
1561 } else if( rad < 47.7 && absz < 400.5 ) {
1562 vertex_pattern = outsidePixelBarrel0_and_insidePixelBarrel1;
1563
1564 } else if( rad < 54.4 && absz < 400.5 ) {
1565 vertex_pattern = aroundPixelBarrel1;
1566
1567 } else if( rad < 85.5 && absz < 400.5 ) {
1568 vertex_pattern = outsidePixelBarrel1_and_insidePixelBarrel2;
1569
1570 } else if( rad < 92.2 && absz < 400.5 ) {
1571 vertex_pattern = aroundPixelBarrel2;
1572
1573 } else if( rad < 119.3 && absz < 400.5 ) {
1574 vertex_pattern = outsidePixelBarrel2_and_insidePixelBarrel3;
1575
1576 } else if( rad < 126.1 && absz < 400.5 ) {
1577 vertex_pattern = aroundPixelBarrel3;
1578
1579 } else if( rad < 290 && absz < 749.0 ) {
1580 vertex_pattern = outsidePixelBarrel3_and_insideSctBarrel0;
1581
1582 } else if( rad < 315 && absz < 749.0 ) {
1583 vertex_pattern = aroundSctBarrel0;
1584
1585 } else if( rad < 360 && absz < 749.0 ) {
1586 vertex_pattern = outsideSctBarrel0_and_insideSctBarrel1;
1587
1588 } else if( rad < 390 && absz < 749.0 ) {
1589 vertex_pattern = aroundSctBarrel1;
1590
1591 } else {
1592 }
1593
1594
1595 unsigned nPixelLayers { 0 };
1596 {
1597 nPixelLayers += ( pattern & (1 << Trk::pixelBarrel0) );
1598 nPixelLayers += ( pattern & (1 << Trk::pixelBarrel1) );
1599 nPixelLayers += ( pattern & (1 << Trk::pixelBarrel2) );
1600 nPixelLayers += ( pattern & (1 << Trk::pixelBarrel3) );
1601 nPixelLayers += ( pattern & (1 << Trk::pixelEndCap0) );
1602 nPixelLayers += ( pattern & (1 << Trk::pixelEndCap1) );
1603 nPixelLayers += ( pattern & (1 << Trk::pixelEndCap2) );
1604 }
1605
1607 if( vertex_pattern == insideBeamPipe ) {
1608
1609 if( ! (pattern & (1<<Trk::pixelBarrel0)) ) return false;
1610 if( ! (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1611 if( nPixelLayers < 3 ) return false;
1612
1613 } else if( vertex_pattern == insidePixelBarrel0 ) {
1614
1615 if( ! (pattern & (1<<Trk::pixelBarrel0)) ) return false;
1616 if( ! (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1617 if( nPixelLayers < 3 ) return false;
1618
1619 }
1620
1621
1622 else if( vertex_pattern == aroundPixelBarrel0 ) {
1623
1624 // require nothing for PixelBarrel0
1625 if( ! (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1626 if( ! (pattern & (1<<Trk::pixelBarrel2)) ) return false;
1627 if( nPixelLayers < 3 ) return false;
1628 }
1629
1630
1631 else if( vertex_pattern == outsidePixelBarrel0_and_insidePixelBarrel1 ) {
1632
1633 if( ! (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1634 if( ! (pattern & (1<<Trk::pixelBarrel2)) ) return false;
1635 if( nPixelLayers < 3 ) return false;
1636 }
1637
1638
1639 else if( vertex_pattern == aroundPixelBarrel1 ) {
1640
1641 // require nothing for PixelBarrel1
1642 if( ! (pattern & (1<<Trk::pixelBarrel2)) ) return false;
1643 if( ! (pattern & (1<<Trk::pixelBarrel3)) ) return false;
1644 if( nPixelLayers < 2 ) return false;
1645 }
1646
1647
1648 else if( vertex_pattern == outsidePixelBarrel1_and_insidePixelBarrel2 ) {
1649
1650 if( ! (pattern & (1<<Trk::pixelBarrel2)) ) return false;
1651 if( ! (pattern & (1<<Trk::pixelBarrel3)) ) return false;
1652 if( nPixelLayers < 2 ) return false;
1653 }
1654
1655
1656 else if( vertex_pattern == aroundPixelBarrel2 ) {
1657
1658 // require nothing for PixelBarrel2
1659 if( ! (pattern & (1<<Trk::pixelBarrel3)) ) return false;
1660 }
1661
1662
1663 else if( vertex_pattern == outsidePixelBarrel2_and_insidePixelBarrel3 ) {
1664
1665 if( ! (pattern & (1<<Trk::pixelBarrel3)) ) return false;
1666 }
1667
1668 else if( vertex_pattern == aroundPixelBarrel3 ) {
1669
1670 // require nothing for PixelBarrel3
1671 if( ! (pattern & (1<<Trk::sctBarrel0)) ) return false;
1672 if( ! (pattern & (1<<Trk::sctBarrel1)) ) return false;
1673 }
1674
1675
1676 else if( vertex_pattern == outsidePixelBarrel3_and_insideSctBarrel0 ) {
1677
1678 if( ! (pattern & (1<<Trk::sctBarrel0)) ) return false;
1679 if( ! (pattern & (1<<Trk::sctBarrel1)) ) return false;
1680 }
1681
1682
1683 else if( vertex_pattern == aroundSctBarrel0 ) {
1684
1685 // require nothing for SctBarrel0
1686 if( ! (pattern & (1<<Trk::sctBarrel1)) ) return false;
1687 if( ! (pattern & (1<<Trk::sctBarrel2)) ) return false;
1688 }
1689
1690
1691 else if( vertex_pattern == outsideSctBarrel0_and_insideSctBarrel1 ) {
1692
1693 if( ! (pattern & (1<<Trk::sctBarrel1)) ) return false;
1694 if( ! (pattern & (1<<Trk::sctBarrel2)) ) return false;
1695 }
1696
1697
1698 else if( vertex_pattern == aroundSctBarrel1 ) {
1699 // require nothing for SctBarrel1
1700 if( ! (pattern & (1<<Trk::sctBarrel2)) ) return false;
1701 if( ! (pattern & (1<<Trk::sctBarrel3)) ) return false;
1702 }
1704
1705 return true;
1706
1707 }
1708
1709 //____________________________________________________________________________________________________
1710 bool VrtSecInclusive::patternCheckRun1( const uint32_t& pattern, const Amg::Vector3D& vertex ) {
1711 //
1712 // rough guesses for active layers:
1713 // BeamPipe: 25.0
1714 // Pix0 (BLayer): 47.7-54.4, Pix1: 85.5-92.2, Pix2: 119.3-126.1
1715 // Sct0: 290-315, Sct1: 360-390, Sct2: 430-460, Sct3:500-530
1716 //
1717
1718 const double rad = vertex.perp();
1719 const double absz = fabs( vertex.z() );
1720
1721 // vertex area classification
1722 enum vertexArea {
1723 insideBeamPipe,
1724
1725 insidePixelBarrel1,
1726 aroundPixelBarrel1,
1727
1728 outsidePixelBarrel1_and_insidePixelBarrel2,
1729 aroundPixelBarrel2,
1730
1731 outsidePixelBarrel2_and_insidePixelBarrel3,
1732 aroundPixelBarrel3,
1733
1734 outsidePixelBarrel3_and_insideSctBarrel0,
1735 aroundSctBarrel0,
1736
1737 outsideSctBarrel0_and_insideSctBarrel1,
1738 aroundSctBarrel1,
1739 };
1740
1741 // Mutually exclusive vertex position pattern
1742 Int_t vertex_pattern = 0;
1743 if( rad < 25.00 ) {
1744 vertex_pattern = insideBeamPipe;
1745
1746 } else if( rad < 47.7 && absz < 400.5 ) {
1747 vertex_pattern = insidePixelBarrel1;
1748
1749 } else if( rad < 54.4 && absz < 400.5 ) {
1750 vertex_pattern = aroundPixelBarrel1;
1751
1752 } else if( rad < 85.5 && absz < 400.5 ) {
1753 vertex_pattern = outsidePixelBarrel1_and_insidePixelBarrel2;
1754
1755 } else if( rad < 92.2 && absz < 400.5 ) {
1756 vertex_pattern = aroundPixelBarrel2;
1757
1758 } else if( rad < 119.3 && absz < 400.5 ) {
1759 vertex_pattern = outsidePixelBarrel2_and_insidePixelBarrel3;
1760
1761 } else if( rad < 126.1 && absz < 400.5 ) {
1762 vertex_pattern = aroundPixelBarrel3;
1763
1764 } else if( rad < 290 && absz < 749.0 ) {
1765 vertex_pattern = outsidePixelBarrel3_and_insideSctBarrel0;
1766
1767 } else if( rad < 315 && absz < 749.0 ) {
1768 vertex_pattern = aroundSctBarrel0;
1769
1770 } else if( rad < 360 && absz < 749.0 ) {
1771 vertex_pattern = outsideSctBarrel0_and_insideSctBarrel1;
1772
1773 } else if( rad < 390 && absz < 749.0 ) {
1774 vertex_pattern = aroundSctBarrel1;
1775
1776 } else {
1777 }
1778
1779
1781 if( vertex_pattern == insideBeamPipe ) {
1782
1783 if( ! (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1784
1785 }
1786
1787
1788 else if( vertex_pattern == insidePixelBarrel1 ) {
1789
1790 if( ! (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1791 }
1792
1793
1794 else if( vertex_pattern == aroundPixelBarrel1 ) {
1795
1796 // require nothing for PixelBarrel1
1797 if( ! (pattern & (1<<Trk::pixelBarrel2)) ) return false;
1798 }
1799
1800
1801 else if( vertex_pattern == outsidePixelBarrel1_and_insidePixelBarrel2 ) {
1802
1803 if( (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1804 if( ! (pattern & (1<<Trk::pixelBarrel2)) ) return false;
1805 }
1806
1807
1808 else if( vertex_pattern == aroundPixelBarrel2 ) {
1809
1810 if( (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1811 // require nothing for PixelBarrel2
1812 if( ! (pattern & (1<<Trk::pixelBarrel3)) ) return false;
1813 }
1814
1815
1816 else if( vertex_pattern == outsidePixelBarrel2_and_insidePixelBarrel3 ) {
1817
1818 if( (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1819 if( (pattern & (1<<Trk::pixelBarrel2)) ) return false;
1820 if( ! (pattern & (1<<Trk::pixelBarrel3)) ) return false;
1821 }
1822
1823 else if( vertex_pattern == aroundPixelBarrel3 ) {
1824
1825 if( (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1826 if( (pattern & (1<<Trk::pixelBarrel2)) ) return false;
1827 // require nothing for PixelBarrel3
1828 if( ! (pattern & (1<<Trk::sctBarrel0)) ) return false;
1829 }
1830
1831
1832 else if( vertex_pattern == outsidePixelBarrel3_and_insideSctBarrel0 ) {
1833
1834 if( (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1835 if( (pattern & (1<<Trk::pixelBarrel2)) ) return false;
1836 if( (pattern & (1<<Trk::pixelBarrel3)) ) return false;
1837 if( ! (pattern & (1<<Trk::sctBarrel0)) ) return false;
1838 }
1839
1840
1841 else if( vertex_pattern == aroundSctBarrel0 ) {
1842
1843 if( (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1844 if( (pattern & (1<<Trk::pixelBarrel2)) ) return false;
1845 if( (pattern & (1<<Trk::pixelBarrel3)) ) return false;
1846 // require nothing for SctBarrel0
1847 if( ! (pattern & (1<<Trk::sctBarrel1)) ) return false;
1848 }
1849
1850
1851 else if( vertex_pattern == outsideSctBarrel0_and_insideSctBarrel1 ) {
1852
1853 if( (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1854 if( (pattern & (1<<Trk::pixelBarrel2)) ) return false;
1855 if( (pattern & (1<<Trk::pixelBarrel3)) ) return false;
1856 if( (pattern & (1<<Trk::sctBarrel0)) ) return false;
1857 if( ! (pattern & (1<<Trk::sctBarrel1)) ) return false;
1858 }
1859
1860
1861 else if( vertex_pattern == aroundSctBarrel1 ) {
1862 if( (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1863 if( (pattern & (1<<Trk::pixelBarrel2)) ) return false;
1864 if( (pattern & (1<<Trk::pixelBarrel3)) ) return false;
1865 if( (pattern & (1<<Trk::sctBarrel0)) ) return false;
1866 // require nothing for SctBarrel1
1867 if( ! (pattern & (1<<Trk::sctBarrel2)) ) return false;
1868 }
1870
1871 return true;
1872 }
1873
1874 //____________________________________________________________________________________________________
1875 bool VrtSecInclusive::patternCheckRun1OuterOnly( const uint32_t& pattern, const Amg::Vector3D& vertex ) {
1876 //
1877 // rough guesses for active layers:
1878 // BeamPipe: 25.0
1879 // Pix0 (BLayer): 47.7-54.4, Pix1: 85.5-92.2, Pix2: 119.3-126.1
1880 // Sct0: 290-315, Sct1: 360-390, Sct2: 430-460, Sct3:500-530
1881 //
1882
1883 const double rad = vertex.perp();
1884 const double absz = fabs( vertex.z() );
1885
1886 // vertex area classification
1887 enum vertexArea {
1888 insideBeamPipe,
1889
1890 insidePixelBarrel1,
1891 aroundPixelBarrel1,
1892
1893 outsidePixelBarrel1_and_insidePixelBarrel2,
1894 aroundPixelBarrel2,
1895
1896 outsidePixelBarrel2_and_insidePixelBarrel3,
1897 aroundPixelBarrel3,
1898
1899 outsidePixelBarrel3_and_insideSctBarrel0,
1900 aroundSctBarrel0,
1901
1902 outsideSctBarrel0_and_insideSctBarrel1,
1903 aroundSctBarrel1,
1904 };
1905
1906 // Mutually exclusive vertex position pattern
1907 Int_t vertex_pattern = 0;
1908 if( rad < 25.00 ) {
1909 vertex_pattern = insideBeamPipe;
1910
1911 } else if( rad < 47.7 && absz < 400.5 ) {
1912 vertex_pattern = insidePixelBarrel1;
1913
1914 } else if( rad < 54.4 && absz < 400.5 ) {
1915 vertex_pattern = aroundPixelBarrel1;
1916
1917 } else if( rad < 85.5 && absz < 400.5 ) {
1918 vertex_pattern = outsidePixelBarrel1_and_insidePixelBarrel2;
1919
1920 } else if( rad < 92.2 && absz < 400.5 ) {
1921 vertex_pattern = aroundPixelBarrel2;
1922
1923 } else if( rad < 119.3 && absz < 400.5 ) {
1924 vertex_pattern = outsidePixelBarrel2_and_insidePixelBarrel3;
1925
1926 } else if( rad < 126.1 && absz < 400.5 ) {
1927 vertex_pattern = aroundPixelBarrel3;
1928
1929 } else if( rad < 290 && absz < 749.0 ) {
1930 vertex_pattern = outsidePixelBarrel3_and_insideSctBarrel0;
1931
1932 } else if( rad < 315 && absz < 749.0 ) {
1933 vertex_pattern = aroundSctBarrel0;
1934
1935 } else if( rad < 360 && absz < 749.0 ) {
1936 vertex_pattern = outsideSctBarrel0_and_insideSctBarrel1;
1937
1938 } else if( rad < 390 && absz < 749.0 ) {
1939 vertex_pattern = aroundSctBarrel1;
1940
1941 } else {
1942 }
1943
1944
1946 if( vertex_pattern == insideBeamPipe ) {
1947
1948 if( ! (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1949
1950 }
1951
1952
1953 else if( vertex_pattern == insidePixelBarrel1 ) {
1954
1955 if( ! (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1956 }
1957
1958
1959 else if( vertex_pattern == aroundPixelBarrel1 ) {
1960
1961 // require nothing for PixelBarrel1
1962 if( ! (pattern & (1<<Trk::pixelBarrel2)) ) return false;
1963 }
1964
1965
1966 else if( vertex_pattern == outsidePixelBarrel1_and_insidePixelBarrel2 ) {
1967
1968 if( ! (pattern & (1<<Trk::pixelBarrel2)) ) return false;
1969 }
1970
1971
1972 else if( vertex_pattern == aroundPixelBarrel2 ) {
1973
1974 // require nothing for PixelBarrel2
1975 if( ! (pattern & (1<<Trk::pixelBarrel3)) ) return false;
1976 }
1977
1978
1979 else if( vertex_pattern == outsidePixelBarrel2_and_insidePixelBarrel3 ) {
1980
1981 if( ! (pattern & (1<<Trk::pixelBarrel3)) ) return false;
1982 }
1983
1984 else if( vertex_pattern == aroundPixelBarrel3 ) {
1985
1986 // require nothing for PixelBarrel3
1987 if( ! (pattern & (1<<Trk::sctBarrel0)) ) return false;
1988 }
1989
1990
1991 else if( vertex_pattern == outsidePixelBarrel3_and_insideSctBarrel0 ) {
1992
1993 if( ! (pattern & (1<<Trk::sctBarrel0)) ) return false;
1994 }
1995
1996
1997 else if( vertex_pattern == aroundSctBarrel0 ) {
1998
1999 // require nothing for SctBarrel0
2000 if( ! (pattern & (1<<Trk::sctBarrel1)) ) return false;
2001 }
2002
2003
2004 else if( vertex_pattern == outsideSctBarrel0_and_insideSctBarrel1 ) {
2005
2006 if( ! (pattern & (1<<Trk::sctBarrel1)) ) return false;
2007 }
2008
2009
2010 else if( vertex_pattern == aroundSctBarrel1 ) {
2011 // require nothing for SctBarrel1
2012 if( ! (pattern & (1<<Trk::sctBarrel2)) ) return false;
2013 }
2015
2016 return true;
2017 }
2018
2019 //____________________________________________________________________________________________________
2020 bool VrtSecInclusive::patternCheck( const uint32_t& pattern, const Amg::Vector3D& vertex ) {
2021 bool flag = false;
2022
2024 flag = patternCheckRun2( pattern, vertex );
2026 flag = patternCheckRun1( pattern, vertex );
2027 }
2028
2029 return flag;
2030 }
2031
2032 //____________________________________________________________________________________________________
2033 bool VrtSecInclusive::patternCheckOuterOnly( const uint32_t& pattern, const Amg::Vector3D& vertex ) {
2034 bool flag = false;
2035
2037 flag = patternCheckRun2OuterOnly( pattern, vertex );
2039 flag = patternCheckRun1OuterOnly( pattern, vertex );
2040 }
2041
2042 return flag;
2043 }
2044
2045 //____________________________________________________________________________________________________
2047 {
2048
2049 const uint32_t pattern = trk->hitPattern();
2050
2051 return patternCheck( pattern, vertex );
2052
2053 }
2054
2055
2056 //____________________________________________________________________________________________________
2058 {
2059
2060 const uint32_t pattern = trk->hitPattern();
2061
2062 return patternCheckOuterOnly( pattern, vertex );
2063
2064 }
2065
2066
2067 //____________________________________________________________________________________________________
2069 {
2070
2071 if( m_extrapolatedPatternBank.find( trk ) == m_extrapolatedPatternBank.end() ) {
2072
2073 std::unique_ptr<ExtrapolatedPattern> exPattern_along( extrapolatedPattern( trk, Trk::alongMomentum ) );
2074
2075 m_extrapolatedPatternBank.emplace( trk, std::make_pair( std::move(exPattern_along), nullptr ) );
2076
2077 }
2078
2079 if( vertex.perp() < 31.0 ) {
2080 double dphi = trk->phi() - vertex.phi();
2081 while( dphi > TMath::Pi() ) { dphi -= TMath::TwoPi(); }
2082 while( dphi < -TMath::Pi() ) { dphi += TMath::TwoPi(); }
2083 if( cos(dphi) < -0.8 ) return false;
2084 }
2085
2086 auto& exPattern = m_extrapolatedPatternBank.at( trk );
2087
2088 using LayerCombination = std::vector<int>;
2089
2090 std::map<LayerCombination, unsigned> layerMap;
2091 if( layerMap.empty() ) {
2092 layerMap[ { 1, 0, 0 } ] = Trk::pixelBarrel0;
2093 layerMap[ { 1, 0, 1 } ] = Trk::pixelBarrel1;
2094 layerMap[ { 1, 0, 2 } ] = Trk::pixelBarrel2;
2095 layerMap[ { 1, 0, 3 } ] = Trk::pixelBarrel3;
2096
2097 layerMap[ { 1, 2, 0 } ] = Trk::pixelEndCap0;
2098 layerMap[ { 1, 2, 1 } ] = Trk::pixelEndCap1;
2099 layerMap[ { 1, 2, 2 } ] = Trk::pixelEndCap2;
2100 layerMap[ { 1,-2, 0 } ] = Trk::pixelEndCap0;
2101 layerMap[ { 1,-2, 1 } ] = Trk::pixelEndCap1;
2102 layerMap[ { 1,-2, 2 } ] = Trk::pixelEndCap2;
2103
2104 layerMap[ { 2, 0, 0 } ] = Trk::sctBarrel0;
2105 layerMap[ { 2, 0, 1 } ] = Trk::sctBarrel1;
2106 layerMap[ { 2, 0, 2 } ] = Trk::sctBarrel2;
2107 layerMap[ { 2, 0, 3 } ] = Trk::sctBarrel3;
2108
2109 layerMap[ { 2, 2, 0 } ] = Trk::sctEndCap0;
2110 layerMap[ { 2, 2, 1 } ] = Trk::sctEndCap1;
2111 layerMap[ { 2, 2, 2 } ] = Trk::sctEndCap2;
2112 layerMap[ { 2, 2, 3 } ] = Trk::sctEndCap3;
2113 layerMap[ { 2, 2, 4 } ] = Trk::sctEndCap4;
2114 layerMap[ { 2, 2, 5 } ] = Trk::sctEndCap5;
2115 layerMap[ { 2, 2, 6 } ] = Trk::sctEndCap6;
2116 layerMap[ { 2, 2, 7 } ] = Trk::sctEndCap7;
2117 layerMap[ { 2, 2, 8 } ] = Trk::sctEndCap8;
2118 layerMap[ { 2,-2, 0 } ] = Trk::sctEndCap0;
2119 layerMap[ { 2,-2, 1 } ] = Trk::sctEndCap1;
2120 layerMap[ { 2,-2, 2 } ] = Trk::sctEndCap2;
2121 layerMap[ { 2,-2, 3 } ] = Trk::sctEndCap3;
2122 layerMap[ { 2,-2, 4 } ] = Trk::sctEndCap4;
2123 layerMap[ { 2,-2, 5 } ] = Trk::sctEndCap5;
2124 layerMap[ { 2,-2, 6 } ] = Trk::sctEndCap6;
2125 layerMap[ { 2,-2, 7 } ] = Trk::sctEndCap7;
2126 layerMap[ { 2,-2, 8 } ] = Trk::sctEndCap8;
2127 }
2128
2129 enum { position=0, detector=1, bec=2, layer=3, isGood=4 };
2130
2131 // Lambda!
2132 auto getDetectorType = [&]( const ExtrapolatedPoint& point ) -> unsigned {
2133
2134 const LayerCombination comb { std::get<detector>( point ), std::get<bec>( point ), std::get<layer>( point ) };
2135
2136 for( auto& pair : layerMap ) {
2137 if( pair.first == comb ) {
2138 return pair.second;
2139 }
2140 }
2141
2143 };
2144
2145 uint32_t disabledPattern { 0 };
2146
2147 // Loop over extrapolated points (along direction)
2148 auto& exPattern_along = *( exPattern.first );
2149
2150 for( auto itr = exPattern_along.begin(); itr != exPattern_along.end(); ++itr ) {
2151 if( std::next( itr ) == exPattern_along.end() ) continue;
2152
2153 const auto& point = *itr;
2154
2155 ATH_MSG_VERBOSE( " > " << __FUNCTION__ << ": isGood = " << std::get<isGood>( point ) );
2156
2157 if( !std::get<isGood>( point ) ) {
2158 const auto& detectorType = getDetectorType( point );
2159 disabledPattern += (1 << detectorType);
2160 }
2161 }
2162
2163 uint32_t hitPattern = trk->hitPattern();
2164 uint32_t modifiedPattern = disabledPattern | hitPattern;
2165
2166 std::string msg = "Disabled hit pattern: ";
2167 for( unsigned i=0; i<Trk::numberOfDetectorTypes; i++) {
2168 msg += Form("%u", ( disabledPattern >> i ) & 1 );
2169 }
2170 ATH_MSG_DEBUG( " > " << __FUNCTION__ << ": " << msg );
2171
2172 msg = "Recorded hit pattern: ";
2173 for( unsigned i=0; i<Trk::numberOfDetectorTypes; i++) {
2174 msg += Form("%u", ( hitPattern >> i ) & 1 );
2175 }
2176 ATH_MSG_DEBUG( " > " << __FUNCTION__ << ": " << msg );
2177
2178 return patternCheck( modifiedPattern, vertex );
2179
2180 }
2181
2182
2183 //____________________________________________________________________________________________________
2185 const xAOD::TrackParticle *itrk,
2186 const xAOD::TrackParticle *jtrk )
2187 {
2188
2189 const bool& check_itrk = ( this->*m_patternStrategyFuncs[m_checkPatternStrategy] )( itrk, FitVertex );
2190 const bool& check_jtrk = ( this->*m_patternStrategyFuncs[m_checkPatternStrategy] )( jtrk, FitVertex );
2191
2192 return ( check_itrk && check_jtrk );
2193
2194 }
2195
2196
2197 //____________________________________________________________________________________________________
2199 {
2200
2201 const auto& vertex = wrkvrt.vertex;
2202
2203 std::map< std::deque<long int>*, std::vector<const xAOD::TrackParticle*>& > indexMap
2204 {
2206 };
2207
2208 for( auto& pair : indexMap ) {
2209
2210 auto* indices = pair.first;
2211 auto& tracks = pair.second;
2212
2213 auto newEnd = std::remove_if( indices->begin(), indices->end(),
2214 [&]( auto& index ) {
2215 bool isConsistent = (this->*m_patternStrategyFuncs[m_checkPatternStrategy] )( tracks.at(index), vertex );
2216 return !isConsistent;
2217 } );
2218
2219 indices->erase( newEnd, indices->end() );
2220
2221 }
2222
2223 }
2224
2225
2226 //____________________________________________________________________________________________________
2228
2229 const xAOD::EventInfo* eventInfo{};
2230 const xAOD::TruthParticleContainer* truthParticles{};
2231 const xAOD::TruthVertexContainer* truthVertices{};
2232
2233 auto sc0 = evtStore()->retrieve( eventInfo, "EventInfo" );
2234 if( sc0.isFailure() ) { return; }
2235
2236 if( !eventInfo->eventType( xAOD::EventInfo::IS_SIMULATION ) ) {
2237 return;
2238 }
2239
2240 auto sc1 = evtStore()->retrieve( truthParticles, "TruthParticles" );
2241 if( sc1.isFailure() ) { return; }
2242
2243 auto sc2 = evtStore()->retrieve( truthVertices, "TruthVertices" );
2244 if( sc2.isFailure() ) { return; }
2245
2246 if( !truthParticles ) { return; }
2247 if( !truthVertices ) { return; }
2248
2249 m_tracingTruthVertices.clear();
2250
2251 std::vector<const xAOD::TruthParticle*> truthSvTracks;
2252
2253 // truth particle selection functions
2254
2255 auto selectNone = [](const xAOD::TruthVertex*) ->bool { return false; };
2256
2257 auto selectRhadron = [](const xAOD::TruthVertex* truthVertex ) -> bool {
2258 if( truthVertex->nIncomingParticles() != 1 ) return false;
2259 if( !truthVertex->incomingParticle(0) ) return false;
2260 if( abs(truthVertex->incomingParticle(0)->pdgId()) < 1000000 ) return false;
2261 if( abs(truthVertex->incomingParticle(0)->pdgId()) > 1000000000 ) return false; // Nuclear codes, e.g. deuteron
2262 // neutralino in daughters
2263 bool hasNeutralino = false;
2264 for( unsigned ip = 0; ip < truthVertex->nOutgoingParticles(); ip++ ) {
2265 const auto* p = truthVertex->outgoingParticle(ip);
2266 if( abs( p->pdgId() ) == 1000022 ) {
2267 hasNeutralino = true;
2268 break;
2269 }
2270 }
2271 return hasNeutralino;
2272 };
2273
2274 auto selectHNL = [](const xAOD::TruthVertex* truthVertex ) -> bool {
2275 if( truthVertex->nIncomingParticles() != 1 ) return false;
2276 if( !truthVertex->incomingParticle(0) ) return false;
2277 if( abs(truthVertex->incomingParticle(0)->pdgId()) != 50 ) return false;
2278 return true;
2279 };
2280
2281 auto selectHiggs = [](const xAOD::TruthVertex* truthVertex ) -> bool {
2282 if( truthVertex->nIncomingParticles() != 1 ) return false;
2283 if( !truthVertex->incomingParticle(0) ) return false;
2284 if( abs(truthVertex->incomingParticle(0)->pdgId()) != 36 ) return false;
2285 return true;
2286 };
2287
2288 auto selectKshort = [](const xAOD::TruthVertex* truthVertex ) -> bool {
2289 if( truthVertex->nIncomingParticles() != 1 ) return false;
2290 if( !truthVertex->incomingParticle(0) ) return false;
2291 if( abs(truthVertex->incomingParticle(0)->pdgId()) != 310 ) return false;
2292 return true;
2293 };
2294
2295 auto selectBhadron = [](const xAOD::TruthVertex* truthVertex ) -> bool {
2296 if( truthVertex->nIncomingParticles() != 1 ) return false;
2297 if( !truthVertex->incomingParticle(0) ) return false;
2298 if( abs(truthVertex->incomingParticle(0)->pdgId()) <= 500 || abs(truthVertex->incomingParticle(0)->pdgId()) >= 600 ) return false;
2299 return true;
2300 };
2301
2302 auto selectHadInt = [](const xAOD::TruthVertex* truthVertex ) -> bool {
2303 if( truthVertex->nIncomingParticles() != 1 ) return false;
2304 if( !truthVertex->incomingParticle(0) ) return false;
2305
2306 const auto* parent = truthVertex->incomingParticle(0);
2307 if( parent->isLepton() ) return false;
2308
2309 TLorentzVector p4sum_in;
2310 TLorentzVector p4sum_out;
2311 for( unsigned ip = 0; ip < truthVertex->nIncomingParticles(); ip++ ) {
2312 const auto* particle = truthVertex->incomingParticle(ip);
2313 TLorentzVector p4; p4.SetPtEtaPhiM( particle->pt(), particle->eta(), particle->phi(), particle->m() );
2314 p4sum_in += p4;
2315 }
2316 for( unsigned ip = 0; ip < truthVertex->nOutgoingParticles(); ip++ ) {
2317 const auto* particle = truthVertex->outgoingParticle(ip);
2318 TLorentzVector p4; p4.SetPtEtaPhiM( particle->pt(), particle->eta(), particle->phi(), particle->m() );
2319 p4sum_out += p4;
2320 }
2321 return p4sum_out.E() - p4sum_in.E() >= 100.;
2322 };
2323
2324
2325
2326 using ParticleSelectFunc = bool (*)(const xAOD::TruthVertex*);
2327 std::map<std::string, ParticleSelectFunc> selectFuncs { { "", selectNone },
2328 { "Kshort", selectKshort },
2329 { "Bhadron", selectBhadron },
2330 { "Rhadron", selectRhadron },
2331 { "HNL", selectHNL },
2332 { "Higgs", selectHiggs },
2333 { "HadInt", selectHadInt } };
2334
2335
2336 if( selectFuncs.find( m_truthParticleFilter ) == selectFuncs.end() ) {
2337 ATH_MSG_WARNING( " > " << __FUNCTION__ << ": invalid function specification: " << m_truthParticleFilter );
2338 return;
2339 }
2340
2341 auto selectFunc = selectFuncs.at( m_truthParticleFilter );
2342
2343 // loop over truth vertices
2344 for( const auto *truthVertex : *truthVertices ) {
2345 if( selectFunc( truthVertex ) ) {
2346 m_tracingTruthVertices.emplace_back( truthVertex );
2347 std::string msg;
2348 msg += Form("pdgId = %d, (r, z) = (%.2f, %.2f), ", truthVertex->incomingParticle(0)->pdgId(), truthVertex->perp(), truthVertex->z());
2349 msg += Form("nOutgoing = %lu, ", truthVertex->nOutgoingParticles() );
2350 msg += Form("mass = %.3f GeV, pt = %.3f GeV", truthVertex->incomingParticle(0)->m()/1.e3, truthVertex->incomingParticle(0)->pt()/1.e3 );
2351 ATH_MSG_DEBUG( " > " << __FUNCTION__ << ": " << msg );
2352 }
2353 }
2354
2355 if( m_FillHist ) {
2356 for( const auto* truthVertex : m_tracingTruthVertices ) {
2357 m_hists["nMatchedTruths"]->Fill( 0., truthVertex->perp() );
2358 }
2359 }
2360
2361 }
2362
2363} // end of namespace VKalVrtAthena
2364
2365
#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)
#define minValue(current, test)
#define AmgSymMatrix(dim)
static Double_t sc
#define max(a, b)
Definition cfImp.cxx:41
MsgStream & msg() const
size_t index() const
Return the index of this element within its container.
bool patternCheck(const uint32_t &pattern, const Amg::Vector3D &vertex)
std::map< std::string, PatternStrategyFunc > m_patternStrategyFuncs
StatusCode refitVertexWithSuggestion(WrkVrt &, const Amg::Vector3D &)
refit the vertex with suggestion
bool passedFakeReject(const Amg::Vector3D &FitVertex, const xAOD::TrackParticle *itrk, const xAOD::TrackParticle *jtrk)
Flag false if the consistituent tracks are not consistent with the vertex position.
bool checkTrackHitPatternToVertex(const xAOD::TrackParticle *trk, const Amg::Vector3D &vertex)
A classical method with hard-coded geometry.
static bool patternCheckRun1(const uint32_t &pattern, const Amg::Vector3D &vertex)
bool checkTrackHitPatternToVertexByExtrapolationAssist(const xAOD::TrackParticle *trk, const Amg::Vector3D &vertex)
New method with track extrapolation.
void printWrkSet(const std::vector< WrkVrt > *WrkVrtSet, const std::string &name)
print the contents of reconstructed vertices
static bool patternCheckRun2(const uint32_t &pattern, const Amg::Vector3D &vertex)
bool checkTrackHitPatternToVertexByExtrapolation(const xAOD::TrackParticle *trk, const Amg::Vector3D &vertex)
New method with track extrapolation.
ToolHandle< IInDetConditionsTool > m_pixelCondSummaryTool
Condition service.
void trackClassification(std::vector< WrkVrt > *, std::map< long int, std::vector< long int > > &)
ExtrapolatedPattern * extrapolatedPattern(const xAOD::TrackParticle *, enum Trk::PropDirection)
double findWorstChi2ofMaximallySharedTrack(std::vector< WrkVrt > *, std::map< long int, std::vector< long int > > &, long int &, long int &)
std::unique_ptr< NtupleVars > m_ntupleVars
static bool patternCheckRun1OuterOnly(const uint32_t &pattern, const Amg::Vector3D &vertex)
Gaudi::Property< std::string > m_truthParticleFilter
void removeInconsistentTracks(WrkVrt &)
Remove inconsistent tracks from vertices.
ToolHandle< IInDetConditionsTool > m_sctCondSummaryTool
Gaudi::Property< int > m_geoModel
Gaudi::Property< bool > m_FillHist
bool checkTrackHitPatternToVertexOuterOnly(const xAOD::TrackParticle *trk, const Amg::Vector3D &vertex)
A classical method with hard-coded geometry.
std::map< std::string, TH1 * > m_hists
static void fillTrackSummary(track_summary &summary, const xAOD::TrackParticle *trk)
retrieve the track hit information
double improveVertexChi2(WrkVrt &)
attempt to improve the vertex chi2 by removing the most-outlier track one by one until the vertex chi...
double distanceBetweenVertices(const WrkVrt &, const WrkVrt &) const
calculate the physical distance
static size_t nTrkCommon(std::vector< WrkVrt > *WrkVrtSet, const std::pair< unsigned, unsigned > &pairIndex)
returns the number of tracks commonly present in both vertices
static double findMinVerticesNextPair(std::vector< WrkVrt > *, std::pair< unsigned, unsigned > &)
returns the next pair of vertices that give next-to-minimum distance significance
std::tuple< const TVector3, Detector, Bec, Layer, Flag > ExtrapolatedPoint
Gaudi::Property< bool > m_FillNtuple
double findMinVerticesPair(std::vector< WrkVrt > *, std::pair< unsigned, unsigned > &, const AlgForVerticesPair &)
returns the pair of vertices that give minimum in terms of some observable (e.g.
const AtlasDetectorID * m_atlasId
Gaudi::Property< std::string > m_checkPatternStrategy
static void removeTrackFromVertex(std::vector< WrkVrt > *, std::vector< std::deque< long int > > *, const long int &, const long int &)
PublicToolHandle< Trk::IExtrapolator > m_extrapolator
Gaudi::Property< double > m_improveChi2ProbThreshold
std::vector< ExtrapolatedPoint > ExtrapolatedPattern
const xAOD::VertexContainer * m_primaryVertices
StatusCode mergeVertices(WrkVrt &destination, WrkVrt &source)
the 2nd vertex is merged into the 1st vertex.
std::vector< const xAOD::TrackParticle * > m_associatedTracks
ToolHandle< Trk::ITrkVKalVrtFitter > m_fitSvc
std::vector< const xAOD::TrackParticle * > m_selectedTracks
StatusCode disassembleVertex(std::vector< WrkVrt > *, const unsigned &vertexIndex)
double(VrtSecInclusive::*)(const WrkVrt &, const WrkVrt &) const AlgForVerticesPair
bool patternCheckOuterOnly(const uint32_t &pattern, const Amg::Vector3D &vertex)
struct VKalVrtAthena::VrtSecInclusive::track_summary_properties track_summary
static bool patternCheckRun2OuterOnly(const uint32_t &pattern, const Amg::Vector3D &vertex)
std::vector< const xAOD::TruthVertex * > m_tracingTruthVertices
double significanceBetweenVertices(const WrkVrt &, const WrkVrt &) const
calculate the significance (Mahalanobis distance) between two reconstructed vertices
std::map< const xAOD::TruthVertex *, bool > m_matchMap
bool eventType(EventType type) const
Check for one particular bitmask value.
@ IS_SIMULATION
true: simulation, false: data
float z0() const
Returns the parameter.
const Trk::Perigee & perigeeParameters() const
Returns the Trk::MeasuredPerigee track parameters.
virtual double phi() const override final
The azimuthal angle ( ) of the particle (has range to .)
float d0() const
Returns the parameter.
uint32_t hitPattern() const
bool summaryValue(uint8_t &value, const SummaryType &information) const
Accessor for TrackSummary values.
virtual double pt() const override final
The transverse momentum ( ) of the particle.
virtual double eta() const override final
The pseudorapidity ( ) of the particle.
double chi2(TH1 *h0, TH1 *h1)
std::string algorithm
Definition hcg.cxx:85
Eigen::Matrix< double, 3, 1 > Vector3D
PropDirection
PropDirection, enum for direction of the propagation.
@ oppositeMomentum
@ alongMomentum
@ pixelBarrel0
there are three or four pixel barrel layers (R1/R2)
@ pixelEndCap0
three pixel discs (on each side)
const xAOD::TrackParticle * getLeptonTrackParticle(const xAOD::Muon *muon, const unsigned &trackType)
bool isAssociatedToVertices(const xAOD::TrackParticle *trk, const xAOD::VertexContainer *vertices)
double vtxVtxDistance(const Amg::Vector3D &v1, const Amg::Vector3D &v2)
void genSequence(const xAOD::Muon *, std::vector< unsigned > &trackTypes)
Definition index.py:1
STL namespace.
DataModel_detail::iterator< DVL > unique(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of unique for DataVector/List.
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
DataModel_detail::iterator< DVL > remove_if(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end, Predicate pred)
Specialization of remove_if for DataVector/List.
const xAOD::TrackParticle * getOriginalTrackParticleFromGSF(const xAOD::TrackParticle *trkPar)
Helper function for getting the "Original" Track Particle (i.e before GSF) via the GSF Track Particle...
@ PriVtx
Primary vertex.
@ NoVtx
Dummy vertex. TrackParticle was not used in vertex fit.
EventInfo_v1 EventInfo
Definition of the latest event info version.
TruthVertex_v1 TruthVertex
Typedef to implementation.
Definition TruthVertex.h:15
TrackParticle_v1 TrackParticle
Reference the current persistent version:
TruthVertexContainer_v1 TruthVertexContainer
Declare the latest version of the truth vertex container.
VertexContainer_v1 VertexContainer
Definition of the current "Vertex container version".
Muon_v1 Muon
Reference the current persistent version:
@ numberOfTRTHits
number of TRT hits [unit8_t].
@ numberOfNextToInnermostPixelLayerHits
these are the hits in the 1st pixel barrel layer
@ numberOfSCTHits
number of hits in SCT [unit8_t].
@ numberOfInnermostPixelLayerHits
these are the hits in the 0th pixel barrel layer
@ numberOfPixelHits
these are the pixel hits, including the b-layer [unit8_t].
TruthParticleContainer_v1 TruthParticleContainer
Declare the latest version of the truth particle container.
Electron_v1 Electron
Definition of the current "egamma version".
double Chi2
VKalVrt fit covariance.
std::vector< double > vertexCov
VKalVrt fit vertex 4-momentum.
std::vector< double > Chi2PerTrk
VKalVrt fit chi2 result.
std::deque< long int > selectedTrackIndices
flagged true for good vertex candidates
std::deque< long int > associatedTrackIndices
list if indices in TrackParticleContainer for selectedBaseTracks
long int Charge
list of VKalVrt fit chi2 for each track
Amg::Vector3D vertex
list if indices in TrackParticleContainer for associatedTracks
TLorentzVector vertexMom
VKalVrt fit vertex position.
double closestWrkVrtValue
stores the index of the closest WrkVrt in std::vector<WrkVrt>
std::vector< std::vector< double > > TrkAtVrt
total charge of the vertex
unsigned long closestWrkVrtIndex
list of track parameters wrt the reconstructed vertex