12 template <
typename vfitter_t,
typename sfinder_t>
14 const std::vector<const InputTrack_t*>& allTracks,
17 if (allTracks.empty()) {
18 ACTS_ERROR(
"Empty track collection handed to find method");
19 return VertexingError::EmptyInput;
22 const std::vector<const InputTrack_t*>& origTracks = allTracks;
25 std::vector<const InputTrack_t*> seedTracks = allTracks;
30 std::vector<std::unique_ptr<Vertex<InputTrack_t>>> allVertices;
32 std::vector<Vertex<InputTrack_t>*> allVerticesPtr;
35 std::vector<const InputTrack_t*> removedSeedTracks;
36 while (((
m_cfg.addSingleTrackVertices && !seedTracks.empty()) ||
37 ((!
m_cfg.addSingleTrackVertices) && !seedTracks.empty())) &&
38 iteration <
m_cfg.maxIterations) {
41 std::vector<const InputTrack_t*> searchTracks;
42 if (
m_cfg.doRealMultiVertex) {
43 searchTracks = origTracks;
45 searchTracks = seedTracks;
49 auto seedResult = doSeeding(seedTracks, currentConstraint, vertexingOptions,
50 seedFinderState, removedSeedTracks);
51 if (!seedResult.ok()) {
52 return seedResult.error();
57 allVerticesPtr.push_back(&vtxCandidate);
59 ACTS_DEBUG(
"Position of current vertex candidate after seeding: "
64 "No seed found anymore. Break and stop primary vertex finding.");
65 allVertices.pop_back();
66 allVerticesPtr.pop_back();
72 removedSeedTracks.clear();
74 auto prepResult = canPrepareVertexForFit(searchTracks, seedTracks,
75 vtxCandidate, currentConstraint,
76 fitterState, vertexingOptions);
78 if (!prepResult.ok()) {
79 return prepResult.error();
82 ACTS_DEBUG(
"Could not prepare for fit anymore. Break.");
83 allVertices.pop_back();
84 allVerticesPtr.pop_back();
88 fitterState.addVertexToMultiMap(vtxCandidate);
91 auto fitResult =
m_cfg.vertexFitter.addVtxToFit(
92 fitterState, vtxCandidate,
m_cfg.linearizer, vertexingOptions);
93 if (!fitResult.ok()) {
94 return fitResult.error();
96 ACTS_DEBUG(
"New position of current vertex candidate after fit: "
99 auto [nCompatibleTracks, isGoodVertex] =
100 checkVertexAndCompatibleTracks(vtxCandidate, seedTracks, fitterState,
103 ACTS_DEBUG(
"Vertex is good vertex: " << isGoodVertex);
104 if (nCompatibleTracks > 0) {
105 removeCompatibleTracksFromSeedTracks(vtxCandidate, seedTracks,
106 fitterState, removedSeedTracks);
108 bool removedIncompatibleTrack = removeTrackIfIncompatible(
109 vtxCandidate, seedTracks, fitterState, removedSeedTracks,
111 if (!removedIncompatibleTrack) {
113 "Could not remove any further track from seed tracks. Break.");
114 allVertices.pop_back();
115 allVerticesPtr.pop_back();
119 bool keepVertex = isGoodVertex &&
120 keepNewVertex(vtxCandidate, allVerticesPtr, fitterState);
121 ACTS_DEBUG(
"New vertex will be saved: " << keepVertex);
124 if (not keepVertex) {
125 auto deleteVertexResult =
126 deleteLastVertex(vtxCandidate, allVertices, allVerticesPtr,
127 fitterState, vertexingOptions);
128 if (not deleteVertexResult.ok()) {
129 return deleteVertexResult.error();
135 return getVertexOutputList(allVerticesPtr, fitterState);
138 template <
typename vfitter_t,
typename sfinder_t>
140 const std::vector<const InputTrack_t*>& trackVector,
144 const std::vector<const InputTrack_t*>& removedSeedTracks)
const
150 seedFinderState.tracksToRemove = removedSeedTracks;
155 m_cfg.seedFinder.find(trackVector, seedOptions, seedFinderState);
157 if (!seedResult.ok()) {
158 return seedResult.error();
169 template <
typename vfitter_t,
typename sfinder_t>
172 bool useVertexConstraintInFit,
174 if (useVertexConstraintInFit) {
175 if (not
m_cfg.useSeedConstraint) {
177 seedVertex.setFullCovariance(currentConstraint.fullCovariance());
180 currentConstraint.setFullPosition(seedVertex.fullPosition());
181 currentConstraint.setFullCovariance(seedVertex.fullCovariance());
184 currentConstraint.setFullPosition(seedVertex.fullPosition());
185 currentConstraint.setFullCovariance(SquareMatrix4::Identity() *
186 m_cfg.looseConstrValue);
187 currentConstraint.setFitQuality(
m_cfg.defaultConstrFitQuality);
191 template <
typename vfitter_t,
typename sfinder_t>
202 if (not
m_cfg.useVertexCovForIPEstimation) {
206 auto estRes =
m_cfg.ipEstimator.getImpactParameters(
207 m_extractParameters(*track), newVtx, vertexingOptions.geoContext,
208 vertexingOptions.magFieldContext);
210 return estRes.error();
215 double significance = 0.;
217 significance = std::sqrt(std::pow(ipas.
d0 / ipas.
sigmaD0, 2) +
224 template <
typename vfitter_t,
typename sfinder_t>
227 const std::vector<const InputTrack_t*>&
tracks,
231 for (
const auto& trk :
tracks) {
232 auto params = m_extractParameters(*trk);
233 auto pos = params.position(vertexingOptions.geoContext);
236 if (
m_cfg.tracksMaxZinterval < std::abs(
pos[
eZ] - vtx.position()[
eZ])) {
239 auto sigRes = getIPSignificance(trk, vtx, vertexingOptions);
241 return sigRes.error();
243 double ipSig = *sigRes;
244 if (ipSig <
m_cfg.tracksMaxSignificance) {
246 fitterState.tracksAtVerticesMap.emplace(std::make_pair(trk, &vtx),
250 fitterState.vtxInfoMap[&vtx].trackLinks.push_back(trk);
256 template <
typename vfitter_t,
typename sfinder_t>
259 const std::vector<const InputTrack_t*>& allTracks,
260 const std::vector<const InputTrack_t*>& seedTracks,
270 if (fitterState.vtxInfoMap[&vtx].trackLinks.empty()) {
272 double smallestDeltaZ = std::numeric_limits<double>::max();
274 bool nearTrackFound =
false;
275 for (
const auto& trk : seedTracks) {
277 m_extractParameters(*trk).position(vertexingOptions.geoContext);
278 auto zDistance = std::abs(
pos[
eZ] - vtx.position()[
eZ]);
279 if (zDistance < smallestDeltaZ) {
280 smallestDeltaZ = zDistance;
281 nearTrackFound =
true;
285 if (nearTrackFound) {
286 vtx.setFullPosition(
Vector4(0., 0., newZ, 0.));
289 fitterState.vtxInfoMap[&vtx] =
293 auto res = addCompatibleTracksToVertex(allTracks, vtx, fitterState,
299 if (fitterState.vtxInfoMap[&vtx].trackLinks.empty()) {
301 "No tracks near seed were found, while at least one was "
307 ACTS_DEBUG(
"No nearest track to seed found. Break.");
315 template <
typename vfitter_t,
typename sfinder_t>
318 const std::vector<const InputTrack_t*>& allTracks,
319 const std::vector<const InputTrack_t*>& seedTracks,
326 fitterState.vtxInfoMap[&vtx] =
330 auto resComp = addCompatibleTracksToVertex(allTracks, vtx, fitterState,
337 auto resRec = canRecoverFromNoCompatibleTracks(allTracks, seedTracks, vtx,
338 currentConstraint, fitterState,
347 template <
typename vfitter_t,
typename sfinder_t>
351 const std::vector<const InputTrack_t*>& seedTracks,
352 FitterState_t& fitterState,
bool useVertexConstraintInFit)
const
353 -> std::pair<int, bool> {
354 bool isGoodVertex =
false;
355 int nCompatibleTracks = 0;
356 for (
const auto& trk : fitterState.vtxInfoMap[&vtx].trackLinks) {
357 const auto& trkAtVtx =
358 fitterState.tracksAtVerticesMap.at(std::make_pair(trk, &vtx));
359 if ((trkAtVtx.vertexCompatibility <
m_cfg.maxVertexChi2 &&
360 m_cfg.useFastCompatibility) ||
361 (trkAtVtx.trackWeight >
m_cfg.minWeight &&
362 trkAtVtx.chi2Track <
m_cfg.maxVertexChi2 &&
363 !
m_cfg.useFastCompatibility)) {
367 std::find_if(seedTracks.begin(), seedTracks.end(),
368 [&trk](
auto seedTrk) {
return trk == seedTrk; });
369 if (foundIter != seedTracks.end()) {
373 if (
m_cfg.addSingleTrackVertices && useVertexConstraintInFit) {
377 if (nCompatibleTracks > 1) {
385 return {nCompatibleTracks, isGoodVertex};
388 template <
typename vfitter_t,
typename sfinder_t>
393 std::vector<const InputTrack_t*>& removedSeedTracks)
const ->
void {
394 for (
const auto& trk : fitterState.vtxInfoMap[&vtx].trackLinks) {
395 const auto& trkAtVtx =
396 fitterState.tracksAtVerticesMap.at(std::make_pair(trk, &vtx));
397 if ((trkAtVtx.vertexCompatibility <
m_cfg.maxVertexChi2 &&
398 m_cfg.useFastCompatibility) ||
399 (trkAtVtx.trackWeight >
m_cfg.minWeight &&
400 trkAtVtx.chi2Track <
m_cfg.maxVertexChi2 &&
401 !
m_cfg.useFastCompatibility)) {
404 std::find_if(seedTracks.begin(), seedTracks.end(),
405 [&trk](
auto seedTrk) {
return trk == seedTrk; });
406 if (foundSeedIter != seedTracks.end()) {
407 seedTracks.erase(foundSeedIter);
408 removedSeedTracks.push_back(trk);
414 template <
typename vfitter_t,
typename sfinder_t>
419 std::vector<const InputTrack_t*>& removedSeedTracks,
422 double maxCompatibility = 0;
424 auto maxCompSeedIt = seedTracks.end();
426 for (
const auto& trk : fitterState.vtxInfoMap[&vtx].trackLinks) {
427 const auto& trkAtVtx =
428 fitterState.tracksAtVerticesMap.at(std::make_pair(trk, &vtx));
429 double compatibility = trkAtVtx.vertexCompatibility;
430 if (compatibility > maxCompatibility) {
433 std::find_if(seedTracks.begin(), seedTracks.end(),
434 [&trk](
auto seedTrk) {
return trk == seedTrk; });
435 if (foundSeedIter != seedTracks.end()) {
436 maxCompatibility = compatibility;
437 maxCompSeedIt = foundSeedIter;
442 if (maxCompSeedIt != seedTracks.end()) {
444 seedTracks.erase(maxCompSeedIt);
445 removedSeedTracks.push_back(removedTrack);
450 double smallestDeltaZ = std::numeric_limits<double>::max();
451 auto smallestDzSeedIter = seedTracks.end();
452 for (
unsigned int i = 0;
i < seedTracks.size();
i++) {
453 auto pos = m_extractParameters(*seedTracks[
i]).position(
geoCtx);
454 double zDistance = std::abs(
pos[
eZ] - vtx.position()[
eZ]);
455 if (zDistance < smallestDeltaZ) {
456 smallestDeltaZ = zDistance;
457 smallestDzSeedIter = seedTracks.begin() +
i;
458 removedTrack = seedTracks[
i];
461 if (smallestDzSeedIter != seedTracks.end()) {
462 seedTracks.erase(smallestDzSeedIter);
463 removedSeedTracks.push_back(removedTrack);
465 ACTS_DEBUG(
"No track found to remove. Stop vertex finding now.");
472 template <
typename vfitter_t,
typename sfinder_t>
477 double contamination = 0.;
478 double contaminationNum = 0;
479 double contaminationDeNom = 0;
480 for (
const auto& trk : fitterState.vtxInfoMap[&vtx].trackLinks) {
481 const auto& trkAtVtx =
482 fitterState.tracksAtVerticesMap.at(std::make_pair(trk, &vtx));
483 double trackWeight = trkAtVtx.trackWeight;
484 contaminationNum += trackWeight * (1. - trackWeight);
485 contaminationDeNom += trackWeight * trackWeight;
487 if (contaminationDeNom != 0) {
488 contamination = contaminationNum / contaminationDeNom;
490 if (contamination >
m_cfg.maximumVertexContamination) {
494 if (isMergedVertex(vtx, allVertices)) {
501 template <
typename vfitter_t,
typename sfinder_t>
507 const double candidateZPos = candidatePos[
eZ];
508 const double candidateZCov = candidateCov(
eZ,
eZ);
510 for (
const auto otherVtx : allVertices) {
511 if (&vtx == otherVtx) {
514 const Vector4& otherPos = otherVtx->fullPosition();
516 const double otherZPos = otherPos[
eZ];
517 const double otherZCov = otherCov(
eZ,
eZ);
519 const Vector4 deltaPos = otherPos - candidatePos;
520 const double deltaZPos = otherZPos - candidateZPos;
521 const double sumCovZ = otherZCov + candidateZCov;
523 double significance = 0;
524 if (not
m_cfg.do3dSplitting) {
530 significance = std::abs(deltaZPos) / std::sqrt(sumCovZ);
535 if (!sumCovInverse) {
539 significance = std::sqrt(deltaPos.dot(*sumCovInverse * deltaPos));
541 if (significance <
m_cfg.maxMergeVertexSignificance) {
548 template <
typename vfitter_t,
typename sfinder_t>
556 allVertices.pop_back();
557 allVerticesPtr.pop_back();
560 fitterState.removeVertexFromMultiMap(vtx);
562 for (
auto&
entry : fitterState.tracksAtVerticesMap) {
564 if (
entry.first.second == &vtx) {
565 entry.second.isLinearized =
false;
570 auto fitResult =
m_cfg.vertexFitter.addVtxToFit(
571 fitterState, vtx,
m_cfg.linearizer, vertexingOptions);
572 if (!fitResult.ok()) {
573 return fitResult.error();
579 template <
typename vfitter_t,
typename sfinder_t>
584 std::vector<Vertex<InputTrack_t>> outputVec;
585 for (
auto vtx : allVerticesPtr) {
587 std::vector<TrackAtVertex<InputTrack_t>> tracksAtVtx;
588 for (
const auto& trk : fitterState.vtxInfoMap[vtx].trackLinks) {
589 tracksAtVtx.push_back(
590 fitterState.tracksAtVerticesMap.at(std::make_pair(trk, vtx)));
592 outVtx.setTracksAtVertex(tracksAtVtx);
593 outputVec.push_back(outVtx);