11 template <
typename vfitter_t,
typename sfinder_t>
13 const std::vector<const InputTrack_t*>& allTracks,
16 if (allTracks.empty()) {
17 return VertexingError::EmptyInput;
20 const std::vector<const InputTrack_t*>& origTracks = allTracks;
23 std::vector<const InputTrack_t*> seedTracks = allTracks;
28 std::vector<std::unique_ptr<Vertex<InputTrack_t>>> allVertices;
30 std::vector<Vertex<InputTrack_t>*> allVerticesPtr;
33 std::vector<const InputTrack_t*> removedSeedTracks;
34 while (((m_cfg.addSingleTrackVertices && seedTracks.size() > 0) ||
35 ((!m_cfg.addSingleTrackVertices) && seedTracks.size() > 1)) &&
36 iteration < m_cfg.maxIterations) {
39 std::vector<const InputTrack_t*> searchTracks;
40 if (m_cfg.doRealMultiVertex) {
41 searchTracks = origTracks;
43 searchTracks = seedTracks;
47 auto seedResult = doSeeding(seedTracks, currentConstraint, vertexingOptions,
48 seedFinderState, removedSeedTracks);
49 if (!seedResult.ok()) {
50 return seedResult.error();
55 allVerticesPtr.push_back(&vtxCandidate);
57 ACTS_DEBUG(
"Position of current vertex candidate after seeding: "
62 "No seed found anymore. Break and stop primary vertex finding.");
63 allVertices.pop_back();
64 allVerticesPtr.pop_back();
70 removedSeedTracks.clear();
72 auto prepResult = canPrepareVertexForFit(searchTracks, seedTracks,
73 vtxCandidate, currentConstraint,
74 fitterState, vertexingOptions);
76 if (!prepResult.ok()) {
77 return prepResult.error();
80 ACTS_DEBUG(
"Could not prepare for fit anymore. Break.");
81 allVertices.pop_back();
82 allVerticesPtr.pop_back();
86 fitterState.addVertexToMultiMap(vtxCandidate);
89 auto fitResult = m_cfg.vertexFitter.addVtxToFit(
90 fitterState, vtxCandidate, m_cfg.linearizer, vertexingOptions);
91 if (!fitResult.ok()) {
92 return fitResult.error();
94 ACTS_DEBUG(
"New position of current vertex candidate after fit: "
97 auto [nCompatibleTracks, isGoodVertex] =
98 checkVertexAndCompatibleTracks(vtxCandidate, seedTracks, fitterState);
100 ACTS_DEBUG(
"Vertex is good vertex: " << isGoodVertex);
101 if (nCompatibleTracks > 0) {
102 removeCompatibleTracksFromSeedTracks(vtxCandidate, seedTracks,
103 fitterState, removedSeedTracks);
105 bool removedIncompatibleTrack = removeTrackIfIncompatible(
106 vtxCandidate, seedTracks, fitterState, removedSeedTracks,
108 if (!removedIncompatibleTrack) {
110 "Could not remove any further track from seed tracks. Break.");
111 allVertices.pop_back();
112 allVerticesPtr.pop_back();
116 bool keepVertex = isGoodVertex &&
117 keepNewVertex(vtxCandidate, allVerticesPtr, fitterState);
118 ACTS_DEBUG(
"New vertex will be saved: " << keepVertex);
121 if (not keepVertex) {
122 auto deleteVertexResult =
123 deleteLastVertex(vtxCandidate, allVertices, allVerticesPtr,
124 fitterState, vertexingOptions);
125 if (not deleteVertexResult.ok()) {
126 return deleteVertexResult.error();
132 return getVertexOutputList(allVerticesPtr, fitterState);
135 template <
typename vfitter_t,
typename sfinder_t>
137 const std::vector<const InputTrack_t*>& trackVector,
141 const std::vector<const InputTrack_t*>& removedSeedTracks)
const
147 seedFinderState.tracksToRemove = removedSeedTracks;
152 m_cfg.seedFinder.find(trackVector, seedOptions, seedFinderState);
154 if (!seedResult.ok()) {
155 return seedResult.error();
160 setConstraintAfterSeeding(currentConstraint, seedVertex);
165 template <
typename vfitter_t,
typename sfinder_t>
170 if (m_cfg.useBeamSpotConstraint) {
171 if (currentConstraint.fullCovariance() == SymMatrix4D::Zero()) {
173 "No constraint provided, but useBeamSpotConstraint set to true.");
175 if (m_cfg.useSeedConstraint) {
176 currentConstraint.setFullPosition(seedVertex.fullPosition());
177 currentConstraint.setFullCovariance(seedVertex.fullCovariance());
180 currentConstraint.setFullPosition(seedVertex.fullPosition());
181 currentConstraint.setFullCovariance(SymMatrix4D::Identity() *
182 m_cfg.looseConstrValue);
183 currentConstraint.setFitQuality(m_cfg.defaultConstrFitQuality);
187 template <
typename vfitter_t,
typename sfinder_t>
198 if (not m_cfg.useVertexCovForIPEstimation) {
202 auto estRes = m_cfg.ipEstimator.estimateImpactParameters(
203 m_extractParameters(*track), newVtx, vertexingOptions.geoContext,
204 vertexingOptions.magFieldContext);
206 return estRes.error();
211 double significance = 0.;
213 significance = std::sqrt(std::pow(ipas.
IPd0 / ipas.
sigmad0, 2) +
220 template <
typename vfitter_t,
typename sfinder_t>
223 const std::vector<const InputTrack_t*>& tracks,
227 for (
const auto& trk : tracks) {
228 auto params = m_extractParameters(*trk);
229 auto pos = params.position(vertexingOptions.geoContext);
235 auto sigRes = getIPSignificance(trk,
vtx, vertexingOptions);
237 return sigRes.error();
239 double ipSig = *sigRes;
240 if (ipSig < m_cfg.tracksMaxSignificance) {
242 fitterState.tracksAtVerticesMap.emplace(std::make_pair(trk, &
vtx),
246 fitterState.vtxInfoMap[&
vtx].trackLinks.push_back(trk);
252 template <
typename vfitter_t,
typename sfinder_t>
255 const std::vector<const InputTrack_t*>& allTracks,
256 const std::vector<const InputTrack_t*>& seedTracks,
266 if (fitterState.vtxInfoMap[&
vtx].trackLinks.empty()) {
270 bool nearTrackFound =
false;
271 for (
const auto& trk : seedTracks) {
273 m_extractParameters(*trk).position(vertexingOptions.geoContext);
275 if (zDistance < smallestDeltaZ) {
276 smallestDeltaZ = zDistance;
277 nearTrackFound =
true;
281 if (nearTrackFound) {
285 fitterState.vtxInfoMap[&
vtx] =
289 auto res = addCompatibleTracksToVertex(allTracks,
vtx, fitterState,
295 if (fitterState.vtxInfoMap[&
vtx].trackLinks.empty()) {
297 "No tracks near seed were found, while at least one was "
303 ACTS_DEBUG(
"No nearest track to seed found. Break.");
311 template <
typename vfitter_t,
typename sfinder_t>
314 const std::vector<const InputTrack_t*>& allTracks,
315 const std::vector<const InputTrack_t*>& seedTracks,
322 fitterState.vtxInfoMap[&
vtx] =
326 auto resComp = addCompatibleTracksToVertex(allTracks,
vtx, fitterState,
333 auto resRec = canRecoverFromNoCompatibleTracks(allTracks, seedTracks,
vtx,
334 currentConstraint, fitterState,
343 template <
typename vfitter_t,
typename sfinder_t>
347 const std::vector<const InputTrack_t*>& seedTracks,
349 bool isGoodVertex =
false;
350 int nCompatibleTracks = 0;
351 for (
const auto& trk : fitterState.vtxInfoMap[&
vtx].trackLinks) {
352 const auto& trkAtVtx =
353 fitterState.tracksAtVerticesMap.at(std::make_pair(trk, &vtx));
354 if ((trkAtVtx.vertexCompatibility < m_cfg.maxVertexChi2 &&
355 m_cfg.useFastCompatibility) ||
356 (trkAtVtx.trackWeight > m_cfg.minWeight &&
357 trkAtVtx.chi2Track < m_cfg.maxVertexChi2 &&
358 !m_cfg.useFastCompatibility)) {
362 std::find_if(seedTracks.begin(), seedTracks.end(),
363 [&trk](
auto seedTrk) {
return trk == seedTrk; });
364 if (foundIter != seedTracks.end()) {
368 if (m_cfg.addSingleTrackVertices && m_cfg.useBeamSpotConstraint) {
372 if (nCompatibleTracks > 1) {
380 return {nCompatibleTracks, isGoodVertex};
383 template <
typename vfitter_t,
typename sfinder_t>
388 std::vector<const InputTrack_t*>& removedSeedTracks)
const ->
void {
389 for (
const auto& trk : fitterState.vtxInfoMap[&
vtx].trackLinks) {
390 const auto& trkAtVtx =
391 fitterState.tracksAtVerticesMap.at(std::make_pair(trk, &vtx));
392 if ((trkAtVtx.vertexCompatibility < m_cfg.maxVertexChi2 &&
393 m_cfg.useFastCompatibility) ||
394 (trkAtVtx.trackWeight > m_cfg.minWeight &&
395 trkAtVtx.chi2Track < m_cfg.maxVertexChi2 &&
396 !m_cfg.useFastCompatibility)) {
399 std::find_if(seedTracks.begin(), seedTracks.end(),
400 [&trk](
auto seedTrk) {
return trk == seedTrk; });
401 if (foundSeedIter != seedTracks.end()) {
402 seedTracks.erase(foundSeedIter);
403 removedSeedTracks.push_back(trk);
409 template <
typename vfitter_t,
typename sfinder_t>
414 std::vector<const InputTrack_t*>& removedSeedTracks,
417 double maxCompatibility = 0;
419 auto maxCompSeedIt = seedTracks.end();
421 for (
const auto& trk : fitterState.vtxInfoMap[&
vtx].trackLinks) {
422 const auto& trkAtVtx =
423 fitterState.tracksAtVerticesMap.at(std::make_pair(trk, &vtx));
424 double compatibility = trkAtVtx.vertexCompatibility;
425 if (compatibility > maxCompatibility) {
428 std::find_if(seedTracks.begin(), seedTracks.end(),
429 [&trk](
auto seedTrk) {
return trk == seedTrk; });
430 if (foundSeedIter != seedTracks.end()) {
431 maxCompatibility = compatibility;
432 maxCompSeedIt = foundSeedIter;
437 if (maxCompSeedIt != seedTracks.end()) {
439 seedTracks.erase(maxCompSeedIt);
440 removedSeedTracks.push_back(removedTrack);
446 auto smallestDzSeedIter = seedTracks.end();
447 for (
unsigned int i = 0; i < seedTracks.size(); i++) {
448 auto pos = m_extractParameters(*seedTracks[i]).position(
geoCtx);
450 if (zDistance < smallestDeltaZ) {
451 smallestDeltaZ = zDistance;
452 smallestDzSeedIter = seedTracks.begin() + i;
453 removedTrack = seedTracks[i];
456 if (smallestDzSeedIter != seedTracks.end()) {
457 seedTracks.erase(smallestDzSeedIter);
458 removedSeedTracks.push_back(removedTrack);
460 ACTS_DEBUG(
"No track found to remove. Stop vertex finding now.");
467 template <
typename vfitter_t,
typename sfinder_t>
472 double contamination = 0.;
473 double contaminationNum = 0;
474 double contaminationDeNom = 0;
475 for (
const auto& trk : fitterState.vtxInfoMap[&
vtx].trackLinks) {
476 const auto& trkAtVtx =
477 fitterState.tracksAtVerticesMap.at(std::make_pair(trk, &vtx));
478 double trackWeight = trkAtVtx.trackWeight;
479 contaminationNum += trackWeight * (1. - trackWeight);
480 contaminationDeNom += trackWeight * trackWeight;
482 if (contaminationDeNom != 0) {
483 contamination = contaminationNum / contaminationDeNom;
485 if (contamination > m_cfg.maximumVertexContamination) {
489 if (isMergedVertex(vtx, allVertices)) {
496 template <
typename vfitter_t,
typename sfinder_t>
502 const double candidateZPos = candidatePos[
eZ];
503 const double candidateZCov = candidateCov(
eZ,
eZ);
505 for (
const auto otherVtx : allVertices) {
506 if (&vtx == otherVtx) {
509 const Vector4D& otherPos = otherVtx->fullPosition();
510 const SymMatrix4D& otherCov = otherVtx->fullCovariance();
511 const double otherZPos = otherPos[
eZ];
512 const double otherZCov = otherCov(
eZ,
eZ);
514 const Vector4D deltaPos = otherPos - candidatePos;
515 const double deltaZPos = otherZPos - candidateZPos;
516 const double sumCovZ = otherZCov + candidateZCov;
519 if (not m_cfg.do3dSplitting) {
522 significance =
std::abs(deltaZPos) / std::sqrt(sumCovZ);
530 std::sqrt(deltaPos.dot((sumCov.inverse().eval()) * deltaPos));
532 if (significance < m_cfg.maxMergeVertexSignificance) {
539 template <
typename vfitter_t,
typename sfinder_t>
547 allVertices.pop_back();
548 allVerticesPtr.pop_back();
551 fitterState.removeVertexFromMultiMap(
vtx);
554 auto fitResult = m_cfg.vertexFitter.addVtxToFit(
555 fitterState,
vtx, m_cfg.linearizer, vertexingOptions);
556 if (!fitResult.ok()) {
557 return fitResult.error();
563 template <
typename vfitter_t,
typename sfinder_t>
568 std::vector<Vertex<InputTrack_t>> outputVec;
569 for (
auto vtx : allVerticesPtr) {
571 std::vector<TrackAtVertex<InputTrack_t>> tracksAtVtx;
572 for (
const auto& trk : fitterState.vtxInfoMap[
vtx].trackLinks) {
573 tracksAtVtx.push_back(
574 fitterState.tracksAtVerticesMap.at(std::make_pair(trk, vtx)));
576 outVtx.setTracksAtVertex(tracksAtVtx);
577 outputVec.push_back(outVtx);