File indexing completed on 2025-01-18 09:11:32
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "Acts/Vertexing/FullBilloirVertexFitter.hpp"
0010
0011 #include "Acts/Definitions/TrackParametrization.hpp"
0012 #include "Acts/MagneticField/ConstantBField.hpp"
0013 #include "Acts/Surfaces/PerigeeSurface.hpp"
0014 #include "Acts/Utilities/detail/periodic.hpp"
0015 #include "Acts/Vertexing/TrackAtVertex.hpp"
0016 #include "Acts/Vertexing/VertexingError.hpp"
0017
0018 namespace {
0019
0020
0021
0022
0023 struct BilloirTrack {
0024 BilloirTrack(const Acts::InputTrack& params) : originalTrack(params) {}
0025
0026 BilloirTrack(const BilloirTrack& arg) = default;
0027
0028 Acts::InputTrack originalTrack;
0029 double chi2 = 0;
0030
0031
0032 Acts::ActsMatrix<Acts::eBoundSize, Acts::eBoundSize> W;
0033 Acts::ActsMatrix<Acts::eBoundSize, 4> D;
0034 Acts::ActsMatrix<Acts::eBoundSize, 3> E;
0035 Acts::ActsSquareMatrix<3> C;
0036 Acts::ActsMatrix<4, 3> B;
0037 Acts::ActsSquareMatrix<3> Cinv;
0038 Acts::Vector3 U;
0039 Acts::ActsMatrix<4, 3> BCinv;
0040 Acts::BoundVector deltaQ;
0041 };
0042
0043
0044
0045
0046 struct BilloirVertex {
0047
0048 Acts::SquareMatrix4 A = Acts::SquareMatrix4::Zero();
0049
0050 Acts::Vector4 T = Acts::Vector4::Zero();
0051
0052 Acts::SquareMatrix4 sumBCinvBt = Acts::SquareMatrix4::Zero();
0053
0054 Acts::Vector4 sumBCinvU = Acts::Vector4::Zero();
0055 };
0056
0057 }
0058
0059 Acts::Result<Acts::Vertex> Acts::FullBilloirVertexFitter::fit(
0060 const std::vector<InputTrack>& paramVector,
0061 const VertexingOptions& vertexingOptions,
0062 MagneticFieldProvider::Cache& fieldCache) const {
0063 unsigned int nTracks = paramVector.size();
0064 double chi2 = std::numeric_limits<double>::max();
0065
0066 if (nTracks == 0) {
0067 return Vertex(Vector3(0., 0., 0.));
0068 }
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078 int ndf = 3 * nTracks - 3;
0079
0080
0081 if (nTracks < 2) {
0082 ndf = 1;
0083 }
0084
0085
0086
0087 if (vertexingOptions.useConstraintInFit) {
0088 ndf += 3;
0089 }
0090
0091 std::vector<BilloirTrack> billoirTracks;
0092 std::vector<Vector3> trackMomenta;
0093
0094 Vector4 linPoint = vertexingOptions.constraint.fullPosition();
0095 Vertex fittedVertex;
0096
0097 for (int nIter = 0; nIter < m_cfg.maxIterations; ++nIter) {
0098 billoirTracks.clear();
0099 double newChi2 = 0;
0100 BilloirVertex billoirVertex;
0101
0102 Vector3 linPointPos = VectorHelpers::position(linPoint);
0103
0104
0105 const std::shared_ptr<PerigeeSurface> perigeeSurface =
0106 Surface::makeShared<PerigeeSurface>(linPointPos);
0107
0108
0109 for (std::size_t iTrack = 0; iTrack < nTracks; ++iTrack) {
0110 const InputTrack& trackContainer = paramVector[iTrack];
0111
0112 const auto& trackParams = m_cfg.extractParameters(trackContainer);
0113
0114 auto result =
0115 m_cfg.trackLinearizer(trackParams, linPoint[3], *perigeeSurface,
0116 vertexingOptions.geoContext,
0117 vertexingOptions.magFieldContext, fieldCache);
0118 if (!result.ok()) {
0119 return result.error();
0120 }
0121
0122 const auto& linTrack = *result;
0123 const auto& parametersAtPCA = linTrack.parametersAtPCA;
0124 double d0 = parametersAtPCA[BoundIndices::eBoundLoc0];
0125 double z0 = parametersAtPCA[BoundIndices::eBoundLoc1];
0126 double phi = parametersAtPCA[BoundIndices::eBoundPhi];
0127 double theta = parametersAtPCA[BoundIndices::eBoundTheta];
0128 double qOverP = parametersAtPCA[BoundIndices::eBoundQOverP];
0129 double t0 = parametersAtPCA[BoundIndices::eBoundTime];
0130
0131
0132
0133 if (nIter == 0) {
0134 trackMomenta.push_back(Vector3(phi, theta, qOverP));
0135 }
0136
0137
0138
0139
0140 double fPhi = trackMomenta[iTrack][0];
0141 double fTheta = trackMomenta[iTrack][1];
0142 double fQOvP = trackMomenta[iTrack][2];
0143 double fTime = linPoint[FreeIndices::eFreeTime];
0144 BilloirTrack billoirTrack(trackContainer);
0145
0146 billoirTrack.deltaQ << d0, z0, phi - fPhi, theta - fTheta, qOverP - fQOvP,
0147 t0 - fTime;
0148
0149
0150 ActsMatrix<eBoundSize, 4> D = linTrack.positionJacobian;
0151
0152
0153 ActsMatrix<eBoundSize, 3> E = linTrack.momentumJacobian;
0154
0155
0156 BoundSquareMatrix W = linTrack.weightAtPCA;
0157 ActsMatrix<4, eBoundSize> DtW = D.transpose() * W;
0158 ActsMatrix<3, eBoundSize> EtW = E.transpose() * W;
0159
0160
0161 billoirTrack.D = D;
0162 billoirTrack.E = E;
0163 billoirTrack.W = W;
0164 billoirTrack.C = EtW * E;
0165 billoirTrack.B = DtW * E;
0166 billoirTrack.U = EtW * billoirTrack.deltaQ;
0167 billoirTrack.Cinv = (billoirTrack.C).inverse();
0168 billoirTrack.BCinv =
0169 billoirTrack.B * billoirTrack.Cinv;
0170
0171
0172 billoirVertex.T += DtW * billoirTrack.deltaQ;
0173 billoirVertex.A += DtW * D;
0174 billoirVertex.sumBCinvU +=
0175 billoirTrack.BCinv * billoirTrack.U;
0176 billoirVertex.sumBCinvBt +=
0177 billoirTrack.BCinv *
0178 billoirTrack.B.transpose();
0179
0180 billoirTracks.push_back(billoirTrack);
0181 }
0182
0183
0184
0185
0186 Vector4 deltaVFac = billoirVertex.T - billoirVertex.sumBCinvU;
0187
0188
0189
0190
0191 SquareMatrix4 invCovV = billoirVertex.A - billoirVertex.sumBCinvBt;
0192 if (vertexingOptions.useConstraintInFit) {
0193
0194
0195
0196
0197 Vector4 posInBilloirFrame =
0198 vertexingOptions.constraint.fullPosition() - linPoint;
0199
0200
0201
0202
0203 deltaVFac += vertexingOptions.constraint.fullCovariance().inverse() *
0204 posInBilloirFrame;
0205
0206 invCovV += vertexingOptions.constraint.fullCovariance().inverse();
0207 }
0208
0209
0210 SquareMatrix4 covV = invCovV.inverse();
0211
0212 Vector4 deltaV = covV * deltaVFac;
0213
0214
0215
0216 std::vector<std::optional<BoundSquareMatrix>> covDeltaP(nTracks);
0217
0218
0219
0220 for (std::size_t iTrack = 0; iTrack < billoirTracks.size(); ++iTrack) {
0221 auto& billoirTrack = billoirTracks[iTrack];
0222
0223 Vector3 deltaP = (billoirTrack.Cinv) *
0224 (billoirTrack.U - billoirTrack.B.transpose() * deltaV);
0225
0226
0227 trackMomenta[iTrack] += deltaP;
0228
0229
0230 const auto correctedPhiTheta = detail::normalizePhiTheta(
0231 trackMomenta[iTrack][0], trackMomenta[iTrack][1]);
0232 trackMomenta[iTrack][0] = correctedPhiTheta.first;
0233 trackMomenta[iTrack][1] = correctedPhiTheta.second;
0234
0235
0236 Acts::BoundVector diffQ = billoirTrack.deltaQ - billoirTrack.D * deltaV -
0237 billoirTrack.E * deltaP;
0238 billoirTrack.chi2 = diffQ.transpose().dot(billoirTrack.W * diffQ);
0239
0240 newChi2 += billoirTrack.chi2;
0241
0242
0243
0244
0245
0246
0247
0248
0249
0250
0251
0252 ActsMatrix<eBoundSize, 7> transMat;
0253 transMat.setZero();
0254 transMat.block<2, 2>(0, 0) = billoirTrack.D.template block<2, 2>(0, 0);
0255 transMat(1, 2) = 1.;
0256 transMat(2, 4) = 1.;
0257 transMat(3, 5) = 1.;
0258 transMat(4, 6) = 1.;
0259 transMat(5, 3) = 1.;
0260
0261
0262 ActsMatrix<4, 3> covVP = -covV * billoirTrack.BCinv;
0263
0264
0265 ActsSquareMatrix<3> covP =
0266 billoirTrack.Cinv +
0267 billoirTrack.BCinv.transpose() * covV * billoirTrack.BCinv;
0268
0269 ActsSquareMatrix<7> cov;
0270 cov.setZero();
0271 cov.block<4, 4>(0, 0) = covV;
0272 cov.block<4, 3>(0, 4) = covVP;
0273 cov.block<3, 4>(4, 0) = covVP.transpose();
0274 cov.block<3, 3>(4, 4) = covP;
0275
0276 covDeltaP[iTrack] = transMat * cov * transMat.transpose();
0277 }
0278
0279
0280 linPoint += deltaV;
0281
0282
0283
0284 if (vertexingOptions.useConstraintInFit) {
0285
0286
0287 Vector4 posInBilloirFrame =
0288 vertexingOptions.constraint.fullPosition() - linPoint;
0289
0290 newChi2 +=
0291 (posInBilloirFrame.transpose())
0292 .dot(vertexingOptions.constraint.fullCovariance().inverse() *
0293 posInBilloirFrame);
0294 }
0295
0296 if (!std::isnormal(newChi2)) {
0297 ACTS_ERROR("Encountered non-normal chi2 value during the fit.");
0298 return VertexingError::NumericFailure;
0299 }
0300
0301 if (newChi2 < chi2) {
0302 chi2 = newChi2;
0303
0304 fittedVertex.setFullPosition(linPoint);
0305 fittedVertex.setFullCovariance(covV);
0306 fittedVertex.setFitQuality(chi2, ndf);
0307
0308 std::vector<TrackAtVertex> tracksAtVertex;
0309
0310 std::shared_ptr<PerigeeSurface> perigee =
0311 Surface::makeShared<PerigeeSurface>(
0312 VectorHelpers::position(linPoint));
0313
0314 for (std::size_t iTrack = 0; iTrack < billoirTracks.size(); ++iTrack) {
0315 const auto& billoirTrack = billoirTracks[iTrack];
0316
0317
0318
0319
0320
0321
0322 BoundVector paramVec = BoundVector::Zero();
0323 paramVec[eBoundPhi] = trackMomenta[iTrack](0);
0324 paramVec[eBoundTheta] = trackMomenta[iTrack](1);
0325 paramVec[eBoundQOverP] = trackMomenta[iTrack](2);
0326 paramVec[eBoundTime] = linPoint[FreeIndices::eFreeTime];
0327 BoundTrackParameters refittedParams(
0328 perigee, paramVec, covDeltaP[iTrack],
0329 m_cfg.extractParameters(billoirTrack.originalTrack)
0330 .particleHypothesis());
0331 TrackAtVertex trackAtVertex(billoirTrack.chi2, refittedParams,
0332 billoirTrack.originalTrack);
0333 tracksAtVertex.push_back(std::move(trackAtVertex));
0334 }
0335
0336 fittedVertex.setTracksAtVertex(std::move(tracksAtVertex));
0337 }
0338 }
0339
0340 return fittedVertex;
0341 }