ATLAS Offline Software
Loading...
Searching...
No Matches
VertexIterativeFitMergingTool.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// Local
9
10// C/C++
11#include <cmath>
12#include <iostream>
13#include <sstream>
14
15//=============================================================================
17 const std::string &name,
18 const std::string &type,
19 const IInterface *parent
20):
21 AthAlgTool (name, type, parent)
22{
23 declareInterface<Prompt::IVertexMergingTool>(this);
24}
25
26//=============================================================================
28{
29 ATH_CHECK(m_vertexFitterTool.retrieve());
30 ATH_CHECK(m_histSvc.retrieve());
31
32 ATH_CHECK(makeHist(m_histNvtx2TrkInit, "nvtx_2trk_init", 25, -0.5, 24.5));
33 ATH_CHECK(makeHist(m_histNvtx2TrkPass, "nvtx_2trk_pass", 25, -0.5, 24.5));
34 ATH_CHECK(makeHist(m_histNvtx2TrkUnmerged, "nvtx_2trk_unmerged", 25, -0.5, 24.5));
35 ATH_CHECK(makeHist(m_histNvtxMerged, "nvtx_merged", 25, -0.5, 24.5));
36
37 ATH_CHECK(makeHist(m_histNewVtxFitChi2, "newVtxFit_chi2", 100, 0.0, 50.0));
38 ATH_CHECK(makeHist(m_histNewVtxFitProb, "newVtxFit_prob", 100, 0.0, 1.0));
39
40 ATH_CHECK(makeHist(m_histNewVtxFitDistToCurr, "newVtxFit_dist_toCurr", 100, 0.0, 10.0));
41 ATH_CHECK(makeHist(m_histNewVtxFitDistToSeed, "newVtxFit_dist_toSeed", 100, 0.0, 10.0));
42 ATH_CHECK(makeHist(m_histNewVtxFitDistToSeedPass, "newVtxFit_dist_toSeed_pass", 100, 0.0, 10.0));
43 ATH_CHECK(makeHist(m_histNewVtxFitDistToSeedFail, "newVtxFit_dist_toSeed_fail", 100, 0.0, 10.0));
44
45 ATH_CHECK(makeHist(m_histNewVtxFitProbCandOverSeed, "newVtxFit_prob_candOverSeed", 100, 0.0, 4.0));
46 ATH_CHECK(makeHist(m_histNewVtxFitProbCandOverSeedPass, "newVtxFit_prob_candOverSeed_pass", 100, 0.0, 4.0));
47 ATH_CHECK(makeHist(m_histNewVtxFitProbCandOverSeedFail, "newVtxFit_prob_candOverSeed_fail", 100, 0.0, 4.0));
48 ATH_CHECK(makeHist(m_histNewVtxFitProbCandOverSeed3Trk, "newVtxFit_prob_candOverSeed_3trk", 100, 0.0, 4.0));
49 ATH_CHECK(makeHist(m_histNewVtxFitProbCandOverSeed3TrkPass, "newVtxFit_prob_candOverSeed_3trk_pass", 100, 0.0, 4.0));
50
51 ATH_CHECK(makeHist(m_histVtx2TrkPairDist, "Vtx2trkPair_dist", 100, 0.0, 100.0));
52 ATH_CHECK(makeHist(m_histVtx2trkPairDistZoom, "Vtx2trkPair_dist_zoom", 100, 0.0, 10.0));
53 ATH_CHECK(makeHist(m_histVtx2TrkPairSig1, "Vtx2trkPair_sig1", 100, 0.0, 20.0));
54 ATH_CHECK(makeHist(m_histVtx2TrkPairSig2, "Vtx2trkPair_sig2", 100, 0.0, 20.0));
55
56 ATH_CHECK(makeHist(m_histSelectedTrackCountAll, "selectedTrack_CountAll", 25, -0.5, 24.5));
57 ATH_CHECK(makeHist(m_histSelectedTrackCountMatch2Vtx , "selectedTrack_CountMatch2Vtx", 25, -0.5, 24.5));
58 ATH_CHECK(makeHist(m_histSelectedTrackCountWithout2Vtx, "selectedTrack_CountWithout2Vtx", 25, -0.5, 24.5));
59
60 ATH_CHECK(makeHist(m_histVtxWithoutLepton2TrkNTrack, "vtxWithoutLepton2trk_NTrack", 25, -0.5, 24.5));
61 ATH_CHECK(makeHist(m_histVtxWithoutLepton2TrkNPass, "vtxWithoutLepton2trk_NPass", 25, -0.5, 24.5));
62 ATH_CHECK(makeHist(m_histVtxWithoutLepton2TrkNPassUnmerged, "vtxWithoutLepton2trk_NPassUnmerged", 25, -0.5, 24.5));
63 ATH_CHECK(makeHist(m_histVtxWithoutLepton2TrkNMerged, "vtxWithoutLepton2trk_NMerged", 25, -0.5, 24.5));
64
65 return StatusCode::SUCCESS;
66}
67
69 const EventContext& ctx,
70 const FittingInput &input,
71 const xAOD::TrackParticle *tracklep,
72 std::vector<std::unique_ptr<xAOD::Vertex>> &initVtxs,
73 const std::vector<const xAOD::TrackParticle *> &selectedTracks
74)
75{
76 //
77 // Merge initial (2-track) vertices into new merged vertices with three tracks or more
78 //
79
80 ATH_MSG_DEBUG("===========================================================================" << std::endl
81 << name() << "::mergeInitVertices - start processing");
82
83
84 /*
85 We store the initial vertices that pass selection in their own list
86 with ownership, as this needs to be passed later to the MergeResults.
87 */
89 std::vector<std::unique_ptr<xAOD::Vertex>> vtxsInitPassed;
90
91 for(std::unique_ptr<xAOD::Vertex> &vtx: initVtxs) {
92 if(passVertexSelection(vtx.get())) {
93 ATH_MSG_DEBUG("pushing vertex into result.vtxInitPassed");
94 result.vtxsInitPassed.push_back(vtx.get());
95 vtxsInitPassed.push_back(std::move(vtx));
96 }
97 }
98
99 const unsigned nvtxInit = initVtxs.size();
100 const unsigned nvtxPass = result.vtxsInitPassed.size();
101
102 fillTH1(m_histNvtx2TrkInit, nvtxInit);
103
104 //
105 // Find tracks that do not form 2-track vertex with lepton track
106 //
107 ATH_MSG_DEBUG(name() << "::mergeInitVertices - processes vertexes without lepton");
108
109 std::vector<const xAOD::TrackParticle *> tracksWithoutVertex = getTracksWithoutVertex(
110 result.vtxsInitPassed, selectedTracks
111 );
112
113 // Rank the tracks by pT, will keep the top `m_maxExtraTracks` tracks
114 // for fitting vertexes without lepton
115 if(tracksWithoutVertex.size() > m_maxExtraTracks) {
116 ATH_MSG_DEBUG(" number of tracks without good lepton+track vertex: " << tracksWithoutVertex.size() << std::endl
117 << " will only keep the top " << m_maxExtraTracks << " tracks");
118
119 std::sort(tracksWithoutVertex.begin(), tracksWithoutVertex.end(), Prompt::SortByIDTrackPt());
120
121 tracksWithoutVertex.erase(tracksWithoutVertex.begin() + m_maxExtraTracks, tracksWithoutVertex.end());
122 }
123
124
125 MergeResultNotOwner resultExtra;
126 std::vector<std::unique_ptr<xAOD::Vertex>> twoTrackVtxInit = fit2TrackVertexes(ctx, input, tracksWithoutVertex, Prompt::kTwoTrackVtxWithoutLepton);
127
129 name() << "::mergeInitVertices - will merge vertexes without lepton" << std::endl
130 << " number of selected tracks without good lepton+track vertex: "
131 << tracksWithoutVertex .size() << std::endl
132 << " number of 2-track vertexes without lepton: "
133 << resultExtra.vtxsInitPassed.size()
134 );
135
136 //
137 // Merge 2-track vertex without lepton only when there are two or more vertices
138 //
139 mergeIteratively2TrackVtxs(ctx, input, twoTrackVtxInit, resultExtra, Prompt::kIterativeFitVtxWithoutLepton);
140
141 if(resultExtra.vtxsInitPassed.size() > 1) {
142 //
143 // Fill histograms only when there are two or more vertices
144 //
145 fillTH1(m_histVtxWithoutLepton2TrkNTrack, tracksWithoutVertex.size());
149 }
150
151 ATH_MSG_DEBUG(name() << "::mergeInitVertices - finished merging vertexes without lepton" << std::endl
152 << " number of tracks without good lepton+track vertex: " << tracksWithoutVertex.size() << std::endl
153 << " number of 2-track vertexes without lepton: " << resultExtra.vtxsInitPassed.size() << std::endl
154 << " number of unmerged 2-track vertexes without lepton: " << resultExtra.vtxsInitPassedNotMerged.size() << std::endl
155 << " number of merged vertexes without lepton: " << resultExtra.vtxsNewMerged.size());
156
157 //
158 // Next, processes 2-track vertexes that contain lepton track
159 //
160 ATH_MSG_DEBUG("===========================================================================" << std::endl
161 << name() << "::mergeInitVertices - process 2-track vertexes with lepton" << std::endl
162 << " lepton track pT=" << tracklep->pt() << std::endl
163 << " number of initial 2-track vertices: " << initVtxs.size() << std::endl
164 << " number of selected 2-track vertices: " << result.vtxsInitPassed.size() << std::endl
165 << " number of selected ID tracks: " << selectedTracks.size() );
166
167 //
168 // Merge 2-track vertexes that contain lepton track
169 //
170 mergeIteratively2TrackVtxs(ctx, input, vtxsInitPassed, result, Prompt::kIterativeFitVtx);
171
172 if(result.vtxsInitPassed.size() > 1) {
173 //
174 // Fill histograms only when there are at least two vertexes to merge
175 //
176 fillTH1(m_histNvtx2TrkPass, nvtxPass);
177 fillTH1(m_histNvtx2TrkUnmerged, result.vtxsInitPassedNotMerged.size());
178 fillTH1(m_histNvtxMerged, result.vtxsNewMerged .size());
179 }
180
181 //
182 // Erase vector of 2-track vertices without lepton that were merged
183 //
184 resultExtra.vtxsInitPassed.clear();
185
186 //
187 // Add vertices without lepton track to result
188 //
189 result.vtxsInitPassedNotMerged.insert(
190 result.vtxsInitPassedNotMerged.end(),
191 std::make_move_iterator(resultExtra.vtxsInitPassedNotMerged.begin()),
192 std::make_move_iterator(resultExtra.vtxsInitPassedNotMerged.end())
193 );
194
195 result.vtxsNewMerged.insert(
196 result.vtxsNewMerged.end(),
197 std::make_move_iterator(resultExtra.vtxsNewMerged.begin()),
198 std::make_move_iterator(resultExtra.vtxsNewMerged.end())
199 );
200
201 ATH_MSG_DEBUG("==========================================" << std::endl
202 << "mergeInitVertices report" << std::endl
203 << " \tnumber of initial 2-track vertices: "
204 << initVtxs.size() << std::endl
205 << "\tnumber of passed 2-track vertices: "
206 << result.vtxsInitPassed.size() << std::endl
207 << "\tnumber of unmerged 2-track vertices: "
208 << result.vtxsInitPassedNotMerged.size() << std::endl
209 << "\tnumber of merged vertices: "
210 << result.vtxsNewMerged.size() << std::endl
211 << std::endl
212 << "\tnumber of tracks without good lepton+track vertex: "
213 << tracksWithoutVertex.size() << std::endl
214 << "\tnumber of 2-track vertexes without lepton: "
215 << resultExtra.vtxsInitPassed.size() << std::endl
216 << "\tnumber of unmerged 2-track vertexes without lepton: "
217 << resultExtra.vtxsInitPassedNotMerged.size() << std::endl
218 << "\tnumber of merged vertexes without lepton: "
219 << resultExtra.vtxsNewMerged.size() << std::endl
220 << name() << "::mergeInitVertices - ALL DONE" << std::endl
221 << "=========================================="
222 );
223
224
225 return result;
226}
227
229 const EventContext& ctx,
230 const FittingInput &input,
231 std::vector<std::unique_ptr<xAOD::Vertex>> &initVtxs,
232 MergeResultNotOwner &result,
233 const VtxType vtxType
234)
235{
236 /*
237 This function merges iterively vertexes with this algorithm:
238 o) Sort 2-track vertexes by sum of track pT
239 o) Select the vertex with the highest sum of track pT as the seed vertex
240 - Sort all other vertexes by the distance to the seed vertex
241 - Add tracks from the closest vertex to the selected vertex
242 - Fit new vertex:
243 -- if the new vertex passes cuts, select as the new seed vertex
244 -- if the new vertex fails cuts, continue with the original seed vertex
245 -- Remove this closest vertex from the list
246 - Resort remaining tracks by the distance to the seed vertex and repeat
247 o) Remove the 2-track vertexes that were merged from the global list and repeat
248 */
249
250 // Only 0 or 1 2-track vertices - add the vertex to not merged list and return
251 if(result.vtxsInitPassed.size() < 2) {
252 result.vtxsInitPassedNotMerged = std::move(initVtxs);
253
254 ATH_MSG_DEBUG(name() << "::mergeIteratively2TrackVtxs - too few vertexes: nothing more to do");
255
256 return false;
257 }
258
259 //
260 // Make 2-track vertex data structures
261 //
262 std::vector<TwoTrackVtx> vtxs2Track;
263
264 for(std::unique_ptr<xAOD::Vertex> &vtx: initVtxs) {
265 if(vtx->nTrackParticles() != 2) {
266 ATH_MSG_WARNING("mergeIteratively2TrackVtxs - wrong number of tracks: " << vtx->nTrackParticles());
267 continue;
268 }
269
270 if(vtx->nTrackParticles() !=2 ) {
271 ATH_MSG_WARNING("mergeIteratively2TrackVtxs - vertex does not contain 2 TrackParticles: ntrack=" << vtx->nTrackParticles());
272 continue;
273 }
274
275 TwoTrackVtx vtx2track;
276 vtx2track.trackId0 = vtx->trackParticle(0);
277 vtx2track.trackId1 = vtx->trackParticle(1);
278
279 if(!vtx2track.trackId0 || !vtx2track.trackId1) {
280 ATH_MSG_WARNING("mergeIteratively2TrackVtxs - failed to find TrackParticles for 2-track vertex");
281 continue;
282 }
283
284 vtx2track.vertex = vtx.get();
285 vtx2track.vertexFitProb = Prompt::getVertexFitProb(vtx.get());
286 vtx2track.sumTrackPt = vtx2track.trackId0->pt() + vtx2track.trackId1->pt();
287
288 vtxs2Track.push_back(vtx2track);
289 }
290
291 ATH_MSG_DEBUG(name() << "::mergeIteratively2TrackVtxs - start processing with " << vtxs2Track.size() << " input vertexes ");
292
293 if(vtxs2Track.size() < 2) {
294 ATH_MSG_WARNING("mergeIteratively2TrackVtxs - logic error: found only " << vtxs2Track.size() << " 2-track vertex");
295 return false;
296 }
297
298 //
299 // Sort 2-track vertexes by ID track pT
300 //
301 std::sort(vtxs2Track.begin(), vtxs2Track.end(), Prompt::SortTwoTrackVtxBySumTrackPt());
302
303 ATH_MSG_DEBUG(name() << "::mergeIteratively2TrackVtxs - number of 2 track passed vertexes=" << vtxs2Track.size());
304
305 for(const TwoTrackVtx &vtx: vtxs2Track) {
306 ATH_MSG_DEBUG("Input vertex with 2 tracks sum pT=" << vtx.sumTrackPt << "\n " << vtxAsStr(vtx.vertex, true));
307 }
308
309 //
310 // Plot distances between all unique pairs of 2-track vertexes
311 //
312 plotVertexDistances(vtxs2Track);
313
314 //
315 // Iterative fit vertices for merging:
316 //
317 std::vector<TwoTrackVtx>::iterator currVit = vtxs2Track.begin();
318
319 /*
320 Seed new vertex with 2-track vertex containing
321 highest pT ID track (non-lepton track)
322 */
323 while(currVit != vtxs2Track.end()) {
324 xAOD::Vertex* seedVtx = currVit->vertex;
325
326 /*
327 We potentially generate a new vertex here,
328 so it has to be a unique_ptr. If the vertex could not be merged,
329 then the newMergedVtx will remain a nullptr.
330 */
331 std::unique_ptr<xAOD::Vertex> newMergedVtx = nullptr;
333 ctx, seedVtx, newMergedVtx, input, currVit, vtxs2Track, vtxType
334 );
335
336 // Check to see if the new merged vertex is not a nullptr
337 // (i.e., if the vertex could be merged)
338 if(newMergedVtx) {
339 // Remove 2-track vertexes that were merged
340 removeMerged2TrackVertexes(newMergedVtx.get(), vtxs2Track);
341
342 // Reset current vertex iterator to beginning
343 currVit = vtxs2Track.begin();
344
345 ATH_MSG_DEBUG(name() << "::mergeIteratively2TrackVtxs - new merged vertex:\n" << vtxAsStr(newMergedVtx.get(), false));
346
347 // Save new merged vertex (it is new because it is distinct from seed vertex)
348 result.vtxsNewMerged.push_back(std::move(newMergedVtx));
349 }
350 else {
351 //
352 // This vertex could not be merged - try next one
353 //
354 ++currVit;
355
356 ATH_MSG_DEBUG(name() << "::mergeIteratively2TrackVtxs - could not merge 2-track vertex:\n" << vtxAsStr(seedVtx, false));
357 }
358 }
359
360 //
361 // Record unmerged two-track vertexes
362 //
363 for(std::unique_ptr<xAOD::Vertex> &vtxUniquePtr: initVtxs) {
364 for(TwoTrackVtx &vtx: vtxs2Track) {
365 if (vtxUniquePtr.get() == vtx.vertex){
366 result.vtxsInitPassedNotMerged.push_back(std::move(vtxUniquePtr));
367
368 ATH_MSG_DEBUG("Unmerged " << vtxAsStr(vtx.vertex, true));
369 }
370 }
371 }
372
373 ATH_MSG_DEBUG(name() << "::mergeIteratively2TrackVtxs - finished processing:" << std::endl
374 << " number of unmerged 2-track vertexes=" << vtxs2Track .size() << std::endl
375 << " number of merged vertexes=" << result.vtxsNewMerged.size() );
376
377 for(TwoTrackVtx &vtx: vtxs2Track) {
378 ATH_MSG_DEBUG("Unmerged " << vtxAsStr(vtx.vertex, true));
379 }
380
381 for(const std::unique_ptr<xAOD::Vertex>& vtx: result.vtxsNewMerged) {
382 ATH_MSG_DEBUG("Merged " << vtxAsStr(vtx.get(), true));
383 }
384
385 return true;
386}
387
389 const EventContext& ctx,
390 xAOD::Vertex* seedVtx,
391 std::unique_ptr<xAOD::Vertex> &newMergedVtx,
392 const FittingInput &input,
393 std::vector<TwoTrackVtx>::iterator &currVit,
394 std::vector<TwoTrackVtx> &vtxs2Track,
395 const VtxType vtxType
396) {
397 // Generate a list of 2-track vertices other than the seed vertex
398 std::vector<TwoTrackVtx> others;
399
400 for(std::vector<TwoTrackVtx>::iterator vit = vtxs2Track.begin(); vit != vtxs2Track.end(); ++vit) {
401 if(vit != currVit) {
402 others.push_back(*vit);
403 }
404 }
405
406 // Sort other vertices by distance to the seed vertex
407 std::sort(others.begin(), others.end(), Prompt::SortTwoTrackVtxByDistToSeed(seedVtx));
408
409 // Call recursive function to fit seed+closest vertex pairs
411 ctx, input, seedVtx, vtxType, others
412 );
413
414 /*
415 If the returned vertex is the seed vertex, that means that the
416 vertex could not be merged. We do not want to return it because
417 then we would assign two unique_ptrs to the same underlying
418 vertex object. Instead, we leave newMergedVtx as a nullptr
419
420 If they are different, then we do in fact have a new vertex,
421 and we are safe to encapsulate it in a unique_ptr.
422 */
423 if (mergedVtx == seedVtx){
424 newMergedVtx.reset(nullptr);
425 } else {
426 newMergedVtx.reset(mergedVtx);
427 }
428}
429
430//=============================================================================
432 const EventContext& ctx,
433 const FittingInput &input,
434 xAOD::Vertex* seedVtx,
435 const VtxType vtxType,
436 std::vector<TwoTrackVtx> &others
437)
438{
439 //
440 // Reached end of the recursive loop
441 //
442 if(others.empty()) {
443 return seedVtx;
444 }
445
446 //
447 // Re-sort other vertices by distance to the seed vertex - needed because seed position changes when vertices are merged
448 //
449 std::sort(others.begin(), others.end(), Prompt::SortTwoTrackVtxByDistToSeed(seedVtx));
450
451 // Take closest vertex
452 xAOD::Vertex* currVtx = others.front().vertex;
453
454 if(!currVtx) {
455 ATH_MSG_WARNING("VertexIterativeFitMergingTool::fitSeedVertexCluster - current vertex is null pointer");
456 return seedVtx;
457 }
458
459 //
460 // Remove closest vertex from the list
461 //
462 others.erase(others.begin());
463
464 /*
465 Found nearby vertex - fit merged vertex
466 */
467 std::unique_ptr<xAOD::Vertex> candVtx =fitSeedPlusOtherVertex(
468 ctx, input, seedVtx, currVtx, vtxType
469 );
470
471 if(!candVtx) {
472 //
473 // Failed to fit new vertex - continue with current seed vertex
474 //
475
476 ATH_MSG_DEBUG("fitSeedVertexCluster - NEW MERGED VERTEX FIT FAILED" << std::endl
477 << "---------------------------------------------------------------------------");
478
479 return fitSeedVertexCluster(ctx, input, std::move(seedVtx), vtxType, others);
480 }
481
482 const double probCand = getVertexFitProb(candVtx.get());
483 const double probSeed = getVertexFitProb(seedVtx);
484
485 double probCandOverSeed = -1.0;
486
487 if(probSeed > 0.0) {
488 probCandOverSeed = probCand/probSeed;
489 }
490
491 const double distToSeed = getDistance(seedVtx, candVtx.get());
492 const double distToCurr = getDistance(currVtx, candVtx.get());
493
494 fillTH1(m_histNewVtxFitChi2, candVtx->chiSquared());
495 fillTH1(m_histNewVtxFitProb, probCand);
496
499 fillTH1(m_histNewVtxFitProbCandOverSeed, probCandOverSeed);
500
501 if(seedVtx->nTrackParticles() > 2) {
503 }
504
505 std::stringstream str;
506
507
508 str << " dist to seed=" << distToSeed << ", probCandOverSeed=" << probCandOverSeed << std::endl
509 << " seed: " << vtxAsStr(seedVtx, false) << std::endl
510 << " curr: " << vtxAsStr(currVtx, true)
511 << " cand: " << vtxAsStr(candVtx.get(), true)
512 << "fitSeedVertexCluster - finished" << std::endl
513 << "---------------------------------------------------------------------------" << std::endl;
514
515
516
517 if(!(passVertexSelection(candVtx.get()) && probCandOverSeed > m_minCandOverSeedFitProbRatio)) {
518 //
519 // New fitted merged vertex failed selection
520 //
521
522 ATH_MSG_DEBUG("fitSeedVertexCluster - FAIL NEW MERGED VERTEX\n" << str.str());
523
524
527
528 //
529 // Continue with current seed vertex
530 //
531 return fitSeedVertexCluster(ctx, input, seedVtx, vtxType, others);
532 }
533
536
537 if(seedVtx->nTrackParticles() > 2) {
539 }
540
541 //
542 // Succesfully fitted new vertex
543 //
544
545 ATH_MSG_DEBUG("fitSeedVertexCluster - PASS NEW MERGED VERTEX" << str.str());
546
547
548 return fitSeedVertexCluster(ctx, input, candVtx, vtxType, others);
549}
550
551// this signature is only called recursively, if a merged vertex candidate has been
552// found. Ensures that we release the final merged candidate to hand it
553// back to the original caller.
555 const EventContext& ctx,
556 const FittingInput &input,
557 std::unique_ptr<xAOD::Vertex> & seedVtx,
558 const VtxType vtxType,
559 std::vector<TwoTrackVtx> &others
560){
561 // remember the seed vertex before the call
562 xAOD::Vertex* originalSeed = seedVtx.get();
563 // call the original signature
564 xAOD::Vertex* iterationResult = fitSeedVertexCluster(ctx, input,seedVtx.get(), vtxType,others);
565 // if the iteration has finished (it is returning the seed), release the seed vertex.
566 // This will be re-captured by the top level caller after exiting the recursion stack.
567 if (iterationResult == originalSeed) return seedVtx.release();
568 // otherwise, return the iteration result. The seed vertex will be deleted
569 // when the call stack unwinds.
570 else return iterationResult;
571}
572
574 const xAOD::Vertex *mergedVtx,
575 std::vector<TwoTrackVtx> &vtxs
576) const {
577 if(!mergedVtx) {
578 ATH_MSG_WARNING("VertexIterativeFitMergingTool::removeMerged2TrackVertexes - merged vertex is null pointer");
579 return 0;
580 }
581
582 unsigned icount = 0;
583 std::vector<TwoTrackVtx>::iterator vit = vtxs.begin();
584
585 while(vit != vtxs.end()) {
586 int iCountMatchedTrack = 0;
587
588 for(unsigned k = 0; k < mergedVtx->nTrackParticles(); ++k) {
589 const xAOD::TrackParticle *track = mergedVtx->trackParticle(k);
590
591 if(!track) {
592 ATH_MSG_WARNING("removeMerged2TrackVertexes - merged vertex contains null TrackParticle pointer");
593 continue;
594 }
595
596 if(vit->trackId0 == track) { iCountMatchedTrack++; }
597 if(vit->trackId1 == track) { iCountMatchedTrack++; }
598 }
599
600 if(iCountMatchedTrack == 2) {
601 //
602 // Found 2-track vertex that was merged - remove this vertex
603 //
604 vit = vtxs.erase(vit);
605 icount++;
606
607 ATH_MSG_DEBUG("removeMerged2TrackVertexes - removed merged 2-track vertex");
608 }
609 else {
610 ++vit;
611
612 ATH_MSG_DEBUG("removeMerged2TrackVertexes - skip unmerged 2-track vertex");
613 }
614 }
615
617 name() << "::removeMerged2TrackVertexes - merged vertex ntrack=" << mergedVtx->nTrackParticles()
618 << ", removed " << icount << " merged 2-track vertexes"
619 );
620
621 return icount;
622}
623
624//=============================================================================
626 const std::vector<TwoTrackVtx> &others
627) {
628 for(std::vector<TwoTrackVtx>::const_iterator fit = others.begin(); fit != others.end(); ++fit) {
629 for(std::vector<TwoTrackVtx>::const_iterator sit = fit+1; sit != others.end(); ++sit) {
630 const double dist = Prompt::getDistance(fit->vertex, sit->vertex);
631 const double sig1 = Prompt::getNormDist(fit->vertex->position(), sit->vertex->position(), fit->vertex->covariance(), msg(MSG::WARNING));
632 const double sig2 = Prompt::getNormDist(fit->vertex->position(), sit->vertex->position(), sit->vertex->covariance(), msg(MSG::WARNING));
633
638 }
639 }
640}
641
642//=============================================================================
644 const std::vector<xAOD::Vertex*> &passVtxs,
645 const std::vector<const xAOD::TrackParticle *> &selectedTracks
646)
647{
648 //
649 // Plot unmatched tracks
650 //
651 std::vector<const xAOD::TrackParticle *> tracksWithoutVertex;
652
653 unsigned iCountDoMatch = 0;
654
655 for(const xAOD::TrackParticle *track: selectedTracks) {
656 bool match = false;
657
658 for(const xAOD::Vertex *vtx: passVtxs) {
659 for(unsigned k = 0; k < vtx->nTrackParticles(); ++k) {
660 const xAOD::TrackParticle *vtxTrack = vtx->trackParticle(k);
661
662 if(vtxTrack == track) {
663 match = true;
664 break;
665 }
666 }
667 }
668
669 if(match) {
670 iCountDoMatch++;
671 }
672 else {
673 tracksWithoutVertex.push_back(track);
674 }
675 }
676
677 fillTH1(m_histSelectedTrackCountAll, selectedTracks.size());
679 fillTH1(m_histSelectedTrackCountWithout2Vtx, tracksWithoutVertex.size());
680
681 return tracksWithoutVertex;
682}
683
684//=============================================================================
686{
687 //
688 // Check whether vertex passes quality cuts
689 //
690 if(!vtx) {
691 ATH_MSG_WARNING("passVertexSelection - input vertex is null pointer");
692 return false;
693 }
694
695 if(!(vtx->numberDoF() > 0 && vtx->chiSquared() >= 0)) {
696 return false;
697 }
698
699 const double fitProb = Prompt::getVertexFitProb(vtx);
700
701 ATH_MSG_DEBUG("passVertexSelection - vertex pointer=" << vtx << " chi2/ndof=" << vtx->chiSquared() << "/" << vtx->numberDoF() << ", prob=" << fitProb);
702
703 return fitProb > m_minFitProb;
704}
705
706//=============================================================================
708 const EventContext& ctx,
709 const FittingInput &input,
710 const xAOD::Vertex *seedVtx,
711 const xAOD::Vertex *otherVtx,
712 const VtxType vtxType
713)
714{
715 //
716 // Fit two 2-track vertexes
717 //
718 if(!seedVtx) {
719 ATH_MSG_WARNING("fitSeedPlusOtherVertex - null seed Vertex pointer");
720 return 0;
721 }
722
723 if(!otherVtx) {
724 ATH_MSG_WARNING("fitSeedPlusOtherVertex - null other Vertex pointer");
725 return 0;
726 }
727
728 if(otherVtx->nTrackParticles() != 2) {
729 ATH_MSG_WARNING("fitSeedPlusOtherVertex - other Vertex does not have 2 tracks: ntrack=" << otherVtx->nTrackParticles());
730 return 0;
731 }
732
733 //
734 // Collect tracks from the seed vertex
735 //
736 std::vector<const xAOD::TrackParticle *> tracks;
737
738 for(unsigned k = 0; k < seedVtx->nTrackParticles(); ++k) {
739 const xAOD::TrackParticle *track = seedVtx->trackParticle(k);
740
741 if(track) {
742 tracks.push_back(track);
743 }
744 else {
745 ATH_MSG_WARNING("fitSeedPlusOtherVertex - seed vertex contains TrackParticle null pointer");
746 }
747 }
748
749 //
750 // Collect tracks from other vertices
751 //
752 for(unsigned k = 0; k < otherVtx->nTrackParticles(); ++k) {
753 const xAOD::TrackParticle *track = otherVtx->trackParticle(k);
754
755 if(track) {
756 tracks.push_back(track);
757 }
758 else {
759 ATH_MSG_WARNING("fitSeedPlusOtherVertex - other vertex contains TrackParticle null pointer");
760 }
761 }
762
763 //
764 // Fit new vertex
765 //
766 std::unique_ptr<xAOD::Vertex> secVtx = m_vertexFitterTool->fitVertexWithSeed(
767 ctx, input, tracks, seedVtx->position(), vtxType
768 );
769
770 if(!secVtx) {
771 ATH_MSG_WARNING("fitSeedPlusOtherVertex - failed to fit vertex");
772 return 0;
773 }
774
775 return secVtx;
776}
777
778std::vector<std::unique_ptr<xAOD::Vertex>> Prompt::VertexIterativeFitMergingTool::fit2TrackVertexes(
779 const EventContext& ctx,
780 const FittingInput &input,
781 std::vector<const xAOD::TrackParticle *> &selectedTracks,
782 const VtxType vtxType
783)
784{
785 //
786 // Fit all possible combinations of two 2-track vertexes
787 //
788 std::vector<std::unique_ptr<xAOD::Vertex>> passVtxs;
789
790 if(selectedTracks.size() < 2) {
791 ATH_MSG_DEBUG("fit2TrackVertexeses - 0 or 1 input tracks - nothing to do");
792 return passVtxs;
793 }
794
795 ATH_MSG_DEBUG(name() << "::fit2TrackVertexes - start with " << selectedTracks.size() << " tracks");
796
797 //
798 // Sort tracks by decreasing pT
799 //
800 std::sort(selectedTracks.begin(), selectedTracks.end(), SortTracksByPt());
801
802 unsigned icount = 0;
803
804 for(std::vector<const xAOD::TrackParticle *>::const_iterator it1 = selectedTracks.begin(); it1 != selectedTracks.end(); ++it1) {
805 for(std::vector<const xAOD::TrackParticle *>::const_iterator it2 = it1 + 1; it2 != selectedTracks.end(); ++it2) {
806 const xAOD::TrackParticle *track1 = *it1;
807 const xAOD::TrackParticle *track2 = *it2;
808
809 if(!track1 || !track2) {
810 ATH_MSG_WARNING("fit2TrackVertexeses - logic error: TrackParticle null pointer");
811 continue;
812 }
813
814 std::vector<const xAOD::TrackParticle *> fit_tracks = {track1, track2};
815
816 //
817 // Fit new vertex
818 //
819 std::unique_ptr<xAOD::Vertex> vtx = m_vertexFitterTool->fitVertexWithPrimarySeed(
820 ctx, input, fit_tracks, vtxType
821 );
822
823 icount++;
824
825 if(!vtx) {
826 ATH_MSG_WARNING("fit2TrackVertexeses - failed to fit vertex");
827 continue;
828 }
829
830 if(passVertexSelection(vtx.get())) {
831 ATH_MSG_DEBUG("fit2TrackVertexeses - pass vertex: " << vtxAsStr(vtx.get(), true));
832 passVtxs.push_back(std::move(vtx));
833 }
834 }
835 }
836
837 ATH_MSG_DEBUG(name() << "::fit2TrackVertexes - finished processing: " << std::endl
838 << " number of input tracks: " << selectedTracks.size() << std::endl
839 << " number of 2-track combinations: " << icount << std::endl
840 << " number of passed 2-track vertexes: " << passVtxs .size() << std::endl
841 << name() << "::fit2TrackVertexes - all is done" );
842
843 return passVtxs;
844}
845
846//=============================================================================
847StatusCode Prompt::VertexIterativeFitMergingTool::makeHist(TH1 *&h, const std::string &key, int nbin, double xmin, double xmax)
848{
849 //
850 // Initiliase histogram pointer. If configured to run in validation mode, then create and register histogram
851 //
852 h = 0;
853
854 if(m_outputStream.empty() || key.empty()) {
855 return StatusCode::SUCCESS;
856 }
857
858 const std::string hname = name() + "_" + key;
859 const std::string hist_key = "/"+m_outputStream+"/"+hname;
860
861 h = new TH1D(hname.c_str(), hname.c_str(), nbin, xmin, xmax);
862 h->SetDirectory(0);
863
864 return m_histSvc->regHist(hist_key, h);
865}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
size_t size() const
Number of registered mappings.
AthAlgTool(const std::string &type, const std::string &name, const IInterface *parent)
Constructor with parameters:
MsgStream & msg() const
Header file for AthHistogramAlgorithm.
std::vector< const xAOD::TrackParticle * > getTracksWithoutVertex(const std::vector< xAOD::Vertex * > &passVtxs, const std::vector< const xAOD::TrackParticle * > &selectedTracks)
ToolHandle< Prompt::IVertexFittingTool > m_vertexFitterTool
void plotVertexDistances(const std::vector< TwoTrackVtx > &others)
std::vector< std::unique_ptr< xAOD::Vertex > > fit2TrackVertexes(const EventContext &ctx, const FittingInput &input, std::vector< const xAOD::TrackParticle * > &selectedTracks, const VtxType vtxType)
bool mergeIteratively2TrackVtxs(const EventContext &ctx, const FittingInput &input, std::vector< std::unique_ptr< xAOD::Vertex > > &initVtxs, MergeResultNotOwner &result, const VtxType vtxType)
VertexIterativeFitMergingTool(const std::string &name, const std::string &type, const IInterface *parent)
void getNewMergedVertex(const EventContext &ctx, xAOD::Vertex *seedVtx, std::unique_ptr< xAOD::Vertex > &newMergedVtx, const FittingInput &input, std::vector< TwoTrackVtx >::iterator &currVit, std::vector< TwoTrackVtx > &vtxs2Track, const VtxType vtxType)
StatusCode makeHist(TH1 *&h, const std::string &key, int nbin, double xmin, double xmax)
std::unique_ptr< xAOD::Vertex > fitSeedPlusOtherVertex(const EventContext &ctx, const FittingInput &input, const xAOD::Vertex *seedVtx, const xAOD::Vertex *otherVtx, const VtxType vtxType)
virtual MergeResultNotOwner mergeInitVertices(const EventContext &ctx, const FittingInput &input, const xAOD::TrackParticle *tracklep, std::vector< std::unique_ptr< xAOD::Vertex > > &initVtxs, const std::vector< const xAOD::TrackParticle * > &selectedTracks) override
xAOD::Vertex * fitSeedVertexCluster(const EventContext &ctx, const FittingInput &input, xAOD::Vertex *seedVtx, const VtxType vtxType, std::vector< TwoTrackVtx > &others)
unsigned removeMerged2TrackVertexes(const xAOD::Vertex *mergedVtx, std::vector< TwoTrackVtx > &vtxs) const
bool passVertexSelection(const xAOD::Vertex *vtx) const
virtual double pt() const override final
The transverse momentum ( ) of the particle.
size_t nTrackParticles() const
Get the number of tracks associated with this vertex.
const TrackParticle * trackParticle(size_t i) const
Get the pointer to a given track that was used in vertex reco.
float numberDoF() const
Returns the number of degrees of freedom of the vertex fit as float.
float chiSquared() const
Returns the of the vertex fit as float.
const Amg::Vector3D & position() const
Returns the 3-pos.
bool match(std::string s1, std::string s2)
match the individual directories of two strings
Definition hcg.cxx:359
double xmax
Definition listroot.cxx:61
double xmin
Definition listroot.cxx:60
void fillTH1(TH1 *h, double val, double weight=1.0)
@ kTwoTrackVtxWithoutLepton
@ kIterativeFitVtxWithoutLepton
double getVertexFitProb(const xAOD::Vertex *vtx)
std::string vtxAsStr(const xAOD::Vertex *vtx, bool print_tracks=false)
double getNormDist(const Amg::Vector3D &PrimVtx, const Amg::Vector3D &SecVtx, const std::vector< float > &ErrorMatrix, MsgStream &msg)
double getDistance(const xAOD::Vertex *vtx1, const xAOD::Vertex *vtx2)
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
TrackParticle_v1 TrackParticle
Reference the current persistent version:
Vertex_v1 Vertex
Define the latest version of the vertex class.
const xAOD::TrackParticle * trackId0
const xAOD::TrackParticle * trackId1