File indexing completed on 2025-01-18 09:11:32
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "Acts/Vertexing/AdaptiveMultiVertexFitter.hpp"
0010
0011 #include "Acts/Surfaces/PerigeeSurface.hpp"
0012 #include "Acts/Utilities/Helpers.hpp"
0013 #include "Acts/Vertexing/KalmanVertexUpdater.hpp"
0014 #include "Acts/Vertexing/VertexingError.hpp"
0015
0016 Acts::Result<void> Acts::AdaptiveMultiVertexFitter::fit(
0017 State& state, const VertexingOptions& vertexingOptions) const {
0018
0019 state.annealingState = AnnealingUtility::State();
0020
0021
0022
0023
0024
0025
0026 bool isSmallShift = true;
0027
0028
0029 unsigned int nIter = 0;
0030
0031
0032 while (nIter < m_cfg.maxIterations &&
0033 (!state.annealingState.equilibriumReached || !isSmallShift)) {
0034
0035 for (auto vtx : state.vertexCollection) {
0036 VertexInfo& vtxInfo = state.vtxInfoMap[vtx];
0037 vtxInfo.relinearize = false;
0038
0039
0040
0041 vtxInfo.oldPosition = vtx->fullPosition();
0042
0043
0044
0045
0046
0047 Vector2 xyDiff = vtxInfo.oldPosition.template head<2>() -
0048 vtxInfo.linPoint.template head<2>();
0049 if (xyDiff.norm() > m_cfg.maxDistToLinPoint) {
0050
0051 vtxInfo.relinearize = true;
0052
0053
0054 auto prepareVertexResult =
0055 prepareVertexForFit(state, vtx, vertexingOptions);
0056 if (!prepareVertexResult.ok()) {
0057
0058 if (logger().doPrint(Logging::DEBUG)) {
0059 logDebugData(state, vertexingOptions.geoContext);
0060 }
0061 return prepareVertexResult.error();
0062 }
0063 }
0064
0065
0066 if (state.vtxInfoMap[vtx].constraint.fullCovariance() !=
0067 SquareMatrix4::Zero()) {
0068 const Acts::Vertex& constraint = state.vtxInfoMap[vtx].constraint;
0069 vtx->setFullPosition(constraint.fullPosition());
0070 vtx->setFitQuality(constraint.fitQuality());
0071 vtx->setFullCovariance(constraint.fullCovariance());
0072 } else if (vtx->fullCovariance() == SquareMatrix4::Zero()) {
0073 return VertexingError::NoCovariance;
0074 }
0075
0076
0077
0078 auto setCompatibilitiesResult =
0079 setAllVertexCompatibilities(state, vtx, vertexingOptions);
0080 if (!setCompatibilitiesResult.ok()) {
0081
0082 if (logger().doPrint(Logging::DEBUG)) {
0083 logDebugData(state, vertexingOptions.geoContext);
0084 }
0085 return setCompatibilitiesResult.error();
0086 }
0087 }
0088
0089
0090 auto setWeightsResult = setWeightsAndUpdate(state, vertexingOptions);
0091 if (!setWeightsResult.ok()) {
0092
0093 if (logger().doPrint(Logging::DEBUG)) {
0094 logDebugData(state, vertexingOptions.geoContext);
0095 }
0096 return setWeightsResult.error();
0097 }
0098
0099
0100
0101 if (!state.annealingState.equilibriumReached) {
0102 m_cfg.annealingTool.anneal(state.annealingState);
0103 }
0104
0105 isSmallShift = checkSmallShift(state);
0106 ++nIter;
0107 }
0108
0109
0110
0111 if (m_cfg.doSmoothing) {
0112 doVertexSmoothing(state);
0113 }
0114
0115 return {};
0116 }
0117
0118 Acts::Result<void> Acts::AdaptiveMultiVertexFitter::addVtxToFit(
0119 State& state, Vertex& newVertex,
0120 const VertexingOptions& vertexingOptions) const {
0121 if (state.vtxInfoMap[&newVertex].trackLinks.empty()) {
0122 ACTS_ERROR(
0123 "newVertex does not have any associated tracks (i.e., its trackLinks "
0124 "are empty).");
0125 return VertexingError::EmptyInput;
0126 }
0127
0128 std::vector<Vertex*> verticesToFit = {&newVertex};
0129
0130
0131 std::vector<Vertex*> lastIterAddedVertices = {&newVertex};
0132
0133 std::vector<Vertex*> currentIterAddedVertices;
0134
0135
0136
0137 while (!lastIterAddedVertices.empty()) {
0138 for (auto& lastIterAddedVertex : lastIterAddedVertices) {
0139
0140 const std::vector<InputTrack>& trks =
0141 state.vtxInfoMap[lastIterAddedVertex].trackLinks;
0142 for (const auto& trk : trks) {
0143
0144
0145
0146
0147 auto [begin, end] = state.trackToVerticesMultiMap.equal_range(trk);
0148
0149 for (auto it = begin; it != end; ++it) {
0150
0151
0152 auto vtxToFit = it->second;
0153
0154 if (!isAlreadyInList(vtxToFit, verticesToFit)) {
0155 verticesToFit.push_back(vtxToFit);
0156
0157
0158 if (vtxToFit != lastIterAddedVertex) {
0159 currentIterAddedVertices.push_back(vtxToFit);
0160 }
0161 }
0162 }
0163 }
0164 }
0165
0166 lastIterAddedVertices = currentIterAddedVertices;
0167 currentIterAddedVertices.clear();
0168 }
0169
0170 state.vertexCollection = verticesToFit;
0171
0172
0173 auto res = prepareVertexForFit(state, &newVertex, vertexingOptions);
0174 if (!res.ok()) {
0175
0176 if (logger().doPrint(Logging::DEBUG)) {
0177 logDebugData(state, vertexingOptions.geoContext);
0178 }
0179 return res.error();
0180 }
0181
0182
0183 auto fitRes = fit(state, vertexingOptions);
0184 if (!fitRes.ok()) {
0185 return fitRes.error();
0186 }
0187
0188 return {};
0189 }
0190
0191 bool Acts::AdaptiveMultiVertexFitter::isAlreadyInList(
0192 Vertex* vtx, const std::vector<Vertex*>& vertices) const {
0193 return rangeContainsValue(vertices, vtx);
0194 }
0195
0196 Acts::Result<void> Acts::AdaptiveMultiVertexFitter::prepareVertexForFit(
0197 State& state, Vertex* vtx, const VertexingOptions& vertexingOptions) const {
0198
0199 auto& vtxInfo = state.vtxInfoMap[vtx];
0200
0201 const Vector3& seedPos = vtxInfo.seedPosition.template head<3>();
0202
0203
0204 for (const auto& trk : vtxInfo.trackLinks) {
0205 auto res = m_cfg.ipEst.estimate3DImpactParameters(
0206 vertexingOptions.geoContext, vertexingOptions.magFieldContext,
0207 m_cfg.extractParameters(trk), seedPos, state.ipState);
0208 if (!res.ok()) {
0209 return res.error();
0210 }
0211
0212 vtxInfo.impactParams3D.emplace(trk, res.value());
0213 }
0214 return {};
0215 }
0216
0217 Acts::Result<void> Acts::AdaptiveMultiVertexFitter::setAllVertexCompatibilities(
0218 State& state, Vertex* vtx, const VertexingOptions& vertexingOptions) const {
0219 VertexInfo& vtxInfo = state.vtxInfoMap[vtx];
0220
0221
0222
0223 for (const auto& trk : vtxInfo.trackLinks) {
0224 auto& trkAtVtx = state.tracksAtVerticesMap.at(std::make_pair(trk, vtx));
0225
0226
0227 if (!vtxInfo.impactParams3D.contains(trk)) {
0228 auto res = m_cfg.ipEst.estimate3DImpactParameters(
0229 vertexingOptions.geoContext, vertexingOptions.magFieldContext,
0230 m_cfg.extractParameters(trk),
0231 VectorHelpers::position(vtxInfo.linPoint), state.ipState);
0232 if (!res.ok()) {
0233 return res.error();
0234 }
0235
0236 vtxInfo.impactParams3D.emplace(trk, res.value());
0237 }
0238
0239 Acts::Result<double> compatibilityResult(0.);
0240 if (m_cfg.useTime) {
0241 compatibilityResult = m_cfg.ipEst.getVertexCompatibility(
0242 vertexingOptions.geoContext, &(vtxInfo.impactParams3D.at(trk)),
0243 vtxInfo.oldPosition);
0244 } else {
0245 Acts::Vector3 vertexPosOnly =
0246 VectorHelpers::position(vtxInfo.oldPosition);
0247 compatibilityResult = m_cfg.ipEst.getVertexCompatibility(
0248 vertexingOptions.geoContext, &(vtxInfo.impactParams3D.at(trk)),
0249 vertexPosOnly);
0250 }
0251
0252 if (!compatibilityResult.ok()) {
0253 return compatibilityResult.error();
0254 }
0255 trkAtVtx.vertexCompatibility = *compatibilityResult;
0256 }
0257 return {};
0258 }
0259
0260 Acts::Result<void> Acts::AdaptiveMultiVertexFitter::setWeightsAndUpdate(
0261 State& state, const VertexingOptions& vertexingOptions) const {
0262 for (auto vtx : state.vertexCollection) {
0263 VertexInfo& vtxInfo = state.vtxInfoMap[vtx];
0264
0265 if (vtxInfo.relinearize) {
0266 vtxInfo.linPoint = vtxInfo.oldPosition;
0267 }
0268
0269 const std::shared_ptr<PerigeeSurface> vtxPerigeeSurface =
0270 Surface::makeShared<PerigeeSurface>(
0271 VectorHelpers::position(vtxInfo.linPoint));
0272
0273 for (const auto& trk : vtxInfo.trackLinks) {
0274 auto& trkAtVtx = state.tracksAtVerticesMap.at(std::make_pair(trk, vtx));
0275
0276
0277 trkAtVtx.trackWeight = m_cfg.annealingTool.getWeight(
0278 state.annealingState, trkAtVtx.vertexCompatibility,
0279 collectTrackToVertexCompatibilities(state, trk));
0280
0281 if (trkAtVtx.trackWeight > m_cfg.minWeight) {
0282
0283
0284 if (!trkAtVtx.isLinearized || vtxInfo.relinearize) {
0285 auto result = m_cfg.trackLinearizer(
0286 m_cfg.extractParameters(trk), vtxInfo.linPoint[3],
0287 *vtxPerigeeSurface, vertexingOptions.geoContext,
0288 vertexingOptions.magFieldContext, state.fieldCache);
0289 if (!result.ok()) {
0290 return result.error();
0291 }
0292
0293 trkAtVtx.linearizedState = *result;
0294 trkAtVtx.isLinearized = true;
0295 }
0296
0297
0298
0299
0300 KalmanVertexUpdater::updateVertexWithTrack(*vtx, trkAtVtx,
0301 m_cfg.useTime ? 4 : 3);
0302 } else {
0303 ACTS_VERBOSE("Track weight too low. Skip track.");
0304 }
0305 }
0306 ACTS_VERBOSE("New vertex position: " << vtx->fullPosition().transpose());
0307 }
0308
0309 return {};
0310 }
0311
0312 std::vector<double>
0313 Acts::AdaptiveMultiVertexFitter::collectTrackToVertexCompatibilities(
0314 State& state, const InputTrack& trk) const {
0315
0316 std::vector<double> trkToVtxCompatibilities;
0317
0318
0319
0320
0321 auto [begin, end] = state.trackToVerticesMultiMap.equal_range(trk);
0322
0323 trkToVtxCompatibilities.reserve(std::distance(begin, end));
0324
0325 for (auto it = begin; it != end; ++it) {
0326
0327
0328 trkToVtxCompatibilities.push_back(
0329 state.tracksAtVerticesMap.at(std::make_pair(trk, it->second))
0330 .vertexCompatibility);
0331 }
0332
0333 return trkToVtxCompatibilities;
0334 }
0335
0336 bool Acts::AdaptiveMultiVertexFitter::checkSmallShift(State& state) const {
0337 for (auto* vtx : state.vertexCollection) {
0338 Vector3 diff =
0339 state.vtxInfoMap[vtx].oldPosition.template head<3>() - vtx->position();
0340 const SquareMatrix3& vtxCov = vtx->covariance();
0341 double relativeShift = diff.dot(vtxCov.inverse() * diff);
0342 if (relativeShift > m_cfg.maxRelativeShift) {
0343 return false;
0344 }
0345 }
0346 return true;
0347 }
0348
0349 void Acts::AdaptiveMultiVertexFitter::doVertexSmoothing(State& state) const {
0350 for (const auto vtx : state.vertexCollection) {
0351 for (const auto& trk : state.vtxInfoMap[vtx].trackLinks) {
0352 auto& trkAtVtx = state.tracksAtVerticesMap.at(std::make_pair(trk, vtx));
0353 if (trkAtVtx.trackWeight > m_cfg.minWeight) {
0354
0355
0356
0357
0358 KalmanVertexUpdater::updateTrackWithVertex(trkAtVtx, *vtx,
0359 m_cfg.useTime ? 4 : 3);
0360 }
0361 }
0362 }
0363 }
0364
0365 void Acts::AdaptiveMultiVertexFitter::logDebugData(
0366 const State& state, const Acts::GeometryContext& geoContext) const {
0367 ACTS_DEBUG("Encountered an error when fitting the following "
0368 << state.vertexCollection.size() << " vertices:");
0369 for (std::size_t vtxInd = 0; vtxInd < state.vertexCollection.size();
0370 ++vtxInd) {
0371 auto vtx = state.vertexCollection[vtxInd];
0372 ACTS_DEBUG("Position of " << vtxInd << ". vertex seed:\n"
0373 << state.vtxInfoMap.at(vtx).seedPosition);
0374 ACTS_DEBUG("Position of said vertex after the last fitting step:\n"
0375 << state.vtxInfoMap.at(vtx).oldPosition);
0376 ACTS_DEBUG("Associated tracks:");
0377 const auto& trks = state.vtxInfoMap.at(vtx).trackLinks;
0378 for (std::size_t trkInd = 0; trkInd < trks.size(); ++trkInd) {
0379 const auto& trkAtVtx =
0380 state.tracksAtVerticesMap.at(std::make_pair(trks[trkInd], vtx));
0381 const auto& trkParams = m_cfg.extractParameters(trkAtVtx.originalParams);
0382 ACTS_DEBUG(trkInd << ". track parameters:\n" << trkParams.parameters());
0383 ACTS_DEBUG(trkInd << ". track covariance matrix:\n"
0384 << trkParams.covariance().value());
0385 ACTS_DEBUG("Origin of corresponding reference surface:\n"
0386 << trkParams.referenceSurface().center(geoContext));
0387 }
0388 }
0389 }