File indexing completed on 2026-05-25 07:34:05
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "Acts/Seeding/EstimateTrackParamsFromSeed.hpp"
0010
0011 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/Definitions/TrackParametrization.hpp"
0013 #include "Acts/Utilities/MathHelpers.hpp"
0014
0015 #include <cmath>
0016
0017 namespace Acts {
0018
0019 namespace {
0020
0021 Transform3 estimationFrameLocalToGlobal(const Vector3& sp0, const Vector3& sp1,
0022 const Vector3& bField) {
0023
0024
0025
0026
0027
0028 const Vector3 relVec = sp1 - sp0;
0029 const Vector3 newZAxis = bField.normalized();
0030 const Vector3 newYAxis = newZAxis.cross(relVec).normalized();
0031 const Vector3 newXAxis = newYAxis.cross(newZAxis);
0032 RotationMatrix3 rotation;
0033 rotation.col(0) = newXAxis;
0034 rotation.col(1) = newYAxis;
0035 rotation.col(2) = newZAxis;
0036
0037 const Translation3 translation(sp0);
0038
0039 return translation * rotation;
0040 }
0041
0042 double computeDzDs(double A, double B, const Vector3& local0,
0043 const Vector3& local2) {
0044 const auto computeLocalPhi = [&](const Vector2& local) -> double {
0045
0046 const Vector2 r = 2 * B * local - Vector2(-A, 1);
0047
0048 return std::atan2(r.y(), r.x());
0049 };
0050
0051 const double localPhi0 = computeLocalPhi(local0.head<2>());
0052 const double localPhi2 = computeLocalPhi(local2.head<2>());
0053
0054 const double dZ = local2.z() - local0.z();
0055 const double dPhi = localPhi2 - localPhi0;
0056
0057
0058
0059
0060 const double sincCorrection = sinc(dPhi / 2);
0061
0062 const double dzds =
0063 sincCorrection * dZ / (local2.head<2>() - local0.head<2>()).norm();
0064
0065 return dzds;
0066 }
0067
0068 struct ConformalMappingResult {
0069 Vector2 uv1;
0070 Vector2 uv2;
0071 Vector2 duv;
0072 double A;
0073 double B;
0074 double bOverS;
0075 double dzds;
0076 };
0077
0078 ConformalMappingResult performConformalMapping(const Vector3& local1,
0079 const Vector3& local2) {
0080 ConformalMappingResult r{};
0081 r.uv1 = local1.head<2>() / local1.head<2>().squaredNorm();
0082 r.uv2 = local2.head<2>() / local2.head<2>().squaredNorm();
0083 r.duv = r.uv2 - r.uv1;
0084 r.A = r.duv.y() / r.duv.x();
0085 r.B = r.uv1.y() - r.A * r.uv1.x();
0086 r.bOverS = (r.uv1.y() * r.uv2.x() - r.uv2.y() * r.uv1.x()) / r.duv.norm();
0087 r.dzds = computeDzDs(r.A, r.B, local1, local2);
0088 return r;
0089 }
0090
0091 Vector3 computeLocalTangent(const ConformalMappingResult& cm,
0092 const Vector2& local) {
0093
0094 const Vector2 r = 2 * cm.B * local - Vector2(-cm.A, 1);
0095
0096
0097 const Vector3 t(-r.y(), r.x(), r.norm() * cm.dzds);
0098
0099 return t.normalized();
0100 }
0101
0102 }
0103
0104 }
0105
0106 Acts::FreeVector Acts::estimateTrackParamsFromSeed(const Vector3& sp0,
0107 const Vector3& sp1,
0108 const Vector3& sp2,
0109 const Vector3& bField) {
0110 return estimateTrackParamsFromSeed(sp0, 0, sp1, sp2, bField);
0111 }
0112
0113 Acts::FreeVector Acts::estimateTrackParamsFromSeed(
0114 const Vector3& sp0, const double t0, const Vector3& sp1, const Vector3& sp2,
0115 const Vector3& bField, Vector3* tangent0, Vector3* tangent1,
0116 Vector3* tangent2) {
0117 const Transform3 transform = estimationFrameLocalToGlobal(sp0, sp1, bField);
0118
0119
0120 const Vector3 local0 = Vector3::Zero();
0121 const Vector3 local1 = transform.inverse() * sp1;
0122 const Vector3 local2 = transform.inverse() * sp2;
0123
0124
0125 const ConformalMappingResult cm = performConformalMapping(local1, local2);
0126
0127
0128 const Vector3 direction =
0129 transform.linear() * computeLocalTangent(cm, local0.head<2>());
0130
0131
0132 FreeVector params = FreeVector::Zero();
0133
0134
0135 params.segment<3>(eFreePos0) = sp0;
0136
0137
0138 params.segment<3>(eFreeDir0) = direction;
0139
0140
0141
0142 const double qOverPt = 2 * cm.bOverS / bField.norm();
0143
0144 params[eFreeQOverP] = qOverPt / fastHypot(1, cm.dzds);
0145
0146
0147 params[eFreeTime] = t0;
0148
0149 if (tangent0 != nullptr) {
0150 *tangent0 = direction;
0151 }
0152 if (tangent1 != nullptr) {
0153 *tangent1 = transform.linear() * computeLocalTangent(cm, local1.head<2>());
0154 }
0155 if (tangent2 != nullptr) {
0156 *tangent2 = transform.linear() * computeLocalTangent(cm, local2.head<2>());
0157 }
0158
0159 return params;
0160 }
0161
0162 Acts::Result<Acts::BoundVector> Acts::estimateTrackParamsFromSeed(
0163 const GeometryContext& gctx, const Surface& surface, const Vector3& sp0,
0164 const double t0, const Vector3& sp1, const Vector3& sp2,
0165 const Vector3& bField) {
0166 const FreeVector freeParams =
0167 estimateTrackParamsFromSeed(sp0, t0, sp1, sp2, bField);
0168 return transformFreeToBoundParameters(freeParams, surface, gctx);
0169 }
0170
0171 Acts::BoundMatrix Acts::estimateTrackParamCovariance(
0172 const EstimateTrackParamCovarianceConfig& config, const BoundVector& params,
0173 bool hasTime) {
0174 assert((params[eBoundTheta] > 0 && params[eBoundTheta] < std::numbers::pi) &&
0175 "Theta must be in the range (0, pi)");
0176
0177 BoundMatrix result = BoundMatrix::Zero();
0178
0179 for (std::size_t i = eBoundLoc0; i < eBoundSize; ++i) {
0180 double sigma = config.initialSigmas[i];
0181 double variance = sigma * sigma;
0182
0183 if (i == eBoundQOverP) {
0184
0185 double varianceTheta = result(eBoundTheta, eBoundTheta);
0186
0187
0188 variance += std::pow(
0189 config.initialSigmaQoverPt * std::sin(params[eBoundTheta]), 2);
0190
0191
0192 variance += std::pow(config.initialSigmaPtRel * params[eBoundQOverP], 2);
0193
0194
0195 variance +=
0196 varianceTheta *
0197 std::pow(params[eBoundQOverP] / std::tan(params[eBoundTheta]), 2);
0198 }
0199
0200 if (i == eBoundTime && !hasTime) {
0201
0202 variance *= config.noTimeVarInflation;
0203 }
0204
0205
0206 variance *= config.initialVarInflation[i];
0207
0208 result(i, i) = variance;
0209 }
0210
0211 return result;
0212 }