Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
CorrectedTransformationFreeToBound.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file CorrectedTransformationFreeToBound.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2021-2022 CERN for the benefit of the Acts project
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 
10 
15 
16 #include <algorithm>
17 #include <cmath>
18 #include <cstddef>
19 #include <memory>
20 #include <ostream>
21 #include <type_traits>
22 #include <utility>
23 #include <vector>
24 
26  ActsScalar alpha_,
27  ActsScalar beta_)
28  : apply(apply_), alpha(alpha_), beta(beta_) {}
29 
31  : apply(apply_) {}
32 
33 Acts::FreeToBoundCorrection::operator bool() const {
34  return apply;
35 }
36 
38  ActsScalar alpha, ActsScalar beta, ActsScalar cosIncidentAngleMinCutoff,
39  ActsScalar cosIncidentAngleMaxCutoff)
40  : m_alpha(alpha),
41  m_beta(beta),
42  m_cosIncidentAngleMinCutoff(cosIncidentAngleMinCutoff),
43  m_cosIncidentAngleMaxCutoff(cosIncidentAngleMaxCutoff) {}
44 
46  const FreeToBoundCorrection& freeToBoundCorrection) {
47  m_alpha = freeToBoundCorrection.alpha;
48  m_beta = freeToBoundCorrection.beta;
49  m_cosIncidentAngleMinCutoff = freeToBoundCorrection.cosIncidentAngleMinCutoff;
50  m_cosIncidentAngleMaxCutoff = freeToBoundCorrection.cosIncidentAngleMaxCutoff;
51 }
52 
53 std::optional<std::tuple<Acts::BoundVector, Acts::BoundSquareMatrix>>
55  const Acts::FreeVector& freeParams,
56  const Acts::FreeSquareMatrix& freeCovariance, const Acts::Surface& surface,
58  const Logger& logger) const {
59  // Get the incidence angle
60  Vector3 dir = freeParams.segment<3>(eFreeDir0);
61  Vector3 normal = surface.normal(geoContext);
62  ActsScalar absCosIncidenceAng = std::abs(dir.dot(normal));
63  // No correction if the incidentAngle is small enough (not necessary ) or too
64  // large (correction could be invalid). Fall back to nominal free to bound
65  // transformation
66  if (absCosIncidenceAng < m_cosIncidentAngleMinCutoff or
67  absCosIncidenceAng > m_cosIncidentAngleMaxCutoff) {
68  ACTS_VERBOSE("Incident angle: " << std::acos(absCosIncidenceAng)
69  << " is out of range for correction");
70  return std::nullopt;
71  }
72 
73  // The number of sigma points
74  size_t sampleSize = 2 * eFreeSize + 1;
75  // The sampled free parameters, the weight for measurement W_m and weight for
76  // covariance, W_c
77  std::vector<std::tuple<FreeVector, ActsScalar, ActsScalar>> sampledFreeParams;
78  sampledFreeParams.reserve(sampleSize);
79 
80  // Initialize the covariance sqrt root matrix
81  FreeSquareMatrix covSqrt = FreeSquareMatrix::Zero();
82  // SVD decomposition: freeCovariance = U*S*U^T here
83  Eigen::JacobiSVD<FreeSquareMatrix> svd(
84  freeCovariance, Eigen::ComputeFullU | Eigen::ComputeFullV);
85  auto S = svd.singularValues();
86  FreeMatrix U = svd.matrixU();
87  // Get the sqrt root matrix of S
88  FreeMatrix D = FreeMatrix::Zero();
89  for (unsigned i = 0; i < eFreeSize; ++i) {
90  if (S(i) > 0) {
91  D(i, i) = std::sqrt(S(i));
92  }
93  }
94  // Get the covariance sqrt root matrix
95  covSqrt = U * D;
96 
97  // Define kappa = alpha*alpha*N
98  ActsScalar kappa = m_alpha * m_alpha * static_cast<double>(eFreeSize);
99  // lambda = alpha*alpha*N - N
100  ActsScalar lambda = kappa - static_cast<double>(eFreeSize);
101  // gamma = sqrt(labmda + N)
102  ActsScalar gamma = std::sqrt(kappa);
103 
104  // Sample the free parameters
105  // 1. the nominal parameter
106  sampledFreeParams.push_back(
107  {freeParams, lambda / kappa,
108  lambda / kappa + (1.0 - m_alpha * m_alpha + m_beta)});
109  // 2. the shifted parameters
110  for (unsigned i = 0; i < eFreeSize; ++i) {
111  sampledFreeParams.push_back(
112  {freeParams + covSqrt.col(i) * gamma, 0.5 / kappa, 0.5 / kappa});
113  sampledFreeParams.push_back(
114  {freeParams - covSqrt.col(i) * gamma, 0.5 / kappa, 0.5 / kappa});
115  }
116 
117  // Initialize the mean of the bound parameters
118  BoundVector bpMean = BoundVector::Zero();
119  // Initialize the bound covariance
120  BoundSquareMatrix bv = BoundSquareMatrix::Zero();
121 
122  // The transformed bound parameters and weight for each sampled free
123  // parameters
124  std::vector<std::pair<BoundVector, ActsScalar>> transformedBoundParams;
125 
126  // 1. The nominal one
127  // The sampled free parameters, the weight for measurement W_m and weight for
128  // covariance, W_c
129  const auto& [paramsNom, mweightNom, cweightNom] = sampledFreeParams[0];
130  // Transform the free to bound
131  auto nominalRes =
132  detail::transformFreeToBoundParameters(paramsNom, surface, geoContext);
133  // Not successful, fall back to nominal free to bound transformation
134  if (not nominalRes.ok()) {
135  ACTS_WARNING(
136  "Free to bound transformation for nominal free parameters failed.");
137  return std::nullopt;
138  }
139  auto nominalBound = nominalRes.value();
140  transformedBoundParams.push_back({nominalBound, cweightNom});
141  bpMean = bpMean + mweightNom * nominalBound;
142 
143  // 2. Loop over the rest sample points of the free parameters to get the
144  // corrected bound parameters
145  for (unsigned i = 1; i < sampledFreeParams.size(); ++i) {
146  const auto& [params, mweight, cweight] = sampledFreeParams[i];
147  FreeVector correctedFreeParams = params;
148 
149  // Reintersect to get the corrected free params without boundary check
150  SurfaceIntersection intersection =
151  surface
152  .intersect(geoContext, params.segment<3>(eFreePos0),
153  navDir * params.segment<3>(eFreeDir0), false)
154  .closest();
155  correctedFreeParams.segment<3>(eFreePos0) = intersection.position();
156 
157  // Transform the free to bound
158  auto result = detail::transformFreeToBoundParameters(correctedFreeParams,
159  surface, geoContext);
160  // Not successful, fall back to nominal free to bound transformation
161  if (not result.ok()) {
162  ACTS_WARNING(
163  "Free to bound transformation for sampled free parameters: \n"
164  << correctedFreeParams << " failed.");
165  return std::nullopt;
166  }
167 
168  auto bp = result.value();
169  transformedBoundParams.push_back({bp, cweight});
170  bpMean = bpMean + mweight * bp;
171  }
172 
173  // Get the corrected bound covariance
174  for (unsigned isample = 0; isample < sampleSize; ++isample) {
175  BoundVector bSigma = transformedBoundParams[isample].first - bpMean;
176 
177  bv = bv +
178  transformedBoundParams[isample].second * bSigma * bSigma.transpose();
179  }
180 
181  return std::make_tuple(bpMean, bv);
182 }