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;
27 std::vector<std::unique_ptr<Vertex<InputTrack_t>>> allVertices;
29 std::vector<Vertex<InputTrack_t>*> allVerticesPtr;
32 while (((m_cfg.addSingleTrackVertices && seedTracks.size() > 0) ||
33 ((!m_cfg.addSingleTrackVertices) && seedTracks.size() > 1)) &&
34 iteration < m_cfg.maxIterations) {
39 std::vector<const InputTrack_t*> allTracks;
40 if (m_cfg.doRealMultiVertex) {
41 allTracks = origTracks;
43 allTracks = seedTracks;
48 doSeeding(seedTracks, currentConstraint, vertexingOptions);
49 if (!seedResult.ok()) {
50 return seedResult.error();
55 allVerticesPtr.push_back(&vtxCandidate);
57 ACTS_DEBUG(
"Position of current vertex candidate after seeding: "
59 if (vtxCandidate.
position().z() == 0.) {
61 "No seed found anymore. Break and stop primary vertex finding.");
62 allVertices.pop_back();
63 allVerticesPtr.pop_back();
66 auto prepResult = canPrepareVertexForFit(allTracks, seedTracks,
67 vtxCandidate, currentConstraint,
68 fitterState, vertexingOptions);
70 if (!prepResult.ok()) {
71 return prepResult.error();
74 ACTS_DEBUG(
"Could not prepare for fit anymore. Break.");
75 allVertices.pop_back();
76 allVerticesPtr.pop_back();
80 fitterState.addVertexToMultiMap(vtxCandidate);
83 auto fitResult = m_cfg.vertexFitter.addVtxToFit(
84 fitterState, vtxCandidate, m_cfg.linearizer, vertexingOptions);
85 if (!fitResult.ok()) {
86 return fitResult.error();
88 ACTS_DEBUG(
"New position of current vertex candidate after fit: "
91 auto [nCompatibleTracks, isGoodVertex] =
92 checkVertexAndCompatibleTracks(vtxCandidate, seedTracks, fitterState);
94 ACTS_DEBUG(
"Vertex is good vertex: " << isGoodVertex);
95 if (nCompatibleTracks > 0) {
96 removeCompatibleTracksFromSeedTracks(vtxCandidate, seedTracks,
99 bool removedNonCompatibleTrack =
100 canRemoveNonCompatibleTrackFromSeedTracks(vtxCandidate, seedTracks,
102 if (!removedNonCompatibleTrack) {
104 "Could not remove any further track from seed tracks. Break.");
105 allVertices.pop_back();
106 allVerticesPtr.pop_back();
110 bool keepVertex = isGoodVertex &&
111 keepNewVertex(vtxCandidate, allVerticesPtr, fitterState);
112 ACTS_DEBUG(
"New vertex will be saved: " << keepVertex);
115 if (not keepVertex) {
116 auto deleteVertexResult =
117 deleteLastVertex(vtxCandidate, allVertices, allVerticesPtr,
118 fitterState, oldFitterState, vertexingOptions);
119 if (not deleteVertexResult.ok()) {
120 return deleteVertexResult.error();
126 return getVertexOutputList(allVerticesPtr, fitterState);
129 template <
typename vfitter_t,
typename sfinder_t>
131 const std::vector<const InputTrack_t*>& trackVector,
138 auto seedResult = m_cfg.seedFinder.find(trackVector, seedOptions);
140 if (!seedResult.ok()) {
141 return seedResult.error();
146 if (m_cfg.useBeamSpotConstraint) {
147 if (currentConstraint.fullCovariance() == SpacePointSymMatrix::Zero()) {
149 "No constraint provided, but useBeamSpotConstraint set to true.");
151 if (m_cfg.useSeedConstraint) {
152 currentConstraint.setFullPosition(seedVertex.
fullPosition());
156 currentConstraint.setFullPosition(seedVertex.
fullPosition());
157 currentConstraint.setFullCovariance(SpacePointSymMatrix::Identity() *
158 m_cfg.looseConstrValue);
159 currentConstraint.setFitQuality(m_cfg.defaultConstrFitQuality);
165 template <
typename vfitter_t,
typename sfinder_t>
173 double X = trackPos[
eX] - vtxPos.x();
174 double Y = trackPos[
eY] - vtxPos.y();
176 double deltaZ = trackPos[
eZ] - vtxPos.z() -
177 1. / std::tan(th) * (X * std::cos(phi) + Y * std::sin(phi));
182 template <
typename vfitter_t,
typename sfinder_t>
193 if (not m_cfg.useVertexCovForIPEstimation) {
197 auto estRes = m_cfg.ipEstimator.estimateImpactParameters(
198 m_extractParameters(*
track), newVtx, vertexingOptions.geoContext,
199 vertexingOptions.magFieldContext);
201 return estRes.error();
206 double significance = 0.;
208 significance = std::sqrt(std::pow(ipas.
IPd0 / ipas.
sigmad0, 2) +
215 template <
typename vfitter_t,
typename sfinder_t>
218 const std::vector<const InputTrack_t*>& tracks,
222 for (
const auto& trk : tracks) {
223 auto sigRes = getIPSignificance(trk, vtx, vertexingOptions);
225 return sigRes.error();
227 double ipSig = *sigRes;
228 auto params = m_extractParameters(*trk);
229 if ((
std::abs(estimateDeltaZ(params, vtx.position())) <
230 m_cfg.tracksMaxZinterval) &&
231 (ipSig < m_cfg.tracksMaxSignificance)) {
234 fitterState.tracksAtVerticesMap.emplace(std::make_pair(trk, &vtx),
238 fitterState.vtxInfoMap[&vtx].trackLinks.push_back(trk);
244 template <
typename vfitter_t,
typename sfinder_t>
247 const std::vector<const InputTrack_t*>& allTracks,
248 const std::vector<const InputTrack_t*>& seedTracks,
258 if (fitterState.vtxInfoMap[&vtx].trackLinks.empty()) {
262 bool nearTrackFound =
false;
263 for (
const auto& trk : seedTracks) {
264 double zDistance =
std::abs(m_extractParameters(*trk).position()[
eZ] -
266 if (zDistance < smallestDeltaZ) {
267 smallestDeltaZ = zDistance;
268 nearTrackFound =
true;
270 newZ = m_extractParameters(*trk).position()[
eZ];
273 if (nearTrackFound) {
277 fitterState.vtxInfoMap[&vtx] =
281 auto res = addCompatibleTracksToVertex(allTracks, vtx, fitterState,
287 if (fitterState.vtxInfoMap[&vtx].trackLinks.empty()) {
289 "No tracks near seed were found, while at least one was "
295 ACTS_DEBUG(
"No nearest track to seed found. Break.");
303 template <
typename vfitter_t,
typename sfinder_t>
306 const std::vector<const InputTrack_t*>& allTracks,
307 const std::vector<const InputTrack_t*>& seedTracks,
314 fitterState.vtxInfoMap[&vtx] =
318 auto resComp = addCompatibleTracksToVertex(allTracks, vtx, fitterState,
325 auto resRec = canRecoverFromNoCompatibleTracks(allTracks, seedTracks, vtx,
326 currentConstraint, fitterState,
335 template <
typename vfitter_t,
typename sfinder_t>
339 const std::vector<const InputTrack_t*>& seedTracks,
341 bool isGoodVertex =
false;
342 int nCompatibleTracks = 0;
343 for (
const auto& trk : fitterState.vtxInfoMap[&vtx].trackLinks) {
344 const auto& trkAtVtx =
345 fitterState.tracksAtVerticesMap.at(std::make_pair(trk, &vtx));
346 if ((trkAtVtx.vertexCompatibility < m_cfg.maxVertexChi2 &&
347 m_cfg.useFastCompatibility) ||
348 (trkAtVtx.trackWeight > m_cfg.minWeight &&
349 trkAtVtx.chi2Track < m_cfg.maxVertexChi2 &&
350 !m_cfg.useFastCompatibility)) {
354 std::find_if(seedTracks.begin(), seedTracks.end(),
355 [&trk,
this](
auto seedTrk) {
return trk == seedTrk; });
356 if (foundIter != seedTracks.end()) {
360 if (m_cfg.addSingleTrackVertices && m_cfg.useBeamSpotConstraint) {
364 if (nCompatibleTracks > 1) {
372 return {nCompatibleTracks, isGoodVertex};
375 template <
typename vfitter_t,
typename sfinder_t>
380 for (
const auto& trk : fitterState.vtxInfoMap[&vtx].trackLinks) {
381 const auto& trkAtVtx =
382 fitterState.tracksAtVerticesMap.at(std::make_pair(trk, &vtx));
383 if ((trkAtVtx.vertexCompatibility < m_cfg.maxVertexChi2 &&
384 m_cfg.useFastCompatibility) ||
385 (trkAtVtx.trackWeight > m_cfg.minWeight &&
386 trkAtVtx.chi2Track < m_cfg.maxVertexChi2 &&
387 !m_cfg.useFastCompatibility)) {
390 std::find_if(seedTracks.begin(), seedTracks.end(),
391 [&trk,
this](
auto seedTrk) {
return trk == seedTrk; });
392 if (foundSeedIter != seedTracks.end()) {
393 seedTracks.erase(foundSeedIter);
399 template <
typename vfitter_t,
typename sfinder_t>
405 double maxCompatibility = 0;
407 auto maxCompSeedIt = seedTracks.end();
408 for (
const auto& trk : fitterState.vtxInfoMap[&vtx].trackLinks) {
409 const auto& trkAtVtx =
410 fitterState.tracksAtVerticesMap.at(std::make_pair(trk, &vtx));
411 double compatibility = trkAtVtx.vertexCompatibility;
412 if (compatibility > maxCompatibility) {
415 std::find_if(seedTracks.begin(), seedTracks.end(),
416 [&trk,
this](
auto seedTrk) {
return trk == seedTrk; });
417 if (foundSeedIter != seedTracks.end()) {
418 maxCompatibility = compatibility;
419 maxCompSeedIt = foundSeedIter;
423 if (maxCompSeedIt != seedTracks.end()) {
425 seedTracks.erase(maxCompSeedIt);
431 auto smallestDzSeedIter = seedTracks.end();
432 for (
auto trkIter = seedTracks.begin(); trkIter != seedTracks.end();
435 m_extractParameters(**trkIter).position()[
eZ] - vtx.position()[
eZ]);
436 if (zDistance < smallestDeltaZ) {
437 smallestDeltaZ = zDistance;
438 smallestDzSeedIter = trkIter;
441 if (smallestDzSeedIter != seedTracks.end()) {
442 seedTracks.erase(smallestDzSeedIter);
444 ACTS_DEBUG(
"No track found to remove. Stop vertex finding now.");
451 template <
typename vfitter_t,
typename sfinder_t>
456 double contamination = 0.;
457 double contaminationNum = 0;
458 double contaminationDeNom = 0;
459 for (
const auto& trk : fitterState.vtxInfoMap[&vtx].trackLinks) {
460 const auto& trkAtVtx =
461 fitterState.tracksAtVerticesMap.at(std::make_pair(trk, &vtx));
462 double trackWeight = trkAtVtx.trackWeight;
463 contaminationNum += trackWeight * (1. - trackWeight);
464 contaminationDeNom += trackWeight * trackWeight;
466 if (contaminationDeNom != 0) {
467 contamination = contaminationNum / contaminationDeNom;
469 if (contamination > m_cfg.maximumVertexContamination) {
473 if (isMergedVertex(vtx, allVertices)) {
480 template <
typename vfitter_t,
typename sfinder_t>
486 const double candidateZPos = candidatePos[
eZ];
487 const double candidateZCov = candidateCov(
eZ,
eZ);
489 for (
const auto otherVtx : allVertices) {
490 if (&vtx == otherVtx) {
495 const double otherZPos = otherPos[
eZ];
496 const double otherZCov = otherCov(
eZ,
eZ);
498 const auto deltaPos = otherPos - candidatePos;
499 const auto deltaZPos = otherZPos - candidateZPos;
500 const auto sumCovZ = otherZCov + candidateZCov;
503 if (not m_cfg.do3dSplitting) {
506 significance =
std::abs(deltaZPos) / std::sqrt(sumCovZ);
512 auto sumCov = candidateCov + otherCov;
514 std::sqrt(deltaPos.dot((sumCov.inverse().eval()) * deltaPos));
516 if (significance < m_cfg.maxMergeVertexSignificance) {
523 template <
typename vfitter_t,
typename sfinder_t>
531 allVertices.pop_back();
532 allVerticesPtr.pop_back();
534 if (!m_cfg.refitAfterBadVertex) {
535 fitterState.vertexCollection = oldFitterState.vertexCollection;
536 fitterState.annealingState = oldFitterState.annealingState;
537 fitterState.vtxInfoMap.clear();
538 for (
const auto& vtx : allVerticesPtr) {
539 fitterState.vtxInfoMap.emplace(vtx, oldFitterState.vtxInfoMap[vtx]);
541 fitterState.trackToVerticesMultiMap =
542 oldFitterState.trackToVerticesMultiMap;
543 fitterState.tracksAtVerticesMap = oldFitterState.tracksAtVerticesMap;
547 fitterState.removeVertexFromMultiMap(vtx);
553 auto fitResult = m_cfg.vertexFitter.fit(fitterState, allVerticesPtr,
554 m_cfg.linearizer, vertexingOptions);
555 if (!fitResult.ok()) {
556 return fitResult.error();
562 template <
typename vfitter_t,
typename sfinder_t>
565 FitterState_t& fitterState)
const -> std::vector<Vertex<InputTrack_t>> {
566 std::vector<Vertex<InputTrack_t>> outputVec;
567 for (
auto vtx : allVerticesPtr) {
569 std::vector<TrackAtVertex<InputTrack_t>> tracksAtVtx;
570 for (
const auto& trk : fitterState.vtxInfoMap[vtx].trackLinks) {
571 tracksAtVtx.push_back(
572 fitterState.tracksAtVerticesMap.at(std::make_pair(trk, vtx)));
574 outVtx.setTracksAtVertex(tracksAtVtx);
575 outputVec.push_back(outVtx);