File indexing completed on 2025-12-06 08:56:43
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "Acts/Vertexing/AdaptiveMultiVertexFinder.hpp"
0010
0011 #include "Acts/Utilities/AlgebraHelpers.hpp"
0012 #include "Acts/Vertexing/IVertexFinder.hpp"
0013 #include "Acts/Vertexing/VertexingError.hpp"
0014
0015 #include <algorithm>
0016
0017 namespace Acts {
0018
0019 Result<std::vector<Vertex>> AdaptiveMultiVertexFinder::find(
0020 const std::vector<InputTrack>& allTracks,
0021 const VertexingOptions& vertexingOptions,
0022 IVertexFinder::State& anyState) const {
0023 if (allTracks.empty()) {
0024 ACTS_ERROR("Empty track collection handed to find method");
0025 return VertexingError::EmptyInput;
0026 }
0027
0028 State& state = anyState.template as<State>();
0029 IVertexFinder::State& seedFinderState = state.seedFinderState;
0030 VertexFitterState fitterState(*m_cfg.bField,
0031 vertexingOptions.magFieldContext);
0032
0033 const std::vector<InputTrack>& origTracks = allTracks;
0034 std::vector<InputTrack> seedTracks = allTracks;
0035 std::vector<std::unique_ptr<Vertex>> allVertices;
0036 std::vector<Vertex*> allVerticesPtr;
0037 std::vector<Vertex*> newVerticesPtr;
0038
0039 int iteration = 0;
0040 std::vector<InputTrack> removedSeedTracks;
0041 while (!seedTracks.empty() && iteration < m_cfg.maxIterations &&
0042 (m_cfg.addSingleTrackVertices || seedTracks.size() >= 2)) {
0043 Vertex currentConstraint = vertexingOptions.constraint;
0044
0045
0046 auto seedResult = doSeeding(seedTracks, currentConstraint, vertexingOptions,
0047 seedFinderState, removedSeedTracks);
0048 if (!seedResult.ok()) {
0049 return seedResult.error();
0050 }
0051 auto& seedVector = *seedResult;
0052
0053 if (seedVector.empty()) {
0054 ACTS_DEBUG(
0055 "No seed found anymore. Break and stop primary vertex finding.");
0056 break;
0057 }
0058
0059 newVerticesPtr.clear();
0060 for (const auto& seedVertex : seedVector) {
0061 allVertices.push_back(std::make_unique<Vertex>(seedVertex));
0062 allVerticesPtr.push_back(allVertices.back().get());
0063 newVerticesPtr.push_back(allVertices.back().get());
0064 }
0065
0066
0067
0068 removedSeedTracks.clear();
0069
0070
0071
0072 std::vector<InputTrack> searchTracks;
0073 if (m_cfg.doRealMultiVertex) {
0074 searchTracks = origTracks;
0075 } else {
0076 searchTracks = seedTracks;
0077 }
0078
0079 bool preparationFailed = false;
0080 for (Vertex* vtxPtr : newVerticesPtr) {
0081 auto prepResult = canPrepareVertexForFit(searchTracks, seedTracks,
0082 *vtxPtr, currentConstraint,
0083 fitterState, vertexingOptions);
0084 if (!prepResult.ok()) {
0085 return prepResult.error();
0086 }
0087 if (!(*prepResult)) {
0088 preparationFailed = true;
0089 break;
0090 }
0091
0092 fitterState.addVertexToMultiMap(*vtxPtr);
0093 }
0094 if (preparationFailed) {
0095 ACTS_DEBUG("Could not prepare for fit. Discarding the vertex candidate.");
0096 allVertices.erase(allVertices.end() - newVerticesPtr.size(),
0097 allVertices.end());
0098 allVerticesPtr.erase(allVerticesPtr.end() - newVerticesPtr.size(),
0099 allVerticesPtr.end());
0100 if (m_cfg.doNotBreakWhileSeeding) {
0101 continue;
0102 } else {
0103 break;
0104 }
0105 }
0106
0107
0108 auto fitResult = m_cfg.vertexFitter.addVtxToFit(fitterState, newVerticesPtr,
0109 vertexingOptions);
0110 if (!fitResult.ok()) {
0111 return fitResult.error();
0112 }
0113
0114 for (Vertex* newVertexPtr : newVerticesPtr) {
0115 Vertex& vtxCandidate = *newVertexPtr;
0116
0117 ACTS_DEBUG("Position of vertex candidate after the fit: "
0118 << vtxCandidate.fullPosition().transpose());
0119
0120 auto [nCompatibleTracks, isGoodVertex] =
0121 checkVertexAndCompatibleTracks(vtxCandidate, seedTracks, fitterState,
0122 vertexingOptions.useConstraintInFit);
0123
0124 ACTS_DEBUG("Vertex is good vertex: " << isGoodVertex);
0125 if (nCompatibleTracks > 0) {
0126 removeCompatibleTracksFromSeedTracks(vtxCandidate, seedTracks,
0127 fitterState, removedSeedTracks);
0128 } else {
0129 auto removedIncompatibleTrack = removeTrackIfIncompatible(
0130 vtxCandidate, seedTracks, fitterState, removedSeedTracks,
0131 vertexingOptions.geoContext);
0132 if (!removedIncompatibleTrack.ok()) {
0133 return removedIncompatibleTrack.error();
0134 }
0135 }
0136 auto keepNewVertexResult =
0137 keepNewVertex(vtxCandidate, allVerticesPtr, fitterState);
0138 if (!keepNewVertexResult.ok()) {
0139 return keepNewVertexResult.error();
0140 }
0141 bool keepVertex = isGoodVertex && *keepNewVertexResult;
0142 ACTS_DEBUG("New vertex will be saved: " << keepVertex);
0143
0144
0145 if (!keepVertex) {
0146 auto deleteVertexResult =
0147 deleteLastVertex(vtxCandidate, allVertices, allVerticesPtr,
0148 fitterState, vertexingOptions);
0149 if (!deleteVertexResult.ok()) {
0150 return deleteVertexResult.error();
0151 }
0152 }
0153 }
0154
0155 iteration++;
0156 }
0157
0158 return getVertexOutputList(allVerticesPtr, fitterState);
0159 }
0160
0161 Result<std::vector<Vertex>> AdaptiveMultiVertexFinder::doSeeding(
0162 const std::vector<InputTrack>& trackVector, Vertex& currentConstraint,
0163 const VertexingOptions& vertexingOptions,
0164 IVertexFinder::State& seedFinderState,
0165 const std::vector<InputTrack>& removedSeedTracks) const {
0166 VertexingOptions seedOptions = vertexingOptions;
0167 seedOptions.constraint = currentConstraint;
0168
0169 m_cfg.seedFinder->setTracksToRemove(seedFinderState, removedSeedTracks);
0170
0171
0172 auto seedResult =
0173 m_cfg.seedFinder->find(trackVector, seedOptions, seedFinderState);
0174
0175 if (!seedResult.ok()) {
0176 return seedResult.error();
0177 }
0178 auto& seedVector = *seedResult;
0179
0180 ACTS_DEBUG("Found " << seedVector.size() << " seeds");
0181
0182 for (auto& seedVertex : seedVector) {
0183
0184 setConstraintAfterSeeding(currentConstraint, seedOptions.useConstraintInFit,
0185 seedVertex);
0186 }
0187
0188 return std::move(seedVector);
0189 }
0190
0191 void AdaptiveMultiVertexFinder::setConstraintAfterSeeding(
0192 Vertex& currentConstraint, bool useVertexConstraintInFit,
0193 Vertex& seedVertex) const {
0194 if (useVertexConstraintInFit) {
0195 if (!m_cfg.useSeedConstraint) {
0196
0197 seedVertex.setFullCovariance(currentConstraint.fullCovariance());
0198 } else {
0199
0200 currentConstraint.setFullPosition(seedVertex.fullPosition());
0201 currentConstraint.setFullCovariance(seedVertex.fullCovariance());
0202 }
0203 } else {
0204 currentConstraint.setFullPosition(seedVertex.fullPosition());
0205 currentConstraint.setFullCovariance(m_cfg.initialVariances.asDiagonal());
0206 currentConstraint.setFitQuality(m_cfg.defaultConstrFitQuality);
0207 }
0208 }
0209
0210 Result<double> AdaptiveMultiVertexFinder::getIPSignificance(
0211 const InputTrack& track, const Vertex& vtx,
0212 const VertexingOptions& vertexingOptions) const {
0213
0214
0215
0216
0217
0218 Vertex newVtx = vtx;
0219 if (!m_cfg.useVertexCovForIPEstimation) {
0220 newVtx.setFullCovariance(SquareMatrix4::Zero());
0221 }
0222
0223 auto estRes = m_cfg.ipEstimator.getImpactParameters(
0224 m_cfg.extractParameters(track), newVtx, vertexingOptions.geoContext,
0225 vertexingOptions.magFieldContext, m_cfg.useTime);
0226 if (!estRes.ok()) {
0227 return estRes.error();
0228 }
0229
0230 ImpactParametersAndSigma ipas = *estRes;
0231
0232
0233 double chi2Time = 0;
0234 if (m_cfg.useTime) {
0235 if (ipas.sigmaDeltaT.value() > 0) {
0236 chi2Time = std::pow(ipas.deltaT.value() / ipas.sigmaDeltaT.value(), 2);
0237 }
0238 }
0239
0240 double significance = 0.;
0241 if (ipas.sigmaD0 > 0 && ipas.sigmaZ0 > 0) {
0242 significance = std::sqrt(std::pow(ipas.d0 / ipas.sigmaD0, 2) +
0243 std::pow(ipas.z0 / ipas.sigmaZ0, 2) + chi2Time);
0244 }
0245
0246 return significance;
0247 }
0248
0249 Result<void> AdaptiveMultiVertexFinder::addCompatibleTracksToVertex(
0250 const std::vector<InputTrack>& tracks, Vertex& vtx,
0251 VertexFitterState& fitterState,
0252 const VertexingOptions& vertexingOptions) const {
0253 for (const auto& trk : tracks) {
0254 auto params = m_cfg.extractParameters(trk);
0255 auto pos = params.position(vertexingOptions.geoContext);
0256
0257
0258 if (m_cfg.tracksMaxZinterval < std::abs(pos[eZ] - vtx.position()[eZ])) {
0259 continue;
0260 }
0261 auto sigRes = getIPSignificance(trk, vtx, vertexingOptions);
0262 if (!sigRes.ok()) {
0263 return sigRes.error();
0264 }
0265 double ipSig = *sigRes;
0266 if (ipSig < m_cfg.tracksMaxSignificance) {
0267
0268 fitterState.tracksAtVerticesMap.emplace(std::make_pair(trk, &vtx),
0269 TrackAtVertex(params, trk));
0270
0271
0272 fitterState.vtxInfoMap[&vtx].trackLinks.push_back(trk);
0273 }
0274 }
0275 return {};
0276 }
0277
0278 Result<bool> AdaptiveMultiVertexFinder::canRecoverFromNoCompatibleTracks(
0279 const std::vector<InputTrack>& allTracks,
0280 const std::vector<InputTrack>& seedTracks, Vertex& vtx,
0281 const Vertex& currentConstraint, VertexFitterState& fitterState,
0282 const VertexingOptions& vertexingOptions) const {
0283
0284
0285
0286
0287 if (fitterState.vtxInfoMap[&vtx].trackLinks.empty()) {
0288
0289 double smallestDeltaZ = std::numeric_limits<double>::max();
0290 double newZ = 0;
0291 bool nearTrackFound = false;
0292 for (const auto& trk : seedTracks) {
0293 auto pos =
0294 m_cfg.extractParameters(trk).position(vertexingOptions.geoContext);
0295 auto zDistance = std::abs(pos[eZ] - vtx.position()[eZ]);
0296 if (zDistance < smallestDeltaZ) {
0297 smallestDeltaZ = zDistance;
0298 nearTrackFound = true;
0299 newZ = pos[eZ];
0300 }
0301 }
0302 if (nearTrackFound) {
0303 vtx.setFullPosition(Vector4(0., 0., newZ, 0.));
0304
0305
0306 fitterState.vtxInfoMap[&vtx] =
0307 VertexInfo(currentConstraint, vtx.fullPosition());
0308
0309
0310 auto res = addCompatibleTracksToVertex(allTracks, vtx, fitterState,
0311 vertexingOptions);
0312 if (!res.ok()) {
0313 return Result<bool>::failure(res.error());
0314 }
0315
0316 if (fitterState.vtxInfoMap[&vtx].trackLinks.empty()) {
0317 ACTS_DEBUG(
0318 "No tracks near seed were found, while at least one was "
0319 "expected. Break.");
0320 return Result<bool>::success(false);
0321 }
0322
0323 } else {
0324 ACTS_DEBUG("No nearest track to seed found. Break.");
0325 return Result<bool>::success(false);
0326 }
0327 }
0328
0329 return Result<bool>::success(true);
0330 }
0331
0332 Result<bool> AdaptiveMultiVertexFinder::canPrepareVertexForFit(
0333 const std::vector<InputTrack>& allTracks,
0334 const std::vector<InputTrack>& seedTracks, Vertex& vtx,
0335 const Vertex& currentConstraint, VertexFitterState& fitterState,
0336 const VertexingOptions& vertexingOptions) const {
0337
0338 fitterState.vtxInfoMap[&vtx] =
0339 VertexInfo(currentConstraint, vtx.fullPosition());
0340
0341
0342 auto resComp = addCompatibleTracksToVertex(allTracks, vtx, fitterState,
0343 vertexingOptions);
0344 if (!resComp.ok()) {
0345 return Result<bool>::failure(resComp.error());
0346 }
0347
0348
0349 auto resRec = canRecoverFromNoCompatibleTracks(allTracks, seedTracks, vtx,
0350 currentConstraint, fitterState,
0351 vertexingOptions);
0352 if (!resRec.ok()) {
0353 return Result<bool>::failure(resRec.error());
0354 }
0355
0356 return Result<bool>::success(*resRec);
0357 }
0358
0359 std::pair<int, bool> AdaptiveMultiVertexFinder::checkVertexAndCompatibleTracks(
0360 Vertex& vtx, const std::vector<InputTrack>& seedTracks,
0361 VertexFitterState& fitterState, bool useVertexConstraintInFit) const {
0362 bool isGoodVertex = false;
0363 int nCompatibleTracks = 0;
0364 for (const auto& trk : fitterState.vtxInfoMap[&vtx].trackLinks) {
0365 const auto& trkAtVtx =
0366 fitterState.tracksAtVerticesMap.at(std::make_pair(trk, &vtx));
0367 if ((trkAtVtx.vertexCompatibility < m_cfg.maxVertexChi2 &&
0368 m_cfg.useFastCompatibility) ||
0369 (trkAtVtx.trackWeight > m_cfg.minWeight &&
0370 trkAtVtx.chi2Track < m_cfg.maxVertexChi2 &&
0371 !m_cfg.useFastCompatibility)) {
0372
0373
0374 if (rangeContainsValue(seedTracks, trk)) {
0375 nCompatibleTracks++;
0376 ACTS_DEBUG("Compatible track found.");
0377
0378 if (m_cfg.addSingleTrackVertices && useVertexConstraintInFit) {
0379 isGoodVertex = true;
0380 break;
0381 }
0382 if (nCompatibleTracks > 1) {
0383 isGoodVertex = true;
0384 break;
0385 }
0386 }
0387 }
0388 }
0389
0390 return {nCompatibleTracks, isGoodVertex};
0391 }
0392
0393 void AdaptiveMultiVertexFinder::removeCompatibleTracksFromSeedTracks(
0394 Vertex& vtx, std::vector<InputTrack>& seedTracks,
0395 VertexFitterState& fitterState,
0396 std::vector<InputTrack>& removedSeedTracks) const {
0397 for (const auto& trk : fitterState.vtxInfoMap[&vtx].trackLinks) {
0398 const auto& trkAtVtx =
0399 fitterState.tracksAtVerticesMap.at(std::make_pair(trk, &vtx));
0400 if ((trkAtVtx.vertexCompatibility < m_cfg.maxVertexChi2 &&
0401 m_cfg.useFastCompatibility) ||
0402 (trkAtVtx.trackWeight > m_cfg.minWeight &&
0403 trkAtVtx.chi2Track < m_cfg.maxVertexChi2 &&
0404 !m_cfg.useFastCompatibility)) {
0405
0406 auto foundSeedIter = std::ranges::find(seedTracks, trk);
0407 if (foundSeedIter != seedTracks.end()) {
0408 seedTracks.erase(foundSeedIter);
0409 removedSeedTracks.push_back(trk);
0410 }
0411 }
0412 }
0413 }
0414
0415 Result<void> AdaptiveMultiVertexFinder::removeTrackIfIncompatible(
0416 Vertex& vtx, std::vector<InputTrack>& seedTracks,
0417 VertexFitterState& fitterState, std::vector<InputTrack>& removedSeedTracks,
0418 const GeometryContext& geoCtx) const {
0419
0420 double maxCompatibility = 0;
0421
0422 auto maxCompSeedIt = seedTracks.end();
0423 std::optional<InputTrack> removedTrack = std::nullopt;
0424 for (const auto& trk : fitterState.vtxInfoMap[&vtx].trackLinks) {
0425 const auto& trkAtVtx =
0426 fitterState.tracksAtVerticesMap.at(std::make_pair(trk, &vtx));
0427 double compatibility = trkAtVtx.vertexCompatibility;
0428 if (compatibility > maxCompatibility) {
0429
0430 auto foundSeedIter = std::ranges::find(seedTracks, trk);
0431 if (foundSeedIter != seedTracks.end()) {
0432 maxCompatibility = compatibility;
0433 maxCompSeedIt = foundSeedIter;
0434 removedTrack = trk;
0435 }
0436 }
0437 }
0438 if (maxCompSeedIt != seedTracks.end()) {
0439
0440 seedTracks.erase(maxCompSeedIt);
0441 removedSeedTracks.push_back(removedTrack.value());
0442 } else {
0443
0444
0445
0446 double smallestDeltaZ = std::numeric_limits<double>::max();
0447 auto smallestDzSeedIter = seedTracks.end();
0448 for (unsigned int i = 0; i < seedTracks.size(); i++) {
0449 auto pos = m_cfg.extractParameters(seedTracks[i]).position(geoCtx);
0450 double zDistance = std::abs(pos[eZ] - vtx.position()[eZ]);
0451 if (zDistance < smallestDeltaZ) {
0452 smallestDeltaZ = zDistance;
0453 smallestDzSeedIter = seedTracks.begin() + i;
0454 removedTrack = seedTracks[i];
0455 }
0456 }
0457 if (smallestDzSeedIter != seedTracks.end()) {
0458 seedTracks.erase(smallestDzSeedIter);
0459 removedSeedTracks.push_back(removedTrack.value());
0460 } else {
0461 ACTS_ERROR("No track found to remove. Stop vertex finding now.");
0462 return Result<void>::failure(VertexingError::CouldNotRemoveTrack);
0463 }
0464 }
0465 return {};
0466 }
0467
0468 Result<bool> AdaptiveMultiVertexFinder::keepNewVertex(
0469 Vertex& vtx, const std::vector<Vertex*>& allVertices,
0470 VertexFitterState& fitterState) const {
0471 double contamination = 0.;
0472 double contaminationNum = 0;
0473 double contaminationDeNom = 0;
0474 for (const auto& trk : fitterState.vtxInfoMap[&vtx].trackLinks) {
0475 const auto& trkAtVtx =
0476 fitterState.tracksAtVerticesMap.at(std::make_pair(trk, &vtx));
0477 double trackWeight = trkAtVtx.trackWeight;
0478 contaminationNum += trackWeight * (1. - trackWeight);
0479
0480 contaminationDeNom += trackWeight * trackWeight;
0481
0482 }
0483 if (contaminationDeNom != 0) {
0484 contamination = contaminationNum / contaminationDeNom;
0485 }
0486 if (contamination > m_cfg.maximumVertexContamination) {
0487 return Result<bool>::success(false);
0488 }
0489
0490 auto isMergedVertexResult = isMergedVertex(vtx, allVertices);
0491 if (!isMergedVertexResult.ok()) {
0492 return Result<bool>::failure(isMergedVertexResult.error());
0493 }
0494
0495 if (*isMergedVertexResult) {
0496 return Result<bool>::success(false);
0497 }
0498
0499 return Result<bool>::success(true);
0500 }
0501
0502 Result<bool> AdaptiveMultiVertexFinder::isMergedVertex(
0503 const Vertex& vtx, const std::vector<Vertex*>& allVertices) const {
0504 const Vector4& candidatePos = vtx.fullPosition();
0505 const SquareMatrix4& candidateCov = vtx.fullCovariance();
0506
0507 for (const auto otherVtx : allVertices) {
0508 if (&vtx == otherVtx) {
0509 continue;
0510 }
0511 const Vector4& otherPos = otherVtx->fullPosition();
0512 const SquareMatrix4& otherCov = otherVtx->fullCovariance();
0513
0514 double significance = 0;
0515 if (!m_cfg.doFullSplitting) {
0516 if (m_cfg.useTime) {
0517 const Vector2 deltaZT = otherPos.tail<2>() - candidatePos.tail<2>();
0518 SquareMatrix2 sumCovZT = candidateCov.bottomRightCorner<2, 2>() +
0519 otherCov.bottomRightCorner<2, 2>();
0520 auto sumCovZTInverse = safeInverse(sumCovZT);
0521 if (!sumCovZTInverse) {
0522 ACTS_ERROR("Vertex z-t covariance matrix is singular.");
0523 ACTS_ERROR("sumCovZT:\n" << sumCovZT);
0524 return Result<bool>::failure(VertexingError::SingularMatrix);
0525 }
0526 significance = std::sqrt(deltaZT.dot(*sumCovZTInverse * deltaZT));
0527 } else {
0528 const double deltaZPos = otherPos[eZ] - candidatePos[eZ];
0529 const double sumVarZ = otherCov(eZ, eZ) + candidateCov(eZ, eZ);
0530 if (sumVarZ <= 0) {
0531 ACTS_ERROR("Variance of the vertex's z-coordinate is not positive.");
0532 ACTS_ERROR("sumVarZ:\n" << sumVarZ);
0533 return Result<bool>::failure(VertexingError::SingularMatrix);
0534 }
0535
0536 significance = std::abs(deltaZPos) / std::sqrt(sumVarZ);
0537 }
0538 } else {
0539 if (m_cfg.useTime) {
0540
0541 const Vector4 deltaPos = otherPos - candidatePos;
0542 SquareMatrix4 sumCov = candidateCov + otherCov;
0543 auto sumCovInverse = safeInverse(sumCov);
0544 if (!sumCovInverse) {
0545 ACTS_ERROR("Vertex 4D covariance matrix is singular.");
0546 ACTS_ERROR("sumCov:\n" << sumCov);
0547 return Result<bool>::failure(VertexingError::SingularMatrix);
0548 }
0549 significance = std::sqrt(deltaPos.dot(*sumCovInverse * deltaPos));
0550 } else {
0551
0552 const Vector3 deltaPos = otherPos.head<3>() - candidatePos.head<3>();
0553 SquareMatrix3 sumCov =
0554 candidateCov.topLeftCorner<3, 3>() + otherCov.topLeftCorner<3, 3>();
0555 auto sumCovInverse = safeInverse(sumCov);
0556 if (!sumCovInverse) {
0557 ACTS_ERROR("Vertex 3D covariance matrix is singular.");
0558 ACTS_ERROR("sumCov:\n" << sumCov);
0559 return Result<bool>::failure(VertexingError::SingularMatrix);
0560 }
0561 significance = std::sqrt(deltaPos.dot(*sumCovInverse * deltaPos));
0562 }
0563 }
0564 if (significance < 0.) {
0565 ACTS_ERROR(
0566 "Found a negative significance (i.e., a negative chi2) when checking "
0567 "if vertices are merged. This should never happen since the vertex "
0568 "covariance should be positive definite, and thus its inverse "
0569 "should be positive definite as well.");
0570 return Result<bool>::failure(VertexingError::MatrixNotPositiveDefinite);
0571 }
0572 if (significance < m_cfg.maxMergeVertexSignificance) {
0573 return Result<bool>::success(true);
0574 }
0575 }
0576 return Result<bool>::success(false);
0577 }
0578
0579 Result<void> AdaptiveMultiVertexFinder::deleteLastVertex(
0580 Vertex& vtx, std::vector<std::unique_ptr<Vertex>>& allVertices,
0581 std::vector<Vertex*>& allVerticesPtr, VertexFitterState& fitterState,
0582 const VertexingOptions& vertexingOptions) const {
0583 allVertices.pop_back();
0584 allVerticesPtr.pop_back();
0585
0586
0587 fitterState.removeVertexFromMultiMap(vtx);
0588
0589
0590
0591
0592 auto removeResult = fitterState.removeVertexFromCollection(vtx, logger());
0593 if (!removeResult.ok()) {
0594 return removeResult.error();
0595 }
0596
0597 for (auto& [key, value] : fitterState.tracksAtVerticesMap) {
0598
0599 if (key.second == &vtx) {
0600 value.isLinearized = false;
0601 }
0602 }
0603
0604
0605 if (fitterState.vertexCollection.empty()) {
0606 return {};
0607 }
0608
0609
0610 auto fitResult = m_cfg.vertexFitter.fit(fitterState, vertexingOptions);
0611 if (!fitResult.ok()) {
0612 return fitResult.error();
0613 }
0614
0615 return {};
0616 }
0617
0618 Result<std::vector<Vertex>> AdaptiveMultiVertexFinder::getVertexOutputList(
0619 const std::vector<Vertex*>& allVerticesPtr,
0620 VertexFitterState& fitterState) const {
0621 std::vector<Vertex> outputVec;
0622 for (auto vtx : allVerticesPtr) {
0623 auto& outVtx = *vtx;
0624 std::vector<TrackAtVertex> tracksAtVtx;
0625 for (const auto& trk : fitterState.vtxInfoMap[vtx].trackLinks) {
0626 tracksAtVtx.push_back(
0627 fitterState.tracksAtVerticesMap.at(std::make_pair(trk, vtx)));
0628 }
0629 outVtx.setTracksAtVertex(std::move(tracksAtVtx));
0630 outputVec.push_back(outVtx);
0631 }
0632 return Result<std::vector<Vertex>>(outputVec);
0633 }
0634
0635 }