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