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