File indexing completed on 2026-04-01 07:45:43
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011 #include "Acts/Definitions/Tolerance.hpp"
0012 #include "Acts/EventData/ParticleHypothesis.hpp"
0013 #include "Acts/EventData/TrackParameterHelpers.hpp"
0014 #include "Acts/EventData/TransformationHelpers.hpp"
0015 #include "Acts/EventData/detail/PrintParameters.hpp"
0016 #include "Acts/Surfaces/CurvilinearSurface.hpp"
0017 #include "Acts/Surfaces/Surface.hpp"
0018 #include "Acts/Utilities/UnitVectors.hpp"
0019 #include "Acts/Utilities/detail/periodic.hpp"
0020
0021 #include <cassert>
0022 #include <cmath>
0023 #include <memory>
0024
0025 namespace Acts {
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036 class BoundTrackParameters {
0037 public:
0038
0039 using ParametersVector = BoundVector;
0040
0041 using CovarianceMatrix = BoundMatrix;
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058 static Result<BoundTrackParameters> create(
0059 const GeometryContext& geoCtx, std::shared_ptr<const Surface> surface,
0060 const Vector4& pos4, const Vector3& dir, double qOverP,
0061 std::optional<BoundMatrix> cov, ParticleHypothesis particleHypothesis,
0062 double tolerance = s_onSurfaceTolerance) {
0063 Result<BoundVector> bound =
0064 transformFreeToBoundParameters(pos4.segment<3>(ePos0), pos4[eTime], dir,
0065 qOverP, *surface, geoCtx, tolerance);
0066
0067 if (!bound.ok()) {
0068 return bound.error();
0069 }
0070
0071 return BoundTrackParameters{std::move(surface), *bound, std::move(cov),
0072 particleHypothesis};
0073 }
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083 static BoundTrackParameters createCurvilinear(
0084 const Vector4& pos4, const Vector3& dir, double qOverP,
0085 std::optional<BoundMatrix> cov, ParticleHypothesis particleHypothesis) {
0086 return BoundTrackParameters(
0087 CurvilinearSurface(pos4.segment<3>(ePos0), dir).surface(),
0088 transformFreeToCurvilinearParameters(pos4[eTime], dir, qOverP),
0089 std::move(cov), particleHypothesis);
0090 }
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101 static BoundTrackParameters createCurvilinear(
0102 const Vector4& pos4, double phi, double theta, double qOverP,
0103 std::optional<BoundMatrix> cov, ParticleHypothesis particleHypothesis) {
0104 return BoundTrackParameters(
0105 CurvilinearSurface(pos4.segment<3>(ePos0),
0106 makeDirectionFromPhiTheta(phi, theta))
0107 .surface(),
0108 transformFreeToCurvilinearParameters(pos4[eTime], phi, theta, qOverP),
0109 std::move(cov), particleHypothesis);
0110 }
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124 BoundTrackParameters(std::shared_ptr<const Surface> surface,
0125 const BoundVector& params,
0126 std::optional<BoundMatrix> cov,
0127 ParticleHypothesis particleHypothesis)
0128 : m_params(params),
0129 m_cov(std::move(cov)),
0130 m_surface(std::move(surface)),
0131 m_particleHypothesis(particleHypothesis) {
0132
0133 assert(isBoundVectorValid(m_params, false) &&
0134 "Invalid bound parameters vector");
0135 assert(m_surface != nullptr && "Reference surface must not be null");
0136 normalizePhiTheta();
0137 }
0138
0139
0140
0141 [[deprecated(
0142 "You already have a universal bound track parameter at hand. You can "
0143 "drop `toBound()`.")]]
0144 BoundTrackParameters toBound() const {
0145 return BoundTrackParameters{*this};
0146 }
0147
0148
0149
0150 BoundVector& parameters() { return m_params; }
0151
0152
0153 const BoundVector& parameters() const { return m_params; }
0154
0155
0156 Vector2 spatialImpactParameters() const { return m_params.head<2>(); }
0157
0158
0159 Vector3 impactParameters() const {
0160 Vector3 ip;
0161 ip.template head<2>() = m_params.template head<2>();
0162 ip(2) = m_params(eBoundTime);
0163 return ip;
0164 }
0165
0166
0167
0168 std::optional<BoundMatrix>& covariance() { return m_cov; }
0169
0170
0171 const std::optional<BoundMatrix>& covariance() const { return m_cov; }
0172
0173
0174 std::optional<SquareMatrix<2>> spatialImpactParameterCovariance() const {
0175 if (!m_cov.has_value()) {
0176 return std::nullopt;
0177 }
0178
0179 return m_cov.value().template topLeftCorner<2, 2>();
0180 }
0181
0182
0183
0184
0185 std::optional<SquareMatrix<3>> impactParameterCovariance() const {
0186 if (!m_cov.has_value()) {
0187 return std::nullopt;
0188 }
0189
0190 SquareMatrix<3> ipCov;
0191 ipCov.template topLeftCorner<2, 2>() =
0192 m_cov.value().template topLeftCorner<2, 2>();
0193 ipCov.template block<2, 1>(0, 2) =
0194 m_cov.value().template block<2, 1>(0, eBoundTime);
0195 ipCov.template block<1, 2>(2, 0) =
0196 m_cov.value().template block<1, 2>(eBoundTime, 0);
0197 ipCov(2, 2) = m_cov.value()(eBoundTime, eBoundTime);
0198 return ipCov;
0199 }
0200
0201
0202
0203
0204
0205 template <BoundIndices kIndex>
0206 double get() const {
0207 return m_params[kIndex];
0208 }
0209
0210
0211
0212 Vector2 localPosition() const { return m_params.segment<2>(eBoundLoc0); }
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222
0223
0224 Vector4 fourPosition(const GeometryContext& geoCtx) const {
0225 Vector4 pos4;
0226 pos4.segment<3>(ePos0) =
0227 m_surface->localToGlobal(geoCtx, localPosition(), direction());
0228 pos4[eTime] = m_params[eBoundTime];
0229 return pos4;
0230 }
0231
0232
0233
0234
0235
0236
0237
0238
0239
0240
0241
0242 Vector3 position(const GeometryContext& geoCtx) const {
0243 return m_surface->localToGlobal(geoCtx, localPosition(), direction());
0244 }
0245
0246
0247 double time() const { return m_params[eBoundTime]; }
0248
0249
0250
0251 double phi() const { return m_params[eBoundPhi]; }
0252
0253
0254 double theta() const { return m_params[eBoundTheta]; }
0255
0256
0257 double qOverP() const { return m_params[eBoundQOverP]; }
0258
0259
0260
0261
0262 Vector3 direction() const {
0263 return makeDirectionFromPhiTheta(m_params[eBoundPhi],
0264 m_params[eBoundTheta]);
0265 }
0266
0267
0268 double absoluteMomentum() const {
0269 return m_particleHypothesis.extractMomentum(m_params[eBoundQOverP]);
0270 }
0271
0272
0273 double transverseMomentum() const {
0274 return std::sin(m_params[eBoundTheta]) * absoluteMomentum();
0275 }
0276
0277
0278 Vector3 momentum() const { return absoluteMomentum() * direction(); }
0279
0280
0281
0282 double charge() const {
0283 return m_particleHypothesis.extractCharge(get<eBoundQOverP>());
0284 }
0285
0286
0287
0288 const ParticleHypothesis& particleHypothesis() const {
0289 return m_particleHypothesis;
0290 }
0291
0292
0293
0294 const Surface& referenceSurface() const { return *m_surface; }
0295
0296
0297
0298
0299
0300
0301
0302
0303
0304
0305 RotationMatrix3 referenceFrame(const GeometryContext& geoCtx) const {
0306 return m_surface->referenceFrame(geoCtx, position(geoCtx), momentum());
0307 }
0308
0309
0310 void reflectInPlace() { m_params = reflectBoundParameters(m_params); }
0311
0312
0313
0314 BoundTrackParameters reflect() const {
0315 BoundTrackParameters reflected = *this;
0316 reflected.reflectInPlace();
0317 return reflected;
0318 }
0319
0320 private:
0321 BoundVector m_params;
0322 std::optional<BoundMatrix> m_cov;
0323
0324 std::shared_ptr<const Surface> m_surface;
0325
0326 ParticleHypothesis m_particleHypothesis;
0327
0328
0329 void normalizePhiTheta() {
0330 auto [phi, theta] =
0331 detail::normalizePhiTheta(m_params[eBoundPhi], m_params[eBoundTheta]);
0332 m_params[eBoundPhi] = phi;
0333 m_params[eBoundTheta] = theta;
0334 }
0335
0336
0337
0338
0339
0340
0341
0342
0343
0344
0345
0346 friend bool operator==(const BoundTrackParameters& lhs,
0347 const BoundTrackParameters& rhs) = default;
0348
0349
0350 friend std::ostream& operator<<(std::ostream& os,
0351 const BoundTrackParameters& tp) {
0352 detail::printBoundParameters(
0353 os, tp.referenceSurface(), tp.particleHypothesis(), tp.parameters(),
0354 tp.covariance().has_value() ? &tp.covariance().value() : nullptr);
0355 return os;
0356 }
0357 };
0358
0359 }