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(const EventContext& ctx, 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(ctx);
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( ctx, 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 //____________________________________________________________________________________________________
265 double VrtSecInclusive::improveVertexChi2( const EventContext& ctx, WrkVrt& vertex )
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( ctx, 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( ctx, 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 //____________________________________________________________________________________________________
452 StatusCode VrtSecInclusive::mergeVertices( const EventContext& ctx, WrkVrt& v1, WrkVrt& v2 )
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( ctx, 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( const EventContext& ctx,
497 WrkVrt& workVertex )
498 {
499 std::unique_ptr<Trk::IVKalState> state = m_fitSvc->makeState(ctx);
500 return refitVertex (workVertex, *state);
501 }
502
503
504
505 //____________________________________________________________________________________________________
506 StatusCode VrtSecInclusive::refitVertex( WrkVrt& workVertex,
507 Trk::IVKalState& istate)
508 {
509
510 //
511 vector<const xAOD::NeutralParticle*> dummyNeutrals;
512
513 int nth = workVertex.selectedTrackIndices.size();
514
515 if(nth<2) {
516 workVertex.isGood = false;
517 return StatusCode::SUCCESS;
518 }
519
520 vector<const xAOD::TrackParticle*> ListBaseTracks;
521
522 workVertex.Chi2PerTrk.clear();
523
524 for( const auto& index : workVertex.selectedTrackIndices ) {
525 ListBaseTracks.emplace_back( m_selectedTracks.at( index ) );
526 workVertex.Chi2PerTrk.emplace_back( AlgConsts::chi2PerTrackInitValue );
527 }
528
529 for( const auto& index : workVertex.associatedTrackIndices ) {
530 ListBaseTracks.emplace_back( m_associatedTracks.at( index ) );
531 workVertex.Chi2PerTrk.emplace_back( AlgConsts::chi2PerTrackInitValue );
532 }
533
534 auto& vertexPos = workVertex.vertex;
535
536 m_fitSvc->setApproximateVertex( vertexPos.x(), vertexPos.y(), vertexPos.z(), istate );
537
538 ATH_MSG_VERBOSE( " >>> refitVertex: ListBaseTracks.size = " << ListBaseTracks.size()
539 << ", #selectedBaseTracks = " << workVertex.selectedTrackIndices.size()
540 << ", #assocTracks = " << workVertex.associatedTrackIndices.size() );
541 for( const auto *trk : ListBaseTracks ) {
542 ATH_MSG_VERBOSE( " >>> refitVertex: track index = " << trk->index() );
543 }
544
545 ATH_MSG_VERBOSE( " >>> refitVertex: m_fitSvc is reset." );
546
547 Amg::Vector3D initVertex;
548
549 StatusCode sc = m_fitSvc->VKalVrtFitFast( ListBaseTracks, initVertex, istate );/* Fast crude estimation */
550 if(sc.isFailure()) ATH_MSG_DEBUG(" >>> refitVertex: fast crude estimation failed.");
551 ATH_MSG_VERBOSE( " >>> refitVertex: Fast VKalVrtFit succeeded. vertex (r,z) = (" << initVertex.perp() << ", " << initVertex.z() << ", " << ")" );
552
553 if( vtxVtxDistance( initVertex, vertexPos ) > 10. ) {
554
555 m_fitSvc->setApproximateVertex( vertexPos.x(), vertexPos.y(), vertexPos.z(), istate );
556
557 } else {
558
559 m_fitSvc->setApproximateVertex( initVertex.x(), initVertex.y(), initVertex.z(), istate );
560
561 }
562
563 ATH_MSG_VERBOSE( " >>> refitVertex: approx vertex is set. Now going to perform fitting..." );
564
565 StatusCode SC=m_fitSvc->VKalVrtFit(ListBaseTracks,dummyNeutrals,
566 workVertex.vertex,
567 workVertex.vertexMom,
568 workVertex.Charge,
569 workVertex.vertexCov,
570 workVertex.Chi2PerTrk,
571 workVertex.TrkAtVrt,
572 workVertex.Chi2,
573 istate);
574
575 auto& cov = workVertex.vertexCov;
576
577 if(SC.isFailure()) ATH_MSG_DEBUG(" >>> refitVertex: SC in refitVertex returned failure ");
578 ATH_MSG_VERBOSE(" >>> refitVertex "<<SC<<", "<<ListBaseTracks.size()<<","<<workVertex.Chi2PerTrk.size());
579 ATH_MSG_VERBOSE( " >>> refitVertex: succeeded in fitting. New vertex pos (r,z) = (" << vertexPos.perp() << ", " << vertexPos.z() << ")" );
580 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) << ")" );
581
582 return SC;
583 }
584
585 //____________________________________________________________________________________________________
586 StatusCode VrtSecInclusive::refitVertexWithSuggestion( const EventContext& ctx, WrkVrt& workVertex, const Amg::Vector3D& suggestedPosition )
587 {
588 std::unique_ptr<Trk::IVKalState> state = m_fitSvc->makeState(ctx);
589 return refitVertexWithSuggestion (workVertex, suggestedPosition, *state);
590 }
591
592
593 //____________________________________________________________________________________________________
595 const Amg::Vector3D& suggestedPosition,
596 Trk::IVKalState& istate )
597 {
598
599 //
600 vector<const xAOD::NeutralParticle*> dummyNeutrals;
601
602 int nth = workVertex.selectedTrackIndices.size();
603
604 if(nth<2) {
605 workVertex.isGood = false;
606 return StatusCode::SUCCESS;
607 }
608
609 vector<const xAOD::TrackParticle*> ListBaseTracks;
610
611 workVertex.Chi2PerTrk.clear();
612
613 for( const auto& index : workVertex.selectedTrackIndices ) {
614 ListBaseTracks.emplace_back( m_selectedTracks.at( index ) );
615 workVertex.Chi2PerTrk.emplace_back( AlgConsts::chi2PerTrackInitValue );
616 }
617
618 for( const auto& index : workVertex.associatedTrackIndices ) {
619 ListBaseTracks.emplace_back( m_associatedTracks.at( index ) );
620 workVertex.Chi2PerTrk.emplace_back( AlgConsts::chi2PerTrackInitValue );
621 }
622
623 auto& vertexPos = workVertex.vertex;
624
625 m_fitSvc->setApproximateVertex( suggestedPosition.x(), suggestedPosition.y(), suggestedPosition.z(), istate );
626
627 ATH_MSG_VERBOSE( " >>> " << __FUNCTION__ <<": ListBaseTracks.size = " << ListBaseTracks.size()
628 << ", #selectedBaseTracks = " << workVertex.selectedTrackIndices.size()
629 << ", #assocTracks = " << workVertex.associatedTrackIndices.size() );
630 for( const auto *trk : ListBaseTracks ) {
631 ATH_MSG_VERBOSE( " >>> " << __FUNCTION__ << ": track index = " << trk->index() );
632 }
633
634 ATH_MSG_VERBOSE( " >>> " << __FUNCTION__ << ": m_fitSvc is reset." );
635
636 ATH_MSG_VERBOSE( " >>> " << __FUNCTION__ << ": approx vertex is set. Now going to perform fitting..." );
637
638 StatusCode SC=m_fitSvc->VKalVrtFit(ListBaseTracks,dummyNeutrals,
639 workVertex.vertex,
640 workVertex.vertexMom,
641 workVertex.Charge,
642 workVertex.vertexCov,
643 workVertex.Chi2PerTrk,
644 workVertex.TrkAtVrt,
645 workVertex.Chi2,
646 istate);
647
648 auto& cov = workVertex.vertexCov;
649
650 if( SC.isFailure() ) ATH_MSG_VERBOSE(" >>> " << __FUNCTION__ << ": SC in refitVertex returned failure ");
651 ATH_MSG_VERBOSE(" >>> " << __FUNCTION__ << ": "<<SC<<", "<<ListBaseTracks.size()<<","<<workVertex.Chi2PerTrk.size());
652
653 if( SC.isSuccess() ) {
654 ATH_MSG_VERBOSE( " >>> " << __FUNCTION__ << ": succeeded in fitting. New vertex pos = (" << vertexPos.x() << ", " << vertexPos.y() << ", " << vertexPos.z() << ")" );
655 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) << ")" );
656 }
657
658 return SC;
659 }
660
661
662 //____________________________________________________________________________________________________
663 size_t VrtSecInclusive::nTrkCommon( std::vector<WrkVrt> *workVerticesContainer, const std::pair<unsigned, unsigned>& pairIndex)
664 {
665 //
666 // Number of common tracks for 2 vertices
667 //
668
669 auto& trackIndices1 = workVerticesContainer->at( pairIndex.first ).selectedTrackIndices;
670 auto& trackIndices2 = workVerticesContainer->at( pairIndex.second ).selectedTrackIndices;
671
672 if( trackIndices1.size() < 2 ) return 0;
673 if( trackIndices2.size() < 2 ) return 0;
674
675 size_t nTrkCom = 0;
676
677 for( auto& index : trackIndices1 ) {
678 if( std::find(trackIndices2.begin(),trackIndices2.end(), index) != trackIndices2.end()) nTrkCom++;
679 }
680
681 return nTrkCom;
682 }
683
684
685
686//____________________________________________________________________________________________________
688
689 //--------------------------------------------------------
690 // Primary vertex extraction from TES
691 //
692
693 ATH_CHECK( evtStore()->retrieve( m_primaryVertices, "PrimaryVertices") );
694
695 if( m_FillNtuple ) m_ntupleVars->get<unsigned int>( "NumPV" ) = 0;
696 m_thePV = nullptr;
697
698 ATH_MSG_DEBUG( "processPrimaryVertices(): pv_size = " << m_primaryVertices->size() );
699
700 // Loop over PV container and get number of tracks of each PV
701
702 for( const auto *vertex : *m_primaryVertices ) {
703
704 // Hide (2015-04-21): xAOD::Vertex may contain several types of vertices
705 // e.g. if VertexType==NoVtx, this is a dummy vertex.
706 // We only need to extract primary vertices here, and skip otherwise.
707
708 if( xAOD::VxType::PriVtx != vertex->vertexType() ) continue;
709
710 // Not considering pile-up; pick-up the first PV
711 m_thePV = vertex;
712
713 if( m_FillNtuple ) {
714
715 if( 0 == m_ntupleVars->get<unsigned int>( "NumPV" ) ) {
716
717 m_ntupleVars->get<double>( "PVX" ) = vertex->x();
718 m_ntupleVars->get<double>( "PVY" ) = vertex->y();
719 m_ntupleVars->get<double>( "PVZ" ) = vertex->z();
720 m_ntupleVars->get<unsigned int>( "PVType" ) = vertex->vertexType();
721
722 // number of tracks associated to the PV
723 m_ntupleVars->get<unsigned int>( "NTrksPV" ) = vertex->nTrackParticles();
724 }
725
726 m_ntupleVars->get<unsigned int>( "NumPV" )++;
727
728 m_ntupleVars->get< vector<int> > ( "NdofTrksPV" ) .emplace_back( vertex->numberDoF() );
729 m_ntupleVars->get< vector<double> >( "PVZpile" ) .emplace_back( vertex->position().z() );
730 }
731
732 ATH_MSG_DEBUG("PrimVertex x/y/z/nDOF "
733 << vertex->x() << ","
734 << vertex->y() << ","
735 << vertex->z() << ","
736 << vertex->numberDoF() );
737
738 }
739
740 // Use the dummy PV if no PV is composed
741 if( !m_thePV ) {
742 ATH_MSG_DEBUG("No Reconstructed PV was found. Using the dummy PV instead.");
743 for( const auto *vertex : *m_primaryVertices ) {
744 if( xAOD::VxType::NoVtx != vertex->vertexType() ) continue;
745
746 if( m_FillNtuple ) {
747 // Not considering pile-up; pick-up the first PV
748 if( 0 == m_ntupleVars->get<unsigned int>( "NumPV" ) ) {
749 m_thePV = vertex;
750
751 m_ntupleVars->get<double>( "PVX" ) = vertex->x();
752 m_ntupleVars->get<double>( "PVY" ) = vertex->y();
753 m_ntupleVars->get<double>( "PVZ" ) = vertex->z();
754 m_ntupleVars->get<unsigned int>( "PVType" ) = vertex->vertexType();
755
756 // number of tracks associated to the PV
757 m_ntupleVars->get<unsigned int>( "NTrksPV" ) = vertex->nTrackParticles();
758 }
759 }
760 }
761 }
762
763 // if thePV is null, the PV is not found.
764 if( !m_thePV ) {
765 ATH_MSG_DEBUG("No PV is found in the PV collection!");
766 return StatusCode::FAILURE;
767 }
768
769 ATH_MSG_DEBUG(" Primary vertex successful. thePV = " << m_thePV );
770
771 return StatusCode::SUCCESS;
772 }
773
774
775 //____________________________________________________________________________________________________
776 void VrtSecInclusive::trackClassification(std::vector<WrkVrt> *workVerticesContainer, std::map<long int, std::vector<long int> >& trackToVertexMap )
777 {
778 // Fill TrkInVrt with vertex IDs of each track
779
780 trackToVertexMap.clear();
781
782 for( size_t iv = 0; iv<workVerticesContainer->size(); iv++ ) {
783
784 WrkVrt& vertex = workVerticesContainer->at(iv);
785
786 auto& trackIndices = vertex.selectedTrackIndices;
787 if( !vertex.isGood ) continue;
788 if( trackIndices.size() < 2 ) continue;
789
790 for( auto& index : trackIndices ) {
791 trackToVertexMap[index].emplace_back( iv );
792 }
793 }
794
795 for( auto& pair: trackToVertexMap ) {
796 std::string msg = Form("track index [%ld]: vertices = (", pair.first);
797 for( auto& v : pair.second ) {
798 msg += Form("%ld, ", v);
799 }
800 msg += ")";
801 if( pair.second.size() >=2 ) ATH_MSG_VERBOSE(" >> " << __FUNCTION__ << ": " << msg );
802 }
803
804 }
805
806
807 //____________________________________________________________________________________________________
808 double VrtSecInclusive::findWorstChi2ofMaximallySharedTrack(std::vector<WrkVrt> *workVerticesContainer,
809 std::map<long int, std::vector<long int> >& trackToVertexMap,
810 long int & maxSharedTrack,
811 long int & worstMatchingVertex)
812 {
813
814 double worstChi2 = AlgConsts::invalidFloat;
815
816 // Find the track index that has the largest shared vertices
817 auto maxSharedTrackToVertices = std::max_element( trackToVertexMap.begin(), trackToVertexMap.end(), []( auto& p1, auto& p2 ) { return p1.second.size() < p2.second.size(); } );
818
819 if( maxSharedTrackToVertices == trackToVertexMap.end() ) return worstChi2;
820
821 ATH_MSG_VERBOSE( " > " << __FUNCTION__ << ": max-shared track index = " << maxSharedTrackToVertices->first << ", number of shared vertices = " << maxSharedTrackToVertices->second.size() );
822
823 if( maxSharedTrackToVertices->second.size() < 2 ) return worstChi2;
824
825 // map of vertex index and the chi2 of the track for the maxSharedTrack
826 std::map<long int, double> vrtChi2Map;
827
828 // loop over vertices for the largest shared track
829 for( auto& iv : maxSharedTrackToVertices->second ) {
830 ATH_MSG_VERBOSE( " > " << __FUNCTION__ << ": loop over vertices: vertex index " << iv );
831
832 auto& wrkvrt = workVerticesContainer->at( iv );
833 auto& trackIndices = wrkvrt.selectedTrackIndices;
834
835 // find the index of the track
836 auto index = std::find_if( trackIndices.begin(), trackIndices.end(), [&]( auto& index ) { return index == maxSharedTrackToVertices->first; } );
837 if( index == trackIndices.end() ) {
838 ATH_MSG_WARNING(" >> " << __FUNCTION__ << ": index not found (algorithm inconsistent)" );
839 return worstChi2;
840 }
841
842 auto& chi2 = wrkvrt.Chi2PerTrk.at( index - trackIndices.begin() );
843
844 vrtChi2Map.emplace( std::pair<long int, double>(iv, chi2) );
845 }
846
847 auto worstVrtChi2Pair = std::max_element( vrtChi2Map.begin(), vrtChi2Map.end(), []( auto& p1, auto& p2 ) { return p1.second < p2.second; } );
848
849 if( worstVrtChi2Pair == vrtChi2Map.end() ) {
850 ATH_MSG_WARNING(" >> " << __FUNCTION__ << ": max_element of vrtChi2Map not found" );
851 return worstChi2;
852 }
853
854 maxSharedTrack = maxSharedTrackToVertices->first;
855 worstMatchingVertex = worstVrtChi2Pair->first;
856 worstChi2 = worstVrtChi2Pair->second;
857
858 return worstChi2;
859 }
860
861
862 //____________________________________________________________________________________________________
863 void VrtSecInclusive::printWrkSet(const std::vector<WrkVrt> *workVerticesContainer, const std::string& name)
864 {
865 ATH_MSG_DEBUG( " >> " << __FUNCTION__ << ": ===============================================================" );
866 ATH_MSG_DEBUG( " >> " << __FUNCTION__ << ": " << name << ": #vertices = " << workVerticesContainer->size() );
867
868 std::set<const xAOD::TrackParticle*> usedTracks;
869
870 auto concatenateIndicesToString = []( auto indices, auto& collection ) -> std::string {
871 if( 0 == indices.size() ) return "";
872 return std::accumulate( std::next(indices.begin()), indices.end(), std::to_string( indices.at(0) ),
873 [&collection]( const std::string& str, auto& index ) { return str + ", " + std::to_string( collection.at(index)->index() ); } );
874 };
875
876 std::map<const xAOD::TruthVertex*, bool> previous;
877
878 for( auto& pair : m_matchMap ) { previous.emplace( pair.first, pair.second ); }
879
880 m_matchMap.clear();
881 for( const auto* truthVertex : m_tracingTruthVertices ) { m_matchMap.emplace( truthVertex, false ); }
882
883 for(size_t iv=0; iv<workVerticesContainer->size(); iv++) {
884 const auto& wrkvrt = workVerticesContainer->at(iv);
885
886 if( wrkvrt.nTracksTotal() < 2 ) continue;
887
888 std::string sels = concatenateIndicesToString( wrkvrt.selectedTrackIndices, m_selectedTracks );
889 std::string assocs = concatenateIndicesToString( wrkvrt.associatedTrackIndices, m_associatedTracks );
890
891 for( const auto& index : wrkvrt.selectedTrackIndices ) { usedTracks.insert( m_selectedTracks.at(index) ); }
892 for( const auto& index : wrkvrt.associatedTrackIndices ) { usedTracks.insert( m_associatedTracks.at(index) ); }
893
894 ATH_MSG_DEBUG( " >> " << __FUNCTION__ << ": " << name << " vertex [" << iv << "]: " << &wrkvrt
895 << ", isGood = " << (wrkvrt.isGood? "true" : "false")
896 << ", #ntrks(tot, sel, assoc) = (" << wrkvrt.nTracksTotal() << ", " << wrkvrt.selectedTrackIndices.size() << ", " << wrkvrt.associatedTrackIndices.size() << "), "
897 << ", chi2/ndof = " << wrkvrt.fitQuality()
898 << ", (r, z) = (" << wrkvrt.vertex.perp()
899 << ", " << wrkvrt.vertex.z() << ")"
900 << ", sels = { " << sels << " }"
901 << ", assocs = { " << assocs << " }" );
902
903 // Truth match condition
904 for( const auto* truthVertex : m_tracingTruthVertices ) {
905
906
907 Amg::Vector3D vTruth( truthVertex->x(), truthVertex->y(), truthVertex->z() );
908 Amg::Vector3D vReco ( wrkvrt.vertex.x(), wrkvrt.vertex.y(), wrkvrt.vertex.z() );
909
910 const auto distance = vReco - vTruth;
911
912 AmgSymMatrix(3) cov;
913 cov.fillSymmetric( 0, 0, wrkvrt.vertexCov.at(0) );
914 cov.fillSymmetric( 1, 0, wrkvrt.vertexCov.at(1) );
915 cov.fillSymmetric( 1, 1, wrkvrt.vertexCov.at(2) );
916 cov.fillSymmetric( 2, 0, wrkvrt.vertexCov.at(3) );
917 cov.fillSymmetric( 2, 1, wrkvrt.vertexCov.at(4) );
918 cov.fillSymmetric( 2, 2, wrkvrt.vertexCov.at(5) );
919
920 const double s2 = distance.transpose() * cov.inverse() * distance;
921
922 if( distance.norm() < 2.0 || s2 < 100. ) m_matchMap.at( truthVertex ) = true;
923
924 }
925
926 }
927
928 ATH_MSG_DEBUG( " >> " << __FUNCTION__ << ": number of used tracks = " << usedTracks.size() );
929
930 if( !previous.empty() && previous.size() == m_matchMap.size() ) {
931 for( auto& pair : m_matchMap ) {
932 if( previous.find( pair.first ) == previous.end() ) continue;
933 if( pair.second != previous.at( pair.first ) ) {
934 ATH_MSG_DEBUG( " >> " << __FUNCTION__ << ": Match flag has changed: (r, z) = (" << pair.first->perp() << ", " << pair.first->z() << ")" );
935 }
936 }
937 }
938
939 if( m_FillHist ) {
940 for( auto& pair : m_matchMap ) {
941 if( pair.second ) m_hists["nMatchedTruths"]->Fill( m_vertexingAlgorithmStep+2, pair.first->perp() );
942 }
943 }
944
945 std::string msg;
946 for( const auto* trk : usedTracks ) { msg += Form("%ld, ", trk->index() ); }
947
948 ATH_MSG_DEBUG( " >> " << __FUNCTION__ << ": used tracks = " << msg );
949 ATH_MSG_DEBUG( " >> " << __FUNCTION__ << ": ===============================================================" );
950
951 }
952
953
954 //____________________________________________________________________________________________________
956 summary.numIBLHits = 0;
957 summary.numBLayerHits = 0;
958 summary.numPixelHits = 0;
959 summary.numSctHits = 0;
960 summary.numTrtHits = 0;
961
962 trk->summaryValue( summary.numIBLHits, xAOD::numberOfInnermostPixelLayerHits );
963 trk->summaryValue( summary.numBLayerHits, xAOD::numberOfNextToInnermostPixelLayerHits );
964 trk->summaryValue( summary.numPixelHits, xAOD::numberOfPixelHits );
965 trk->summaryValue( summary.numSctHits, xAOD::numberOfSCTHits );
966 trk->summaryValue( summary.numTrtHits, xAOD::numberOfTRTHits );
967 }
968
969
970
971 //____________________________________________________________________________________________________
973
974 auto* pattern = new ExtrapolatedPattern;
975 const EventContext& ctx = Gaudi::Hive::currentContext();
976 std::vector<std::unique_ptr<Trk::TrackParameters>> paramsVector =
977 m_extrapolator->extrapolateBlindly(ctx, trk->perigeeParameters(), direction);
978
980
981 auto nDisabled = 0;
982
983 for( auto& params : paramsVector ) {
984
985 const TVector3 position( params->position().x(), params->position().y(), params->position().z() );
986
987 if( prevPos == position ) {
988 continue;
989 }
990
991 prevPos = position;
992
993 const auto* detElement = params->associatedSurface().associatedDetectorElement();
994
995 if( detElement ) {
996
997 enum { Pixel = 1, SCT = 2 };
998
999 const auto& id = detElement->identify();
1000 Flag good = false;
1001
1002 if( m_atlasId->is_pixel(id) ) {
1003
1004 auto idHash = m_pixelId->wafer_hash( id );
1005 good = m_pixelCondSummaryTool->isGood( idHash, ctx );
1006
1007 pattern->emplace_back( std::make_tuple( position, Pixel, m_pixelId->barrel_ec(id), m_pixelId->layer_disk(id), good ) );
1008
1009 } else if( m_atlasId->is_sct(id) ) {
1010
1011 auto idHash = m_sctId->wafer_hash( id );
1012 good = m_sctCondSummaryTool->isGood( idHash, ctx );
1013
1014 pattern->emplace_back( std::make_tuple( position, SCT, m_sctId->barrel_ec(id), m_sctId->layer_disk(id), good ) );
1015
1016 }
1017
1018 if( !pattern->empty() ) {
1019
1020 ATH_MSG_VERBOSE(" >> " << __FUNCTION__ << ", track " << trk << ": position = (" << position.Perp() << ", " << position.z() << ", " << position.Phi() << "), detElement ID = " << id << ", good = " << good
1021 << ": (det, bec, layer) = (" << std::get<1>( pattern->back() ) << ", " << std::get<2>( pattern->back() ) << ", " << std::get<3>( pattern->back() ) << ")" );
1022
1023 if( !good ) nDisabled++;
1024 }
1025
1026 }
1027
1028 }
1029
1030 if( m_FillHist ) {
1031 m_hists["disabledCount"]->Fill( nDisabled );
1032 }
1033
1034 return pattern;
1035
1036 }
1037
1038
1039 //____________________________________________________________________________________________________
1041 {
1042
1043 if( m_extrapolatedPatternBank.find( trk ) == m_extrapolatedPatternBank.end() ) {
1044
1045 std::unique_ptr<ExtrapolatedPattern> exPattern_along( extrapolatedPattern( trk, Trk::alongMomentum ) );
1046 std::unique_ptr<ExtrapolatedPattern> exPattern_oppos( extrapolatedPattern( trk, Trk::oppositeMomentum ) );
1047
1048 m_extrapolatedPatternBank.emplace( trk, std::make_pair( std::move(exPattern_along), std::move(exPattern_oppos) ) );
1049
1050 }
1051
1052 auto& exPattern = m_extrapolatedPatternBank.at( trk );
1053
1054 using LayerCombination = std::vector<int>;
1055
1056 std::map<LayerCombination, unsigned> layerMap;
1057 if( layerMap.empty() ) {
1058 layerMap[ { 1, 0, 0 } ] = Trk::pixelBarrel0;
1059 layerMap[ { 1, 0, 1 } ] = Trk::pixelBarrel1;
1060 layerMap[ { 1, 0, 2 } ] = Trk::pixelBarrel2;
1061 layerMap[ { 1, 0, 3 } ] = Trk::pixelBarrel3;
1062
1063 layerMap[ { 1, 2, 0 } ] = Trk::pixelEndCap0;
1064 layerMap[ { 1, 2, 1 } ] = Trk::pixelEndCap1;
1065 layerMap[ { 1, 2, 2 } ] = Trk::pixelEndCap2;
1066 layerMap[ { 1,-2, 0 } ] = Trk::pixelEndCap0;
1067 layerMap[ { 1,-2, 1 } ] = Trk::pixelEndCap1;
1068 layerMap[ { 1,-2, 2 } ] = Trk::pixelEndCap2;
1069
1070 layerMap[ { 2, 0, 0 } ] = Trk::sctBarrel0;
1071 layerMap[ { 2, 0, 1 } ] = Trk::sctBarrel1;
1072 layerMap[ { 2, 0, 2 } ] = Trk::sctBarrel2;
1073 layerMap[ { 2, 0, 3 } ] = Trk::sctBarrel3;
1074
1075 layerMap[ { 2, 2, 0 } ] = Trk::sctEndCap0;
1076 layerMap[ { 2, 2, 1 } ] = Trk::sctEndCap1;
1077 layerMap[ { 2, 2, 2 } ] = Trk::sctEndCap2;
1078 layerMap[ { 2, 2, 3 } ] = Trk::sctEndCap3;
1079 layerMap[ { 2, 2, 4 } ] = Trk::sctEndCap4;
1080 layerMap[ { 2, 2, 5 } ] = Trk::sctEndCap5;
1081 layerMap[ { 2, 2, 6 } ] = Trk::sctEndCap6;
1082 layerMap[ { 2, 2, 7 } ] = Trk::sctEndCap7;
1083 layerMap[ { 2, 2, 8 } ] = Trk::sctEndCap8;
1084 layerMap[ { 2,-2, 0 } ] = Trk::sctEndCap0;
1085 layerMap[ { 2,-2, 1 } ] = Trk::sctEndCap1;
1086 layerMap[ { 2,-2, 2 } ] = Trk::sctEndCap2;
1087 layerMap[ { 2,-2, 3 } ] = Trk::sctEndCap3;
1088 layerMap[ { 2,-2, 4 } ] = Trk::sctEndCap4;
1089 layerMap[ { 2,-2, 5 } ] = Trk::sctEndCap5;
1090 layerMap[ { 2,-2, 6 } ] = Trk::sctEndCap6;
1091 layerMap[ { 2,-2, 7 } ] = Trk::sctEndCap7;
1092 layerMap[ { 2,-2, 8 } ] = Trk::sctEndCap8;
1093 }
1094
1095 enum { position=0, detector=1, bec=2, layer=3, isGood=4 };
1096
1097 // Lambda!
1098 auto getDetectorType = [&]( const ExtrapolatedPoint& point ) -> unsigned {
1099
1100 const LayerCombination comb { std::get<detector>( point ), std::get<bec>( point ), std::get<layer>( point ) };
1101
1102 for( auto& pair : layerMap ) {
1103 if( pair.first == comb ) {
1104 return pair.second;
1105 }
1106 }
1107
1109 };
1110
1111 enum { kShouldNotHaveHit, kShouldHaveHit, kMayHaveHit };
1112 std::vector<unsigned> expectedHitPattern(Trk::numberOfDetectorTypes, kShouldNotHaveHit);
1113
1114 auto minExpectedRadius = AlgConsts::maxValue;
1115
1116 // Loop over extrapolated points (along direction)
1117 auto& exPattern_along = *( exPattern.first );
1118
1119 for( auto itr = exPattern_along.begin(); itr != exPattern_along.end(); ++itr ) {
1120 if( std::next( itr ) == exPattern_along.end() ) continue;
1121
1122 const auto& point = *itr;
1123 const auto& nextPoint = *( std::next( itr ) );
1124
1125 ATH_MSG_VERBOSE( " > " << __FUNCTION__ << ": isGood = " << std::get<isGood>( point ) );
1126
1127 const auto& thisPos = std::get<position>( point );
1128 const auto& nextPos = std::get<position>( nextPoint );
1129
1130 auto sectionVector = nextPos - thisPos;
1131 auto vertexVector = TVector3( vertex.x(), vertex.y(), vertex.z() ) - thisPos;
1132
1133
1134 const auto& detectorType = getDetectorType( point );
1135
1136 ATH_MSG_VERBOSE( " > " << __FUNCTION__ << ": detType = " << detectorType );
1137
1138 if( detectorType == AlgConsts::invalidUnsigned ) continue;
1139 if( detectorType >= Trk::numberOfDetectorTypes ) continue;
1140
1141 // if the vertex is nearby (within 10 mm), the hit may be presnet ("X")
1142 if( vertexVector.Mag() < 10. ) {
1143 expectedHitPattern.at( detectorType ) = kMayHaveHit;
1144 continue;
1145 }
1146
1147 // if the front-end module is not active, then the hit is not expected,
1148 // which means the hit may be present
1149 if( !static_cast<bool>(std::get<isGood>( point )) ) {
1150 expectedHitPattern.at( detectorType ) = kMayHaveHit;
1151 continue;
1152 }
1153
1154 // if the inner product of the above two vectors is positive,
1155 // then point is inner than the vertex.
1156 // Else, the point is outer than the vertex and expect to have hits
1157 // when the track is originated from the vertex.
1158
1159 if( sectionVector.Mag() == 0. ) continue;
1160
1161 ATH_MSG_VERBOSE( " > " << __FUNCTION__
1162 << ": hitPos = (" << thisPos.Perp() << ", " << thisPos.z() << ", " << thisPos.Phi() << ")"
1163 << ", sectionVec = (" << sectionVector.Perp() << ", " << sectionVector.z() << ", " << sectionVector.Phi() << ")"
1164 << ", vertexVec = (" << vertexVector.Perp() << ", " << vertexVector.z() << ", " << vertexVector.Phi() << ")"
1165 << ", cos(s,v) = " << sectionVector * vertexVector / ( sectionVector.Mag() * vertexVector.Mag() + AlgConsts::infinitesimal ) );
1166
1167 if( sectionVector * vertexVector > 0. ) continue;
1168
1169 if( minExpectedRadius > thisPos.Perp() ) minExpectedRadius = thisPos.Perp();
1170
1171 // now, the hit is expected to present.
1172
1173 expectedHitPattern.at( detectorType ) = kShouldHaveHit;
1174 }
1175
1176 // Loop over extrapolated points (opposite direction)
1177 auto& exPattern_oppos = *( exPattern.second );
1178 bool oppositeFlag = false;
1179
1180 for( auto itr = exPattern_oppos.begin(); itr != exPattern_oppos.end(); ++itr ) {
1181 if( std::next( itr ) == exPattern_oppos.end() ) continue;
1182
1183 const auto& point = *itr;
1184 const auto& nextPoint = *( std::next( itr ) );
1185
1186 const auto& thisPos = std::get<position>( point );
1187 const auto& nextPos = std::get<position>( nextPoint );
1188
1189 auto sectionVector = nextPos - thisPos;
1190 auto vertexVector = TVector3( vertex.x(), vertex.y(), vertex.z() ) - thisPos;
1191
1192 const auto& detectorType = getDetectorType( point );
1193
1194 ATH_MSG_VERBOSE( " > " << __FUNCTION__ << ": detType = " << detectorType );
1195
1196 ATH_MSG_DEBUG( " > " << __FUNCTION__
1197 << ": hitPos = (" << thisPos.Perp() << ", " << thisPos.z() << ", " << thisPos.Phi() << ")"
1198 << ", vertex = (" << vertex.perp() << ", " << vertex.z() << ", " << vertex.phi() << ")"
1199 << ", cos(s,v) = " << sectionVector * vertexVector / ( sectionVector.Mag() * vertexVector.Mag() + AlgConsts::infinitesimal ) );
1200
1201 if( detectorType == AlgConsts::invalidUnsigned ) continue;
1202 if( detectorType >= Trk::numberOfDetectorTypes ) continue;
1203
1204 if( sectionVector * vertexVector < 0. ) {
1205 oppositeFlag = true;
1206 }
1207 }
1208
1209 // If the first expected point's radius is smaller than the vertex radius,
1210 // it's the case that the vertex was reconstructed in the opposite phi-direction
1211 // to the track outgoing direction. Such a case should be rejected.
1212 // bool oppositeFlag = ( minExpectedRadius < vertex.perp() );
1213
1214 std::string msg = "Expected hit pattern: ";
1215 for( unsigned i=0; i<Trk::numberOfDetectorTypes; i++) {
1216 msg += Form("%s", expectedHitPattern.at(i) < kMayHaveHit? Form("%u", expectedHitPattern.at(i)) : "X" );
1217 }
1218 ATH_MSG_DEBUG( " > " << __FUNCTION__ << ": " << msg );
1219
1220 msg = "Recorded hit pattern: ";
1221 for( unsigned i=0; i<Trk::numberOfDetectorTypes; i++) {
1222 msg += Form("%u", ( trk->hitPattern() >> i ) & 1 );
1223 }
1224 ATH_MSG_DEBUG( " > " << __FUNCTION__ << ": " << msg );
1225
1226 std::vector<unsigned> matchedLayers;
1227
1228 for( unsigned i=0; i<Trk::numberOfDetectorTypes; i++) {
1229 const unsigned recordedPattern = ( (trk->hitPattern()>>i) & 1 );
1230
1231 if( expectedHitPattern.at(i) == kMayHaveHit ) {
1232 matchedLayers.emplace_back( i );
1233 } else if( expectedHitPattern.at(i) == kShouldHaveHit ) {
1234 if( expectedHitPattern.at(i) != recordedPattern ) {
1235 break;
1236 } else {
1237 matchedLayers.emplace_back( i );
1238 }
1239 } else {
1240 if( expectedHitPattern.at(i) != recordedPattern ) {
1241 break;
1242 }
1243 }
1244
1245 }
1246
1247 uint8_t PixelHits = 0;
1248 uint8_t SctHits = 0;
1249 uint8_t TRTHits = 0;
1250 if( !(trk->summaryValue( PixelHits, xAOD::numberOfPixelHits ) ) ) PixelHits =0;
1251 if( !(trk->summaryValue( SctHits, xAOD::numberOfSCTHits ) ) ) SctHits =0;
1252 if( !(trk->summaryValue( TRTHits, xAOD::numberOfTRTHits ) ) ) TRTHits =0;
1253
1254 auto dphi = trk->phi() - vertex.phi();
1255 while( dphi > TMath::Pi() ) dphi -= TMath::TwoPi();
1256 while( dphi < -TMath::Pi() ) dphi += TMath::TwoPi();
1257
1258 ATH_MSG_DEBUG( " > " << __FUNCTION__ << ": vtx phi = " << vertex.phi() << ", track phi = " << trk->phi() << ", dphi = " << dphi
1259 << ", oppositeFlag = " << oppositeFlag
1260 << ", nPixelHits = " << static_cast<int>(PixelHits)
1261 << ", nSCTHits = " << static_cast<int>(SctHits)
1262 << ", nTRTHits = " << static_cast<int>(TRTHits)
1263 << ", nMatchedLayers = " << matchedLayers.size() );
1264
1265 if( PixelHits == 0 && vertex.perp() > 300. ) {
1266 ATH_MSG_DEBUG( " > " << __FUNCTION__ << ": vertex r > 300 mm, w/o no pixel hits" );
1267 }
1268
1269
1270 // Requires the first 2 layers with the hit matches.
1271 if( matchedLayers.size() < 2 ) return false;
1272
1273 // In case of the first matched layer is not within pixel barrel, requires the first 4 layers with the hit match
1274 if( matchedLayers.at(0) >= Trk::pixelEndCap0 ) {
1275 if( matchedLayers.size() < 4 ) return false;
1276 }
1277
1278 // Sometimes the vertex is reconstructed at the opposite phi direction.
1279 // In this case, the pattern match may pass.
1280 // This can be avoided by requiring that the
1281 if( oppositeFlag ) return false;
1282
1283 // The following condition should apply for vertices outer than IBL.
1284 if( false /*matchedLayers.at(0) > Trk::pixelBarrel0*/ ) {
1285
1286 // If the dphi (defined above) is opposite, reject.
1287 if( fabs( dphi ) > TMath::Pi()/2.0 ) return false;
1288
1289 // If the track is not within the forward hemisphere to the vertex, reject.
1290 TVector3 trkP; trkP.SetPtEtaPhi( trk->pt(), trk->eta(), trk->phi() );
1291 TVector3 vtx; vtx.SetXYZ( vertex.x(), vertex.y(), vertex.z() );
1292 if( trkP.Dot( vtx ) < 0. ) return false;
1293
1294 }
1295
1296 return true;
1297 }
1298
1299
1300 //____________________________________________________________________________________________________
1301 bool VrtSecInclusive::patternCheckRun2( const uint32_t& pattern, const Amg::Vector3D& vertex ) {
1302
1303 //
1304 // rough guesses for active layers:
1305 // BeamPipe: 23.5-24.3
1306 // IBL: 31.0-38.4
1307 // Pix0 (BLayer): 47.7-54.4, Pix1: 85.5-92.2, Pix2: 119.3-126.1
1308 // Sct0: 290-315, Sct1: 360-390, Sct2: 430-460, Sct3:500-530
1309 //
1310
1311 const double rad = vertex.perp();
1312 const double absz = fabs( vertex.z() );
1313
1314 // vertex area classification
1315 enum vertexArea {
1316 insideBeamPipe,
1317
1318 insidePixelBarrel0,
1319 aroundPixelBarrel0,
1320
1321 outsidePixelBarrel0_and_insidePixelBarrel1,
1322 aroundPixelBarrel1,
1323
1324 outsidePixelBarrel1_and_insidePixelBarrel2,
1325 aroundPixelBarrel2,
1326
1327 outsidePixelBarrel2_and_insidePixelBarrel3,
1328 aroundPixelBarrel3,
1329
1330 outsidePixelBarrel3_and_insideSctBarrel0,
1331 aroundSctBarrel0,
1332
1333 outsideSctBarrel0_and_insideSctBarrel1,
1334 aroundSctBarrel1,
1335 };
1336
1337 // Mutually exclusive vertex position pattern
1338 int vertex_pattern = 0;
1339 if( rad < 23.50 ) {
1340 vertex_pattern = insideBeamPipe;
1341
1342 } else if( rad < 31.0 && absz < 331.5 ) {
1343 vertex_pattern = insidePixelBarrel0;
1344
1345 } else if( rad < 38.4 && absz < 331.5 ) {
1346 vertex_pattern = aroundPixelBarrel0;
1347
1348 } else if( rad < 47.7 && absz < 400.5 ) {
1349 vertex_pattern = outsidePixelBarrel0_and_insidePixelBarrel1;
1350
1351 } else if( rad < 54.4 && absz < 400.5 ) {
1352 vertex_pattern = aroundPixelBarrel1;
1353
1354 } else if( rad < 85.5 && absz < 400.5 ) {
1355 vertex_pattern = outsidePixelBarrel1_and_insidePixelBarrel2;
1356
1357 } else if( rad < 92.2 && absz < 400.5 ) {
1358 vertex_pattern = aroundPixelBarrel2;
1359
1360 } else if( rad < 119.3 && absz < 400.5 ) {
1361 vertex_pattern = outsidePixelBarrel2_and_insidePixelBarrel3;
1362
1363 } else if( rad < 126.1 && absz < 400.5 ) {
1364 vertex_pattern = aroundPixelBarrel3;
1365
1366 } else if( rad < 290 && absz < 749.0 ) {
1367 vertex_pattern = outsidePixelBarrel3_and_insideSctBarrel0;
1368
1369 } else if( rad < 315 && absz < 749.0 ) {
1370 vertex_pattern = aroundSctBarrel0;
1371
1372 } else if( rad < 360 && absz < 749.0 ) {
1373 vertex_pattern = outsideSctBarrel0_and_insideSctBarrel1;
1374
1375 } else if( rad < 390 && absz < 749.0 ) {
1376 vertex_pattern = aroundSctBarrel1;
1377
1378 } else {
1379 }
1380
1381 unsigned nPixelLayers { 0 };
1382 {
1383 if ( pattern & (1 << Trk::pixelBarrel0) ) nPixelLayers++;
1384 if ( pattern & (1 << Trk::pixelBarrel1) ) nPixelLayers++;
1385 if ( pattern & (1 << Trk::pixelBarrel2) ) nPixelLayers++;
1386 if ( pattern & (1 << Trk::pixelBarrel3) ) nPixelLayers++;
1387 if ( pattern & (1 << Trk::pixelEndCap0) ) nPixelLayers++;
1388 if ( pattern & (1 << Trk::pixelEndCap1) ) nPixelLayers++;
1389 if ( pattern & (1 << Trk::pixelEndCap2) ) nPixelLayers++;
1390 }
1391
1393 if( vertex_pattern == insideBeamPipe ) {
1394
1395 if( ! (pattern & (1<<Trk::pixelBarrel0)) ) return false;
1396 if( nPixelLayers < 3 ) return false;
1397
1398
1399 } else if( vertex_pattern == insidePixelBarrel0 ) {
1400
1401 if( ! (pattern & (1<<Trk::pixelBarrel0)) ) return false;
1402 if( nPixelLayers < 3 ) return false;
1403 }
1404
1405
1406 else if( vertex_pattern == aroundPixelBarrel0 ) {
1407
1408 // require nothing for PixelBarrel0
1409 if( ! (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1410 if( nPixelLayers < 2 ) return false;
1411 }
1412
1413
1414 else if( vertex_pattern == outsidePixelBarrel0_and_insidePixelBarrel1 ) {
1415
1416 if( (pattern & (1<<Trk::pixelBarrel0)) ) return false;
1417 if( ! (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1418 if( nPixelLayers < 2 ) return false;
1419 }
1420
1421
1422 else if( vertex_pattern == aroundPixelBarrel1 ) {
1423
1424 if( (pattern & (1<<Trk::pixelBarrel0)) ) return false;
1425 // require nothing for PixelBarrel
1426 if( ! (pattern & (1<<Trk::pixelBarrel2)) ) return false;
1427 if( nPixelLayers < 2 ) return false;
1428 }
1429
1430
1431 else if( vertex_pattern == outsidePixelBarrel1_and_insidePixelBarrel2 ) {
1432
1433 if( (pattern & (1<<Trk::pixelBarrel0)) ) return false;
1434 if( (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1435 if( ! (pattern & (1<<Trk::pixelBarrel2)) ) return false;
1436 if( nPixelLayers < 2 ) return false;
1437 }
1438
1439
1440 else if( vertex_pattern == aroundPixelBarrel2 ) {
1441
1442 if( (pattern & (1<<Trk::pixelBarrel0)) ) return false;
1443 if( (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1444 // require nothing for PixelBarrel2
1445 if( ! (pattern & (1<<Trk::pixelBarrel3)) ) return false;
1446 }
1447
1448
1449 else if( vertex_pattern == outsidePixelBarrel2_and_insidePixelBarrel3 ) {
1450
1451 if( (pattern & (1<<Trk::pixelBarrel0)) ) return false;
1452 if( (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1453 if( (pattern & (1<<Trk::pixelBarrel2)) ) return false;
1454 if( ! (pattern & (1<<Trk::pixelBarrel3)) ) return false;
1455 }
1456
1457 else if( vertex_pattern == aroundPixelBarrel3 ) {
1458
1459 if( (pattern & (1<<Trk::pixelBarrel0)) ) return false;
1460 if( (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1461 if( (pattern & (1<<Trk::pixelBarrel2)) ) return false;
1462 // require nothing for PixelBarrel3
1463 if( ! (pattern & (1<<Trk::sctBarrel0)) ) return false;
1464 }
1465
1466
1467 else if( vertex_pattern == outsidePixelBarrel3_and_insideSctBarrel0 ) {
1468
1469 if( (pattern & (1<<Trk::pixelBarrel0)) ) return false;
1470 if( (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1471 if( (pattern & (1<<Trk::pixelBarrel2)) ) return false;
1472 if( (pattern & (1<<Trk::pixelBarrel3)) ) return false;
1473 if( ! (pattern & (1<<Trk::sctBarrel0)) ) return false;
1474 }
1475
1476
1477 else if( vertex_pattern == aroundSctBarrel0 ) {
1478
1479 if( (pattern & (1<<Trk::pixelBarrel0)) ) return false;
1480 if( (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1481 if( (pattern & (1<<Trk::pixelBarrel2)) ) return false;
1482 if( (pattern & (1<<Trk::pixelBarrel3)) ) return false;
1483 // require nothing for SctBarrel0
1484 if( ! (pattern & (1<<Trk::sctBarrel1)) ) return false;
1485 }
1486
1487
1488 else if( vertex_pattern == outsideSctBarrel0_and_insideSctBarrel1 ) {
1489
1490 if( (pattern & (1<<Trk::pixelBarrel0)) ) return false;
1491 if( (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1492 if( (pattern & (1<<Trk::pixelBarrel2)) ) return false;
1493 if( (pattern & (1<<Trk::pixelBarrel3)) ) return false;
1494 if( (pattern & (1<<Trk::sctBarrel0)) ) return false;
1495 if( ! (pattern & (1<<Trk::sctBarrel1)) ) return false;
1496 }
1497
1498
1499 else if( vertex_pattern == aroundSctBarrel1 ) {
1500 if( (pattern & (1<<Trk::pixelBarrel0)) ) return false;
1501 if( (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1502 if( (pattern & (1<<Trk::pixelBarrel2)) ) return false;
1503 if( (pattern & (1<<Trk::pixelBarrel3)) ) return false;
1504 if( (pattern & (1<<Trk::sctBarrel0)) ) return false;
1505 // require nothing for SctBarrel1
1506 if( ! (pattern & (1<<Trk::sctBarrel2)) ) return false;
1507 }
1509
1510 return true;
1511
1512 }
1513
1514 //____________________________________________________________________________________________________
1515 bool VrtSecInclusive::patternCheckRun2OuterOnly( const uint32_t& pattern, const Amg::Vector3D& vertex ) {
1516
1517 //
1518 // rough guesses for active layers:
1519 // BeamPipe: 23.5-24.3
1520 // IBL: 31.0-38.4
1521 // Pix0 (BLayer): 47.7-54.4, Pix1: 85.5-92.2, Pix2: 119.3-126.1
1522 // Sct0: 290-315, Sct1: 360-390, Sct2: 430-460, Sct3:500-530
1523 //
1524
1525 const double rad = vertex.perp();
1526 const double absz = fabs( vertex.z() );
1527
1528 // vertex area classification
1529 enum vertexArea {
1530 insideBeamPipe,
1531
1532 insidePixelBarrel0,
1533 aroundPixelBarrel0,
1534
1535 outsidePixelBarrel0_and_insidePixelBarrel1,
1536 aroundPixelBarrel1,
1537
1538 outsidePixelBarrel1_and_insidePixelBarrel2,
1539 aroundPixelBarrel2,
1540
1541 outsidePixelBarrel2_and_insidePixelBarrel3,
1542 aroundPixelBarrel3,
1543
1544 outsidePixelBarrel3_and_insideSctBarrel0,
1545 aroundSctBarrel0,
1546
1547 outsideSctBarrel0_and_insideSctBarrel1,
1548 aroundSctBarrel1,
1549 };
1550
1551 // Mutually exclusive vertex position pattern
1552 int vertex_pattern = 0;
1553 if( rad < 23.50 ) {
1554 vertex_pattern = insideBeamPipe;
1555
1556 } else if( rad < 31.0 && absz < 331.5 ) {
1557 vertex_pattern = insidePixelBarrel0;
1558
1559 } else if( rad < 38.4 && absz < 331.5 ) {
1560 vertex_pattern = aroundPixelBarrel0;
1561
1562 } else if( rad < 47.7 && absz < 400.5 ) {
1563 vertex_pattern = outsidePixelBarrel0_and_insidePixelBarrel1;
1564
1565 } else if( rad < 54.4 && absz < 400.5 ) {
1566 vertex_pattern = aroundPixelBarrel1;
1567
1568 } else if( rad < 85.5 && absz < 400.5 ) {
1569 vertex_pattern = outsidePixelBarrel1_and_insidePixelBarrel2;
1570
1571 } else if( rad < 92.2 && absz < 400.5 ) {
1572 vertex_pattern = aroundPixelBarrel2;
1573
1574 } else if( rad < 119.3 && absz < 400.5 ) {
1575 vertex_pattern = outsidePixelBarrel2_and_insidePixelBarrel3;
1576
1577 } else if( rad < 126.1 && absz < 400.5 ) {
1578 vertex_pattern = aroundPixelBarrel3;
1579
1580 } else if( rad < 290 && absz < 749.0 ) {
1581 vertex_pattern = outsidePixelBarrel3_and_insideSctBarrel0;
1582
1583 } else if( rad < 315 && absz < 749.0 ) {
1584 vertex_pattern = aroundSctBarrel0;
1585
1586 } else if( rad < 360 && absz < 749.0 ) {
1587 vertex_pattern = outsideSctBarrel0_and_insideSctBarrel1;
1588
1589 } else if( rad < 390 && absz < 749.0 ) {
1590 vertex_pattern = aroundSctBarrel1;
1591
1592 } else {
1593 }
1594
1595
1596 unsigned nPixelLayers { 0 };
1597 {
1598 nPixelLayers += ( pattern & (1 << Trk::pixelBarrel0) );
1599 nPixelLayers += ( pattern & (1 << Trk::pixelBarrel1) );
1600 nPixelLayers += ( pattern & (1 << Trk::pixelBarrel2) );
1601 nPixelLayers += ( pattern & (1 << Trk::pixelBarrel3) );
1602 nPixelLayers += ( pattern & (1 << Trk::pixelEndCap0) );
1603 nPixelLayers += ( pattern & (1 << Trk::pixelEndCap1) );
1604 nPixelLayers += ( pattern & (1 << Trk::pixelEndCap2) );
1605 }
1606
1608 if( vertex_pattern == insideBeamPipe ) {
1609
1610 if( ! (pattern & (1<<Trk::pixelBarrel0)) ) return false;
1611 if( ! (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1612 if( nPixelLayers < 3 ) return false;
1613
1614 } else if( vertex_pattern == insidePixelBarrel0 ) {
1615
1616 if( ! (pattern & (1<<Trk::pixelBarrel0)) ) return false;
1617 if( ! (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1618 if( nPixelLayers < 3 ) return false;
1619
1620 }
1621
1622
1623 else if( vertex_pattern == aroundPixelBarrel0 ) {
1624
1625 // require nothing for PixelBarrel0
1626 if( ! (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1627 if( ! (pattern & (1<<Trk::pixelBarrel2)) ) return false;
1628 if( nPixelLayers < 3 ) return false;
1629 }
1630
1631
1632 else if( vertex_pattern == outsidePixelBarrel0_and_insidePixelBarrel1 ) {
1633
1634 if( ! (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1635 if( ! (pattern & (1<<Trk::pixelBarrel2)) ) return false;
1636 if( nPixelLayers < 3 ) return false;
1637 }
1638
1639
1640 else if( vertex_pattern == aroundPixelBarrel1 ) {
1641
1642 // require nothing for PixelBarrel1
1643 if( ! (pattern & (1<<Trk::pixelBarrel2)) ) return false;
1644 if( ! (pattern & (1<<Trk::pixelBarrel3)) ) return false;
1645 if( nPixelLayers < 2 ) return false;
1646 }
1647
1648
1649 else if( vertex_pattern == outsidePixelBarrel1_and_insidePixelBarrel2 ) {
1650
1651 if( ! (pattern & (1<<Trk::pixelBarrel2)) ) return false;
1652 if( ! (pattern & (1<<Trk::pixelBarrel3)) ) return false;
1653 if( nPixelLayers < 2 ) return false;
1654 }
1655
1656
1657 else if( vertex_pattern == aroundPixelBarrel2 ) {
1658
1659 // require nothing for PixelBarrel2
1660 if( ! (pattern & (1<<Trk::pixelBarrel3)) ) return false;
1661 }
1662
1663
1664 else if( vertex_pattern == outsidePixelBarrel2_and_insidePixelBarrel3 ) {
1665
1666 if( ! (pattern & (1<<Trk::pixelBarrel3)) ) return false;
1667 }
1668
1669 else if( vertex_pattern == aroundPixelBarrel3 ) {
1670
1671 // require nothing for PixelBarrel3
1672 if( ! (pattern & (1<<Trk::sctBarrel0)) ) return false;
1673 if( ! (pattern & (1<<Trk::sctBarrel1)) ) return false;
1674 }
1675
1676
1677 else if( vertex_pattern == outsidePixelBarrel3_and_insideSctBarrel0 ) {
1678
1679 if( ! (pattern & (1<<Trk::sctBarrel0)) ) return false;
1680 if( ! (pattern & (1<<Trk::sctBarrel1)) ) return false;
1681 }
1682
1683
1684 else if( vertex_pattern == aroundSctBarrel0 ) {
1685
1686 // require nothing for SctBarrel0
1687 if( ! (pattern & (1<<Trk::sctBarrel1)) ) return false;
1688 if( ! (pattern & (1<<Trk::sctBarrel2)) ) return false;
1689 }
1690
1691
1692 else if( vertex_pattern == outsideSctBarrel0_and_insideSctBarrel1 ) {
1693
1694 if( ! (pattern & (1<<Trk::sctBarrel1)) ) return false;
1695 if( ! (pattern & (1<<Trk::sctBarrel2)) ) return false;
1696 }
1697
1698
1699 else if( vertex_pattern == aroundSctBarrel1 ) {
1700 // require nothing for SctBarrel1
1701 if( ! (pattern & (1<<Trk::sctBarrel2)) ) return false;
1702 if( ! (pattern & (1<<Trk::sctBarrel3)) ) return false;
1703 }
1705
1706 return true;
1707
1708 }
1709
1710 //____________________________________________________________________________________________________
1711 bool VrtSecInclusive::patternCheckRun1( const uint32_t& pattern, const Amg::Vector3D& vertex ) {
1712 //
1713 // rough guesses for active layers:
1714 // BeamPipe: 25.0
1715 // Pix0 (BLayer): 47.7-54.4, Pix1: 85.5-92.2, Pix2: 119.3-126.1
1716 // Sct0: 290-315, Sct1: 360-390, Sct2: 430-460, Sct3:500-530
1717 //
1718
1719 const double rad = vertex.perp();
1720 const double absz = fabs( vertex.z() );
1721
1722 // vertex area classification
1723 enum vertexArea {
1724 insideBeamPipe,
1725
1726 insidePixelBarrel1,
1727 aroundPixelBarrel1,
1728
1729 outsidePixelBarrel1_and_insidePixelBarrel2,
1730 aroundPixelBarrel2,
1731
1732 outsidePixelBarrel2_and_insidePixelBarrel3,
1733 aroundPixelBarrel3,
1734
1735 outsidePixelBarrel3_and_insideSctBarrel0,
1736 aroundSctBarrel0,
1737
1738 outsideSctBarrel0_and_insideSctBarrel1,
1739 aroundSctBarrel1,
1740 };
1741
1742 // Mutually exclusive vertex position pattern
1743 Int_t vertex_pattern = 0;
1744 if( rad < 25.00 ) {
1745 vertex_pattern = insideBeamPipe;
1746
1747 } else if( rad < 47.7 && absz < 400.5 ) {
1748 vertex_pattern = insidePixelBarrel1;
1749
1750 } else if( rad < 54.4 && absz < 400.5 ) {
1751 vertex_pattern = aroundPixelBarrel1;
1752
1753 } else if( rad < 85.5 && absz < 400.5 ) {
1754 vertex_pattern = outsidePixelBarrel1_and_insidePixelBarrel2;
1755
1756 } else if( rad < 92.2 && absz < 400.5 ) {
1757 vertex_pattern = aroundPixelBarrel2;
1758
1759 } else if( rad < 119.3 && absz < 400.5 ) {
1760 vertex_pattern = outsidePixelBarrel2_and_insidePixelBarrel3;
1761
1762 } else if( rad < 126.1 && absz < 400.5 ) {
1763 vertex_pattern = aroundPixelBarrel3;
1764
1765 } else if( rad < 290 && absz < 749.0 ) {
1766 vertex_pattern = outsidePixelBarrel3_and_insideSctBarrel0;
1767
1768 } else if( rad < 315 && absz < 749.0 ) {
1769 vertex_pattern = aroundSctBarrel0;
1770
1771 } else if( rad < 360 && absz < 749.0 ) {
1772 vertex_pattern = outsideSctBarrel0_and_insideSctBarrel1;
1773
1774 } else if( rad < 390 && absz < 749.0 ) {
1775 vertex_pattern = aroundSctBarrel1;
1776
1777 } else {
1778 }
1779
1780
1782 if( vertex_pattern == insideBeamPipe ) {
1783
1784 if( ! (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1785
1786 }
1787
1788
1789 else if( vertex_pattern == insidePixelBarrel1 ) {
1790
1791 if( ! (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1792 }
1793
1794
1795 else if( vertex_pattern == aroundPixelBarrel1 ) {
1796
1797 // require nothing for PixelBarrel1
1798 if( ! (pattern & (1<<Trk::pixelBarrel2)) ) return false;
1799 }
1800
1801
1802 else if( vertex_pattern == outsidePixelBarrel1_and_insidePixelBarrel2 ) {
1803
1804 if( (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1805 if( ! (pattern & (1<<Trk::pixelBarrel2)) ) return false;
1806 }
1807
1808
1809 else if( vertex_pattern == aroundPixelBarrel2 ) {
1810
1811 if( (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1812 // require nothing for PixelBarrel2
1813 if( ! (pattern & (1<<Trk::pixelBarrel3)) ) return false;
1814 }
1815
1816
1817 else if( vertex_pattern == outsidePixelBarrel2_and_insidePixelBarrel3 ) {
1818
1819 if( (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1820 if( (pattern & (1<<Trk::pixelBarrel2)) ) return false;
1821 if( ! (pattern & (1<<Trk::pixelBarrel3)) ) return false;
1822 }
1823
1824 else if( vertex_pattern == aroundPixelBarrel3 ) {
1825
1826 if( (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1827 if( (pattern & (1<<Trk::pixelBarrel2)) ) return false;
1828 // require nothing for PixelBarrel3
1829 if( ! (pattern & (1<<Trk::sctBarrel0)) ) return false;
1830 }
1831
1832
1833 else if( vertex_pattern == outsidePixelBarrel3_and_insideSctBarrel0 ) {
1834
1835 if( (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1836 if( (pattern & (1<<Trk::pixelBarrel2)) ) return false;
1837 if( (pattern & (1<<Trk::pixelBarrel3)) ) return false;
1838 if( ! (pattern & (1<<Trk::sctBarrel0)) ) return false;
1839 }
1840
1841
1842 else if( vertex_pattern == aroundSctBarrel0 ) {
1843
1844 if( (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1845 if( (pattern & (1<<Trk::pixelBarrel2)) ) return false;
1846 if( (pattern & (1<<Trk::pixelBarrel3)) ) return false;
1847 // require nothing for SctBarrel0
1848 if( ! (pattern & (1<<Trk::sctBarrel1)) ) return false;
1849 }
1850
1851
1852 else if( vertex_pattern == outsideSctBarrel0_and_insideSctBarrel1 ) {
1853
1854 if( (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1855 if( (pattern & (1<<Trk::pixelBarrel2)) ) return false;
1856 if( (pattern & (1<<Trk::pixelBarrel3)) ) return false;
1857 if( (pattern & (1<<Trk::sctBarrel0)) ) return false;
1858 if( ! (pattern & (1<<Trk::sctBarrel1)) ) return false;
1859 }
1860
1861
1862 else if( vertex_pattern == aroundSctBarrel1 ) {
1863 if( (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1864 if( (pattern & (1<<Trk::pixelBarrel2)) ) return false;
1865 if( (pattern & (1<<Trk::pixelBarrel3)) ) return false;
1866 if( (pattern & (1<<Trk::sctBarrel0)) ) return false;
1867 // require nothing for SctBarrel1
1868 if( ! (pattern & (1<<Trk::sctBarrel2)) ) return false;
1869 }
1871
1872 return true;
1873 }
1874
1875 //____________________________________________________________________________________________________
1876 bool VrtSecInclusive::patternCheckRun1OuterOnly( const uint32_t& pattern, const Amg::Vector3D& vertex ) {
1877 //
1878 // rough guesses for active layers:
1879 // BeamPipe: 25.0
1880 // Pix0 (BLayer): 47.7-54.4, Pix1: 85.5-92.2, Pix2: 119.3-126.1
1881 // Sct0: 290-315, Sct1: 360-390, Sct2: 430-460, Sct3:500-530
1882 //
1883
1884 const double rad = vertex.perp();
1885 const double absz = fabs( vertex.z() );
1886
1887 // vertex area classification
1888 enum vertexArea {
1889 insideBeamPipe,
1890
1891 insidePixelBarrel1,
1892 aroundPixelBarrel1,
1893
1894 outsidePixelBarrel1_and_insidePixelBarrel2,
1895 aroundPixelBarrel2,
1896
1897 outsidePixelBarrel2_and_insidePixelBarrel3,
1898 aroundPixelBarrel3,
1899
1900 outsidePixelBarrel3_and_insideSctBarrel0,
1901 aroundSctBarrel0,
1902
1903 outsideSctBarrel0_and_insideSctBarrel1,
1904 aroundSctBarrel1,
1905 };
1906
1907 // Mutually exclusive vertex position pattern
1908 Int_t vertex_pattern = 0;
1909 if( rad < 25.00 ) {
1910 vertex_pattern = insideBeamPipe;
1911
1912 } else if( rad < 47.7 && absz < 400.5 ) {
1913 vertex_pattern = insidePixelBarrel1;
1914
1915 } else if( rad < 54.4 && absz < 400.5 ) {
1916 vertex_pattern = aroundPixelBarrel1;
1917
1918 } else if( rad < 85.5 && absz < 400.5 ) {
1919 vertex_pattern = outsidePixelBarrel1_and_insidePixelBarrel2;
1920
1921 } else if( rad < 92.2 && absz < 400.5 ) {
1922 vertex_pattern = aroundPixelBarrel2;
1923
1924 } else if( rad < 119.3 && absz < 400.5 ) {
1925 vertex_pattern = outsidePixelBarrel2_and_insidePixelBarrel3;
1926
1927 } else if( rad < 126.1 && absz < 400.5 ) {
1928 vertex_pattern = aroundPixelBarrel3;
1929
1930 } else if( rad < 290 && absz < 749.0 ) {
1931 vertex_pattern = outsidePixelBarrel3_and_insideSctBarrel0;
1932
1933 } else if( rad < 315 && absz < 749.0 ) {
1934 vertex_pattern = aroundSctBarrel0;
1935
1936 } else if( rad < 360 && absz < 749.0 ) {
1937 vertex_pattern = outsideSctBarrel0_and_insideSctBarrel1;
1938
1939 } else if( rad < 390 && absz < 749.0 ) {
1940 vertex_pattern = aroundSctBarrel1;
1941
1942 } else {
1943 }
1944
1945
1947 if( vertex_pattern == insideBeamPipe ) {
1948
1949 if( ! (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1950
1951 }
1952
1953
1954 else if( vertex_pattern == insidePixelBarrel1 ) {
1955
1956 if( ! (pattern & (1<<Trk::pixelBarrel1)) ) return false;
1957 }
1958
1959
1960 else if( vertex_pattern == aroundPixelBarrel1 ) {
1961
1962 // require nothing for PixelBarrel1
1963 if( ! (pattern & (1<<Trk::pixelBarrel2)) ) return false;
1964 }
1965
1966
1967 else if( vertex_pattern == outsidePixelBarrel1_and_insidePixelBarrel2 ) {
1968
1969 if( ! (pattern & (1<<Trk::pixelBarrel2)) ) return false;
1970 }
1971
1972
1973 else if( vertex_pattern == aroundPixelBarrel2 ) {
1974
1975 // require nothing for PixelBarrel2
1976 if( ! (pattern & (1<<Trk::pixelBarrel3)) ) return false;
1977 }
1978
1979
1980 else if( vertex_pattern == outsidePixelBarrel2_and_insidePixelBarrel3 ) {
1981
1982 if( ! (pattern & (1<<Trk::pixelBarrel3)) ) return false;
1983 }
1984
1985 else if( vertex_pattern == aroundPixelBarrel3 ) {
1986
1987 // require nothing for PixelBarrel3
1988 if( ! (pattern & (1<<Trk::sctBarrel0)) ) return false;
1989 }
1990
1991
1992 else if( vertex_pattern == outsidePixelBarrel3_and_insideSctBarrel0 ) {
1993
1994 if( ! (pattern & (1<<Trk::sctBarrel0)) ) return false;
1995 }
1996
1997
1998 else if( vertex_pattern == aroundSctBarrel0 ) {
1999
2000 // require nothing for SctBarrel0
2001 if( ! (pattern & (1<<Trk::sctBarrel1)) ) return false;
2002 }
2003
2004
2005 else if( vertex_pattern == outsideSctBarrel0_and_insideSctBarrel1 ) {
2006
2007 if( ! (pattern & (1<<Trk::sctBarrel1)) ) return false;
2008 }
2009
2010
2011 else if( vertex_pattern == aroundSctBarrel1 ) {
2012 // require nothing for SctBarrel1
2013 if( ! (pattern & (1<<Trk::sctBarrel2)) ) return false;
2014 }
2016
2017 return true;
2018 }
2019
2020 //____________________________________________________________________________________________________
2021 bool VrtSecInclusive::patternCheck( const uint32_t& pattern, const Amg::Vector3D& vertex ) {
2022 bool flag = false;
2023
2025 flag = patternCheckRun2( pattern, vertex );
2027 flag = patternCheckRun1( pattern, vertex );
2028 }
2029
2030 return flag;
2031 }
2032
2033 //____________________________________________________________________________________________________
2034 bool VrtSecInclusive::patternCheckOuterOnly( const uint32_t& pattern, const Amg::Vector3D& vertex ) {
2035 bool flag = false;
2036
2038 flag = patternCheckRun2OuterOnly( pattern, vertex );
2040 flag = patternCheckRun1OuterOnly( pattern, vertex );
2041 }
2042
2043 return flag;
2044 }
2045
2046 //____________________________________________________________________________________________________
2048 {
2049
2050 const uint32_t pattern = trk->hitPattern();
2051
2052 return patternCheck( pattern, vertex );
2053
2054 }
2055
2056
2057 //____________________________________________________________________________________________________
2059 {
2060
2061 const uint32_t pattern = trk->hitPattern();
2062
2063 return patternCheckOuterOnly( pattern, vertex );
2064
2065 }
2066
2067
2068 //____________________________________________________________________________________________________
2070 {
2071
2072 if( m_extrapolatedPatternBank.find( trk ) == m_extrapolatedPatternBank.end() ) {
2073
2074 std::unique_ptr<ExtrapolatedPattern> exPattern_along( extrapolatedPattern( trk, Trk::alongMomentum ) );
2075
2076 m_extrapolatedPatternBank.emplace( trk, std::make_pair( std::move(exPattern_along), nullptr ) );
2077
2078 }
2079
2080 if( vertex.perp() < 31.0 ) {
2081 double dphi = trk->phi() - vertex.phi();
2082 while( dphi > TMath::Pi() ) { dphi -= TMath::TwoPi(); }
2083 while( dphi < -TMath::Pi() ) { dphi += TMath::TwoPi(); }
2084 if( cos(dphi) < -0.8 ) return false;
2085 }
2086
2087 auto& exPattern = m_extrapolatedPatternBank.at( trk );
2088
2089 using LayerCombination = std::vector<int>;
2090
2091 std::map<LayerCombination, unsigned> layerMap;
2092 if( layerMap.empty() ) {
2093 layerMap[ { 1, 0, 0 } ] = Trk::pixelBarrel0;
2094 layerMap[ { 1, 0, 1 } ] = Trk::pixelBarrel1;
2095 layerMap[ { 1, 0, 2 } ] = Trk::pixelBarrel2;
2096 layerMap[ { 1, 0, 3 } ] = Trk::pixelBarrel3;
2097
2098 layerMap[ { 1, 2, 0 } ] = Trk::pixelEndCap0;
2099 layerMap[ { 1, 2, 1 } ] = Trk::pixelEndCap1;
2100 layerMap[ { 1, 2, 2 } ] = Trk::pixelEndCap2;
2101 layerMap[ { 1,-2, 0 } ] = Trk::pixelEndCap0;
2102 layerMap[ { 1,-2, 1 } ] = Trk::pixelEndCap1;
2103 layerMap[ { 1,-2, 2 } ] = Trk::pixelEndCap2;
2104
2105 layerMap[ { 2, 0, 0 } ] = Trk::sctBarrel0;
2106 layerMap[ { 2, 0, 1 } ] = Trk::sctBarrel1;
2107 layerMap[ { 2, 0, 2 } ] = Trk::sctBarrel2;
2108 layerMap[ { 2, 0, 3 } ] = Trk::sctBarrel3;
2109
2110 layerMap[ { 2, 2, 0 } ] = Trk::sctEndCap0;
2111 layerMap[ { 2, 2, 1 } ] = Trk::sctEndCap1;
2112 layerMap[ { 2, 2, 2 } ] = Trk::sctEndCap2;
2113 layerMap[ { 2, 2, 3 } ] = Trk::sctEndCap3;
2114 layerMap[ { 2, 2, 4 } ] = Trk::sctEndCap4;
2115 layerMap[ { 2, 2, 5 } ] = Trk::sctEndCap5;
2116 layerMap[ { 2, 2, 6 } ] = Trk::sctEndCap6;
2117 layerMap[ { 2, 2, 7 } ] = Trk::sctEndCap7;
2118 layerMap[ { 2, 2, 8 } ] = Trk::sctEndCap8;
2119 layerMap[ { 2,-2, 0 } ] = Trk::sctEndCap0;
2120 layerMap[ { 2,-2, 1 } ] = Trk::sctEndCap1;
2121 layerMap[ { 2,-2, 2 } ] = Trk::sctEndCap2;
2122 layerMap[ { 2,-2, 3 } ] = Trk::sctEndCap3;
2123 layerMap[ { 2,-2, 4 } ] = Trk::sctEndCap4;
2124 layerMap[ { 2,-2, 5 } ] = Trk::sctEndCap5;
2125 layerMap[ { 2,-2, 6 } ] = Trk::sctEndCap6;
2126 layerMap[ { 2,-2, 7 } ] = Trk::sctEndCap7;
2127 layerMap[ { 2,-2, 8 } ] = Trk::sctEndCap8;
2128 }
2129
2130 enum { position=0, detector=1, bec=2, layer=3, isGood=4 };
2131
2132 // Lambda!
2133 auto getDetectorType = [&]( const ExtrapolatedPoint& point ) -> unsigned {
2134
2135 const LayerCombination comb { std::get<detector>( point ), std::get<bec>( point ), std::get<layer>( point ) };
2136
2137 for( auto& pair : layerMap ) {
2138 if( pair.first == comb ) {
2139 return pair.second;
2140 }
2141 }
2142
2144 };
2145
2146 uint32_t disabledPattern { 0 };
2147
2148 // Loop over extrapolated points (along direction)
2149 auto& exPattern_along = *( exPattern.first );
2150
2151 for( auto itr = exPattern_along.begin(); itr != exPattern_along.end(); ++itr ) {
2152 if( std::next( itr ) == exPattern_along.end() ) continue;
2153
2154 const auto& point = *itr;
2155
2156 ATH_MSG_VERBOSE( " > " << __FUNCTION__ << ": isGood = " << std::get<isGood>( point ) );
2157
2158 if( !std::get<isGood>( point ) ) {
2159 const auto& detectorType = getDetectorType( point );
2160 disabledPattern += (1 << detectorType);
2161 }
2162 }
2163
2164 uint32_t hitPattern = trk->hitPattern();
2165 uint32_t modifiedPattern = disabledPattern | hitPattern;
2166
2167 std::string msg = "Disabled hit pattern: ";
2168 for( unsigned i=0; i<Trk::numberOfDetectorTypes; i++) {
2169 msg += Form("%u", ( disabledPattern >> i ) & 1 );
2170 }
2171 ATH_MSG_DEBUG( " > " << __FUNCTION__ << ": " << msg );
2172
2173 msg = "Recorded hit pattern: ";
2174 for( unsigned i=0; i<Trk::numberOfDetectorTypes; i++) {
2175 msg += Form("%u", ( hitPattern >> i ) & 1 );
2176 }
2177 ATH_MSG_DEBUG( " > " << __FUNCTION__ << ": " << msg );
2178
2179 return patternCheck( modifiedPattern, vertex );
2180
2181 }
2182
2183
2184 //____________________________________________________________________________________________________
2186 const xAOD::TrackParticle *itrk,
2187 const xAOD::TrackParticle *jtrk )
2188 {
2189
2190 const bool& check_itrk = ( this->*m_patternStrategyFuncs[m_checkPatternStrategy] )( itrk, FitVertex );
2191 const bool& check_jtrk = ( this->*m_patternStrategyFuncs[m_checkPatternStrategy] )( jtrk, FitVertex );
2192
2193 return ( check_itrk && check_jtrk );
2194
2195 }
2196
2197
2198 //____________________________________________________________________________________________________
2200 {
2201
2202 const auto& vertex = wrkvrt.vertex;
2203
2204 std::map< std::deque<long int>*, std::vector<const xAOD::TrackParticle*>& > indexMap
2205 {
2207 };
2208
2209 for( auto& pair : indexMap ) {
2210
2211 auto* indices = pair.first;
2212 auto& tracks = pair.second;
2213
2214 auto newEnd = std::remove_if( indices->begin(), indices->end(),
2215 [&]( auto& index ) {
2216 bool isConsistent = (this->*m_patternStrategyFuncs[m_checkPatternStrategy] )( tracks.at(index), vertex );
2217 return !isConsistent;
2218 } );
2219
2220 indices->erase( newEnd, indices->end() );
2221
2222 }
2223
2224 }
2225
2226
2227 //____________________________________________________________________________________________________
2229
2230 const xAOD::EventInfo* eventInfo{};
2231 const xAOD::TruthParticleContainer* truthParticles{};
2232 const xAOD::TruthVertexContainer* truthVertices{};
2233
2234 auto sc0 = evtStore()->retrieve( eventInfo, "EventInfo" );
2235 if( sc0.isFailure() ) { return; }
2236
2237 if( !eventInfo->eventType( xAOD::EventInfo::IS_SIMULATION ) ) {
2238 return;
2239 }
2240
2241 auto sc1 = evtStore()->retrieve( truthParticles, "TruthParticles" );
2242 if( sc1.isFailure() ) { return; }
2243
2244 auto sc2 = evtStore()->retrieve( truthVertices, "TruthVertices" );
2245 if( sc2.isFailure() ) { return; }
2246
2247 if( !truthParticles ) { return; }
2248 if( !truthVertices ) { return; }
2249
2250 m_tracingTruthVertices.clear();
2251
2252 std::vector<const xAOD::TruthParticle*> truthSvTracks;
2253
2254 // truth particle selection functions
2255
2256 auto selectNone = [](const xAOD::TruthVertex*) ->bool { return false; };
2257
2258 auto selectRhadron = [](const xAOD::TruthVertex* truthVertex ) -> bool {
2259 if( truthVertex->nIncomingParticles() != 1 ) return false;
2260 if( !truthVertex->incomingParticle(0) ) return false;
2261 if( abs(truthVertex->incomingParticle(0)->pdgId()) < 1000000 ) return false;
2262 if( abs(truthVertex->incomingParticle(0)->pdgId()) > 1000000000 ) return false; // Nuclear codes, e.g. deuteron
2263 // neutralino in daughters
2264 bool hasNeutralino = false;
2265 for( unsigned ip = 0; ip < truthVertex->nOutgoingParticles(); ip++ ) {
2266 const auto* p = truthVertex->outgoingParticle(ip);
2267 if( abs( p->pdgId() ) == 1000022 ) {
2268 hasNeutralino = true;
2269 break;
2270 }
2271 }
2272 return hasNeutralino;
2273 };
2274
2275 auto selectHNL = [](const xAOD::TruthVertex* truthVertex ) -> bool {
2276 if( truthVertex->nIncomingParticles() != 1 ) return false;
2277 if( !truthVertex->incomingParticle(0) ) return false;
2278 if( abs(truthVertex->incomingParticle(0)->pdgId()) != 50 ) return false;
2279 return true;
2280 };
2281
2282 auto selectHiggs = [](const xAOD::TruthVertex* truthVertex ) -> bool {
2283 if( truthVertex->nIncomingParticles() != 1 ) return false;
2284 if( !truthVertex->incomingParticle(0) ) return false;
2285 if( abs(truthVertex->incomingParticle(0)->pdgId()) != 36 ) return false;
2286 return true;
2287 };
2288
2289 auto selectKshort = [](const xAOD::TruthVertex* truthVertex ) -> bool {
2290 if( truthVertex->nIncomingParticles() != 1 ) return false;
2291 if( !truthVertex->incomingParticle(0) ) return false;
2292 if( abs(truthVertex->incomingParticle(0)->pdgId()) != 310 ) return false;
2293 return true;
2294 };
2295
2296 auto selectBhadron = [](const xAOD::TruthVertex* truthVertex ) -> bool {
2297 if( truthVertex->nIncomingParticles() != 1 ) return false;
2298 if( !truthVertex->incomingParticle(0) ) return false;
2299 if( abs(truthVertex->incomingParticle(0)->pdgId()) <= 500 || abs(truthVertex->incomingParticle(0)->pdgId()) >= 600 ) return false;
2300 return true;
2301 };
2302
2303 auto selectHadInt = [](const xAOD::TruthVertex* truthVertex ) -> bool {
2304 if( truthVertex->nIncomingParticles() != 1 ) return false;
2305 if( !truthVertex->incomingParticle(0) ) return false;
2306
2307 const auto* parent = truthVertex->incomingParticle(0);
2308 if( parent->isLepton() ) return false;
2309
2310 TLorentzVector p4sum_in;
2311 TLorentzVector p4sum_out;
2312 for( unsigned ip = 0; ip < truthVertex->nIncomingParticles(); ip++ ) {
2313 const auto* particle = truthVertex->incomingParticle(ip);
2314 TLorentzVector p4; p4.SetPtEtaPhiM( particle->pt(), particle->eta(), particle->phi(), particle->m() );
2315 p4sum_in += p4;
2316 }
2317 for( unsigned ip = 0; ip < truthVertex->nOutgoingParticles(); ip++ ) {
2318 const auto* particle = truthVertex->outgoingParticle(ip);
2319 TLorentzVector p4; p4.SetPtEtaPhiM( particle->pt(), particle->eta(), particle->phi(), particle->m() );
2320 p4sum_out += p4;
2321 }
2322 return p4sum_out.E() - p4sum_in.E() >= 100.;
2323 };
2324
2325
2326
2327 using ParticleSelectFunc = bool (*)(const xAOD::TruthVertex*);
2328 std::map<std::string, ParticleSelectFunc> selectFuncs { { "", selectNone },
2329 { "Kshort", selectKshort },
2330 { "Bhadron", selectBhadron },
2331 { "Rhadron", selectRhadron },
2332 { "HNL", selectHNL },
2333 { "Higgs", selectHiggs },
2334 { "HadInt", selectHadInt } };
2335
2336
2337 if( selectFuncs.find( m_truthParticleFilter ) == selectFuncs.end() ) {
2338 ATH_MSG_WARNING( " > " << __FUNCTION__ << ": invalid function specification: " << m_truthParticleFilter );
2339 return;
2340 }
2341
2342 auto selectFunc = selectFuncs.at( m_truthParticleFilter );
2343
2344 // loop over truth vertices
2345 for( const auto *truthVertex : *truthVertices ) {
2346 if( selectFunc( truthVertex ) ) {
2347 m_tracingTruthVertices.emplace_back( truthVertex );
2348 std::string msg;
2349 msg += Form("pdgId = %d, (r, z) = (%.2f, %.2f), ", truthVertex->incomingParticle(0)->pdgId(), truthVertex->perp(), truthVertex->z());
2350 msg += Form("nOutgoing = %lu, ", truthVertex->nOutgoingParticles() );
2351 msg += Form("mass = %.3f GeV, pt = %.3f GeV", truthVertex->incomingParticle(0)->m()/1.e3, truthVertex->incomingParticle(0)->pt()/1.e3 );
2352 ATH_MSG_DEBUG( " > " << __FUNCTION__ << ": " << msg );
2353 }
2354 }
2355
2356 if( m_FillHist ) {
2357 for( const auto* truthVertex : m_tracingTruthVertices ) {
2358 m_hists["nMatchedTruths"]->Fill( 0., truthVertex->perp() );
2359 }
2360 }
2361
2362 }
2363
2364} // end of namespace VKalVrtAthena
2365
2366
#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
bool patternCheck(const uint32_t &pattern, const Amg::Vector3D &vertex)
std::map< std::string, PatternStrategyFunc > m_patternStrategyFuncs
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
StatusCode refitVertexWithSuggestion(const EventContext &ctx, WrkVrt &, const Amg::Vector3D &)
refit the vertex with suggestion
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 distanceBetweenVertices(const WrkVrt &, const WrkVrt &) const
calculate the physical distance
double improveVertexChi2(const EventContext &, WrkVrt &)
attempt to improve the vertex chi2 by removing the most-outlier track one by one until the vertex chi...
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
StatusCode disassembleVertex(const EventContext &ctx, std::vector< WrkVrt > *, const unsigned &vertexIndex)
std::vector< ExtrapolatedPoint > ExtrapolatedPattern
const xAOD::VertexContainer * m_primaryVertices
std::vector< const xAOD::TrackParticle * > m_associatedTracks
ToolHandle< Trk::ITrkVKalVrtFitter > m_fitSvc
StatusCode refitVertex(const EventContext &, WrkVrt &)
refit the vertex.
std::vector< const xAOD::TrackParticle * > m_selectedTracks
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
StatusCode mergeVertices(const EventContext &ctx, WrkVrt &destination, WrkVrt &source)
the 2nd vertex is merged into the 1st vertex.
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:87
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