File indexing completed on 2026-01-04 08:54:28
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "Acts/Vertexing/HelicalTrackLinearizer.hpp"
0010
0011 #include "Acts/Propagator/PropagatorOptions.hpp"
0012 #include "Acts/Utilities/Intersection.hpp"
0013 #include "Acts/Utilities/MathHelpers.hpp"
0014 #include "Acts/Vertexing/LinearizerTrackParameters.hpp"
0015
0016 Acts::Result<Acts::LinearizedTrack>
0017 Acts::HelicalTrackLinearizer::linearizeTrack(
0018 const BoundTrackParameters& params, double linPointTime,
0019 const Surface& perigeeSurface, const Acts::GeometryContext& gctx,
0020 const Acts::MagneticFieldContext& mctx,
0021 MagneticFieldProvider::Cache& fieldCache) const {
0022
0023 PropagatorPlainOptions pOptions(gctx, mctx);
0024
0025
0026
0027 pOptions.surfaceTolerance = m_cfg.targetTolerance;
0028
0029
0030
0031
0032
0033 Intersection3D intersection =
0034 perigeeSurface
0035 .intersect(gctx, params.position(gctx), params.direction(),
0036 BoundaryTolerance::Infinite())
0037 .closest();
0038
0039
0040
0041
0042
0043 pOptions.direction =
0044 Direction::fromScalarZeroAsPositive(intersection.pathLength());
0045
0046
0047 const auto res =
0048 m_cfg.propagator->propagateToSurface(params, perigeeSurface, pOptions);
0049 if (!res.ok()) {
0050 return res.error();
0051 }
0052 const auto& endParams = *res;
0053
0054
0055
0056 BoundVector paramsAtPCA = endParams.parameters();
0057
0058
0059 Vector4 pca = Vector4::Zero();
0060 {
0061 auto pos = endParams.position(gctx);
0062 pca[ePos0] = pos[ePos0];
0063 pca[ePos1] = pos[ePos1];
0064 pca[ePos2] = pos[ePos2];
0065 pca[eTime] = endParams.time();
0066 }
0067 BoundSquareMatrix parCovarianceAtPCA = endParams.covariance().value();
0068
0069
0070
0071 double d0 = paramsAtPCA(BoundIndices::eBoundLoc0);
0072
0073 double phi = paramsAtPCA(BoundIndices::eBoundPhi);
0074 double sinPhi = std::sin(phi);
0075 double cosPhi = std::cos(phi);
0076
0077 double theta = paramsAtPCA(BoundIndices::eBoundTheta);
0078 double sinTheta = std::sin(theta);
0079 double tanTheta = std::tan(theta);
0080
0081
0082 double qOvP = paramsAtPCA(BoundIndices::eBoundQOverP);
0083
0084 double m0 = params.particleHypothesis().mass();
0085
0086 double p = params.particleHypothesis().extractMomentum(qOvP);
0087
0088
0089 double beta = p / fastHypot(p, m0);
0090
0091 double betaT = beta * sinTheta;
0092
0093
0094 Vector3 momentumAtPCA(phi, theta, qOvP);
0095
0096
0097 double absoluteCharge = params.particleHypothesis().absoluteCharge();
0098
0099
0100 auto field = m_cfg.bField->getField(VectorHelpers::position(pca), fieldCache);
0101 if (!field.ok()) {
0102 return field.error();
0103 }
0104 double Bz = (*field)[eZ];
0105
0106
0107 ActsMatrix<eBoundSize, eLinSize> completeJacobian =
0108 ActsMatrix<eBoundSize, eLinSize>::Zero(eBoundSize, eLinSize);
0109
0110
0111
0112
0113 if (absoluteCharge == 0. || Bz == 0.) {
0114
0115
0116
0117
0118
0119
0120 completeJacobian(eBoundLoc0, eLinPos0) = -sinPhi;
0121 completeJacobian(eBoundLoc0, eLinPos1) = cosPhi;
0122
0123
0124 completeJacobian(eBoundLoc1, eLinPos0) = -cosPhi / tanTheta;
0125 completeJacobian(eBoundLoc1, eLinPos1) = -sinPhi / tanTheta;
0126 completeJacobian(eBoundLoc1, eLinPos2) = 1.;
0127 completeJacobian(eBoundLoc1, eLinPhi) = -d0 / tanTheta;
0128
0129
0130 completeJacobian(eBoundPhi, eLinPhi) = 1.;
0131
0132
0133 completeJacobian(eBoundTheta, eLinTheta) = 1.;
0134
0135
0136 completeJacobian(eBoundQOverP, eLinQOverP) = 1.;
0137
0138
0139 completeJacobian(eBoundTime, eLinPos0) = -cosPhi / betaT;
0140 completeJacobian(eBoundTime, eLinPos1) = -sinPhi / betaT;
0141 completeJacobian(eBoundTime, eLinTime) = 1.;
0142 completeJacobian(eBoundTime, eLinPhi) = -d0 / betaT;
0143 } else {
0144
0145 double rho = sinTheta * (1. / qOvP) / Bz;
0146
0147 double h = (rho < 0.) ? -1 : 1;
0148
0149
0150 double X = pca(0) - perigeeSurface.center(gctx).x() + rho * sinPhi;
0151 double Y = pca(1) - perigeeSurface.center(gctx).y() - rho * cosPhi;
0152 double S2 = (X * X + Y * Y);
0153
0154
0155 double S = std::sqrt(S2);
0156
0157 double XoverS2 = X / S2;
0158 double YoverS2 = Y / S2;
0159 double rhoCotTheta = rho / tanTheta;
0160 double rhoOverBetaT = rho / betaT;
0161
0162 double absRhoOverS = h * rho / S;
0163
0164
0165
0166
0167
0168
0169
0170
0171 completeJacobian(eBoundLoc0, eLinPos0) = -h * X / S;
0172 completeJacobian(eBoundLoc0, eLinPos1) = -h * Y / S;
0173
0174
0175 completeJacobian(eBoundLoc1, eLinPos0) = rhoCotTheta * YoverS2;
0176 completeJacobian(eBoundLoc1, eLinPos1) = -rhoCotTheta * XoverS2;
0177 completeJacobian(eBoundLoc1, eLinPos2) = 1.;
0178 completeJacobian(eBoundLoc1, eLinPhi) = rhoCotTheta * (1. - absRhoOverS);
0179
0180
0181 completeJacobian(eBoundPhi, eLinPos0) = -YoverS2;
0182 completeJacobian(eBoundPhi, eLinPos1) = XoverS2;
0183 completeJacobian(eBoundPhi, eLinPhi) = absRhoOverS;
0184
0185
0186 completeJacobian(eBoundTheta, eLinTheta) = 1.;
0187
0188
0189 completeJacobian(eBoundQOverP, eLinQOverP) = 1.;
0190
0191
0192 completeJacobian(eBoundTime, eLinPos0) = rhoOverBetaT * YoverS2;
0193 completeJacobian(eBoundTime, eLinPos1) = -rhoOverBetaT * XoverS2;
0194 completeJacobian(eBoundTime, eLinTime) = 1.;
0195 completeJacobian(eBoundTime, eLinPhi) = rhoOverBetaT * (1. - absRhoOverS);
0196 }
0197
0198
0199 ActsMatrix<eBoundSize, eLinPosSize> positionJacobian =
0200 completeJacobian.block<eBoundSize, eLinPosSize>(0, 0);
0201 ActsMatrix<eBoundSize, eLinMomSize> momentumJacobian =
0202 completeJacobian.block<eBoundSize, eLinMomSize>(0, eLinPosSize);
0203
0204
0205 BoundVector constTerm =
0206 paramsAtPCA - positionJacobian * pca - momentumJacobian * momentumAtPCA;
0207
0208
0209 BoundSquareMatrix weightAtPCA = parCovarianceAtPCA.inverse();
0210
0211 Vector4 linPoint;
0212 linPoint.head<3>() = perigeeSurface.center(gctx);
0213 linPoint[3] = linPointTime;
0214
0215 return LinearizedTrack(paramsAtPCA, parCovarianceAtPCA, weightAtPCA, linPoint,
0216 positionJacobian, momentumJacobian, pca, momentumAtPCA,
0217 constTerm);
0218 }