Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-25 07:34:05

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
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   // Define a new coordinate frame with its origin at the bottom space point, z
0024   // axis long the magnetic field direction and y axis perpendicular to vector
0025   // from the bottom to middle space point. Hence, the projection of the middle
0026   // space point on the transverse plane will be located at the x axis of the
0027   // new frame.
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   // The center of the new frame is at the bottom space point
0037   const Translation3 translation(sp0);
0038   // The transform which constructs the new frame
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     // Scaled radius vector from circle center
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   // Apply the sinc correction to account for the fact that the particle do not
0058   // follow a straight line in the R-Z plane. This is especially important for
0059   // high delta phi and/or strongly bent tracks.
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   // Scaled radius vector from circle center
0094   const Vector2 r = 2 * cm.B * local - Vector2(-cm.A, 1);
0095 
0096   // Tangent perpendicular to radius
0097   const Vector3 t(-r.y(), r.x(), r.norm() * cm.dzds);
0098 
0099   return t.normalized();
0100 }
0101 
0102 }  // namespace
0103 
0104 }  // namespace Acts
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   // Local coordinates
0120   const Vector3 local0 = Vector3::Zero();
0121   const Vector3 local1 = transform.inverse() * sp1;
0122   const Vector3 local2 = transform.inverse() * sp2;
0123 
0124   // Conformal mapping
0125   const ConformalMappingResult cm = performConformalMapping(local1, local2);
0126 
0127   // The tangent vector at the bottom space point
0128   const Vector3 direction =
0129       transform.linear() * computeLocalTangent(cm, local0.head<2>());
0130 
0131   // Initialize the free parameters vector
0132   FreeVector params = FreeVector::Zero();
0133 
0134   // The bottom space point position
0135   params.segment<3>(eFreePos0) = sp0;
0136 
0137   // The estimated direction
0138   params.segment<3>(eFreeDir0) = direction;
0139 
0140   // The estimated q/pt in [GeV/c]^-1 (note that the pt is the projection of
0141   // momentum on the transverse plane of the new frame)
0142   const double qOverPt = 2 * cm.bOverS / bField.norm();
0143   // The estimated q/p in [GeV/c]^-1
0144   params[eFreeQOverP] = qOverPt / fastHypot(1, cm.dzds);
0145 
0146   // The time parameter is set to the time of the bottom space point
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       // note that we rely on the fact that sigma theta is already computed
0185       double varianceTheta = result(eBoundTheta, eBoundTheta);
0186 
0187       // contribution from sigma(q/pt)
0188       variance += std::pow(
0189           config.initialSigmaQoverPt * std::sin(params[eBoundTheta]), 2);
0190 
0191       // contribution from sigma(pt)/pt
0192       variance += std::pow(config.initialSigmaPtRel * params[eBoundQOverP], 2);
0193 
0194       // contribution from sigma(theta)
0195       variance +=
0196           varianceTheta *
0197           std::pow(params[eBoundQOverP] / std::tan(params[eBoundTheta]), 2);
0198     }
0199 
0200     if (i == eBoundTime && !hasTime) {
0201       // Inflate the time uncertainty if no time measurement is available
0202       variance *= config.noTimeVarInflation;
0203     }
0204 
0205     // Inflate the initial covariance
0206     variance *= config.initialVarInflation[i];
0207 
0208     result(i, i) = variance;
0209   }
0210 
0211   return result;
0212 }