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