File indexing completed on 2025-10-20 07:58:35
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "Acts/EventData/detail/CorrectedTransformationFreeToBound.hpp"
0010
0011 #include "Acts/Definitions/TrackParametrization.hpp"
0012 #include "Acts/EventData/TransformationHelpers.hpp"
0013 #include "Acts/Surfaces/Surface.hpp"
0014 #include "Acts/Utilities/Intersection.hpp"
0015 #include "Acts/Utilities/Result.hpp"
0016
0017 #include <cmath>
0018 #include <cstddef>
0019 #include <ostream>
0020 #include <utility>
0021 #include <vector>
0022
0023 Acts::FreeToBoundCorrection::FreeToBoundCorrection(bool apply_, double alpha_,
0024 double beta_)
0025 : apply(apply_), alpha(alpha_), beta(beta_) {}
0026
0027 Acts::FreeToBoundCorrection::FreeToBoundCorrection(bool apply_)
0028 : apply(apply_) {}
0029
0030 Acts::FreeToBoundCorrection::operator bool() const {
0031 return apply;
0032 }
0033
0034 Acts::detail::CorrectedFreeToBoundTransformer::CorrectedFreeToBoundTransformer(
0035 double alpha, double beta, double cosIncidentAngleMinCutoff,
0036 double cosIncidentAngleMaxCutoff)
0037 : m_alpha(alpha),
0038 m_beta(beta),
0039 m_cosIncidentAngleMinCutoff(cosIncidentAngleMinCutoff),
0040 m_cosIncidentAngleMaxCutoff(cosIncidentAngleMaxCutoff) {}
0041
0042 Acts::detail::CorrectedFreeToBoundTransformer::CorrectedFreeToBoundTransformer(
0043 const FreeToBoundCorrection& freeToBoundCorrection) {
0044 m_alpha = freeToBoundCorrection.alpha;
0045 m_beta = freeToBoundCorrection.beta;
0046 m_cosIncidentAngleMinCutoff = freeToBoundCorrection.cosIncidentAngleMinCutoff;
0047 m_cosIncidentAngleMaxCutoff = freeToBoundCorrection.cosIncidentAngleMaxCutoff;
0048 }
0049
0050 std::optional<std::tuple<Acts::BoundVector, Acts::BoundSquareMatrix>>
0051 Acts::detail::CorrectedFreeToBoundTransformer::operator()(
0052 const Acts::FreeVector& freeParams,
0053 const Acts::FreeSquareMatrix& freeCovariance, const Acts::Surface& surface,
0054 const Acts::GeometryContext& geoContext, Direction navDir,
0055 const Logger& logger) const {
0056
0057 Vector3 dir = freeParams.segment<3>(eFreeDir0);
0058 Vector3 normal =
0059 surface.normal(geoContext, freeParams.segment<3>(eFreePos0), dir);
0060 double absCosIncidenceAng = std::abs(dir.dot(normal));
0061
0062
0063
0064 if (absCosIncidenceAng < m_cosIncidentAngleMinCutoff ||
0065 absCosIncidenceAng > m_cosIncidentAngleMaxCutoff) {
0066 ACTS_VERBOSE("Incident angle: " << std::acos(absCosIncidenceAng)
0067 << " is out of range for correction");
0068 return std::nullopt;
0069 }
0070
0071
0072 std::size_t sampleSize = 2 * eFreeSize + 1;
0073
0074
0075 std::vector<std::tuple<FreeVector, double, double>> sampledFreeParams;
0076 sampledFreeParams.reserve(sampleSize);
0077
0078
0079 FreeSquareMatrix covSqrt = FreeSquareMatrix::Zero();
0080
0081 Eigen::JacobiSVD<FreeSquareMatrix> svd(
0082 freeCovariance, Eigen::ComputeFullU | Eigen::ComputeFullV);
0083 auto S = svd.singularValues();
0084 FreeMatrix U = svd.matrixU();
0085
0086 FreeMatrix D = FreeMatrix::Zero();
0087 for (unsigned i = 0; i < eFreeSize; ++i) {
0088 if (S(i) > 0) {
0089 D(i, i) = std::sqrt(S(i));
0090 }
0091 }
0092
0093 covSqrt = U * D;
0094
0095
0096 double kappa = m_alpha * m_alpha * static_cast<double>(eFreeSize);
0097
0098 double lambda = kappa - static_cast<double>(eFreeSize);
0099
0100 double gamma = std::sqrt(kappa);
0101
0102
0103
0104 sampledFreeParams.push_back(
0105 {freeParams, lambda / kappa,
0106 lambda / kappa + (1.0 - m_alpha * m_alpha + m_beta)});
0107
0108 for (unsigned i = 0; i < eFreeSize; ++i) {
0109 sampledFreeParams.push_back(
0110 {freeParams + covSqrt.col(i) * gamma, 0.5 / kappa, 0.5 / kappa});
0111 sampledFreeParams.push_back(
0112 {freeParams - covSqrt.col(i) * gamma, 0.5 / kappa, 0.5 / kappa});
0113 }
0114
0115
0116 BoundVector bpMean = BoundVector::Zero();
0117
0118 BoundSquareMatrix bv = BoundSquareMatrix::Zero();
0119
0120
0121
0122 std::vector<std::pair<BoundVector, double>> transformedBoundParams;
0123
0124
0125
0126
0127 const auto& [paramsNom, mweightNom, cweightNom] = sampledFreeParams[0];
0128
0129 auto nominalRes =
0130 transformFreeToBoundParameters(paramsNom, surface, geoContext);
0131
0132 if (!nominalRes.ok()) {
0133 ACTS_WARNING(
0134 "Free to bound transformation for nominal free parameters failed.");
0135 return std::nullopt;
0136 }
0137 auto nominalBound = nominalRes.value();
0138 transformedBoundParams.push_back({nominalBound, cweightNom});
0139 bpMean = bpMean + mweightNom * nominalBound;
0140
0141
0142
0143 for (unsigned i = 1; i < sampledFreeParams.size(); ++i) {
0144 const auto& [params, mweight, cweight] = sampledFreeParams[i];
0145 FreeVector correctedFreeParams = params;
0146
0147
0148 Intersection3D intersection =
0149 surface
0150 .intersect(geoContext, params.segment<3>(eFreePos0),
0151 navDir * params.segment<3>(eFreeDir0),
0152 BoundaryTolerance::Infinite())
0153 .closest();
0154 correctedFreeParams.segment<3>(eFreePos0) = intersection.position();
0155
0156
0157 auto result = transformFreeToBoundParameters(correctedFreeParams, surface,
0158 geoContext);
0159
0160 if (!result.ok()) {
0161 ACTS_WARNING(
0162 "Free to bound transformation for sampled free parameters: \n"
0163 << correctedFreeParams << " failed.");
0164 return std::nullopt;
0165 }
0166
0167 auto bp = result.value();
0168 transformedBoundParams.push_back({bp, cweight});
0169 bpMean = bpMean + mweight * bp;
0170 }
0171
0172
0173 for (unsigned isample = 0; isample < sampleSize; ++isample) {
0174 BoundVector bSigma = transformedBoundParams[isample].first - bpMean;
0175
0176 bv = bv +
0177 transformedBoundParams[isample].second * bSigma * bSigma.transpose();
0178 }
0179
0180 return std::make_tuple(bpMean, bv);
0181 }