File indexing completed on 2025-01-18 09:10:58
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "Acts/Definitions/TrackParametrization.hpp"
0010
0011 #include <numbers>
0012
0013 template <typename propagator_t>
0014 template <typename parameters_t, typename propagator_options_t>
0015 auto Acts::RiddersPropagator<propagator_t>::propagate(
0016 const parameters_t& start, const propagator_options_t& options) const
0017 -> Result<
0018 actor_list_t_result_t<CurvilinearTrackParameters,
0019 typename propagator_options_t::actor_list_type>> {
0020 using ThisResult = Result<
0021 actor_list_t_result_t<CurvilinearTrackParameters,
0022 typename propagator_options_t::actor_list_type>>;
0023
0024
0025
0026 CurvilinearTrackParameters startWithoutCov = start;
0027 startWithoutCov.covariance() = std::nullopt;
0028
0029
0030 auto result = m_propagator.propagate(startWithoutCov, options);
0031 if (!result.ok()) {
0032 return ThisResult::failure(result.error());
0033 }
0034
0035 auto nominalResult = result.value();
0036 assert(nominalResult.endParameters);
0037 const auto& nominalFinalParameters = *nominalResult.endParameters;
0038
0039 Jacobian jacobian = wiggleAndCalculateJacobian(options, start, nominalResult);
0040 nominalResult.transportJacobian = jacobian;
0041
0042 if (start.covariance()) {
0043
0044 auto cov = jacobian * (*start.covariance()) * jacobian.transpose();
0045
0046 nominalResult.endParameters = CurvilinearTrackParameters(
0047 nominalFinalParameters.fourPosition(options.geoContext),
0048 nominalFinalParameters.direction(), nominalFinalParameters.qOverP(),
0049 std::move(cov), nominalFinalParameters.particleHypothesis());
0050 }
0051
0052 return ThisResult::success(std::move(nominalResult));
0053 }
0054
0055 template <typename propagator_t>
0056 template <typename parameters_t, typename propagator_options_t>
0057 auto Acts::RiddersPropagator<propagator_t>::propagate(
0058 const parameters_t& start, const Surface& target,
0059 const propagator_options_t& options) const
0060 -> Result<actor_list_t_result_t<
0061 BoundTrackParameters, typename propagator_options_t::actor_list_type>> {
0062 using ThisResult = Result<actor_list_t_result_t<
0063 BoundTrackParameters, typename propagator_options_t::actor_list_type>>;
0064
0065
0066
0067 BoundTrackParameters startWithoutCov = start;
0068 startWithoutCov.covariance() = std::nullopt;
0069
0070
0071 auto result = m_propagator.propagate(startWithoutCov, target, options);
0072 if (!result.ok()) {
0073 return ThisResult::failure(result.error());
0074 }
0075
0076 auto nominalResult = result.value();
0077 assert(nominalResult.endParameters);
0078 const auto& nominalFinalParameters = *nominalResult.endParameters;
0079
0080 Jacobian jacobian = wiggleAndCalculateJacobian(options, start, nominalResult);
0081 nominalResult.transportJacobian = jacobian;
0082
0083 if (start.covariance()) {
0084
0085 auto cov = jacobian * (*start.covariance()) * jacobian.transpose();
0086
0087 nominalResult.endParameters = BoundTrackParameters(
0088 nominalFinalParameters.referenceSurface().getSharedPtr(),
0089 nominalFinalParameters.parameters(), std::move(cov),
0090 nominalFinalParameters.particleHypothesis());
0091 }
0092
0093 return ThisResult::success(std::move(nominalResult));
0094 }
0095
0096 template <typename propagator_t>
0097 template <typename propagator_options_t, typename parameters_t,
0098 typename result_t>
0099 auto Acts::RiddersPropagator<propagator_t>::wiggleAndCalculateJacobian(
0100 const propagator_options_t& options, const parameters_t& start,
0101 result_t& nominalResult) const -> Jacobian {
0102 auto nominalFinalParameters = *nominalResult.endParameters;
0103
0104 const Surface& target = nominalFinalParameters.referenceSurface();
0105
0106
0107
0108 const std::vector<double>* deviations = &m_config.deviations;
0109 if (target.type() == Surface::Disc) {
0110 deviations = &m_config.deviationsDisc;
0111 }
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123 propagator_options_t opts = options;
0124 opts.pathLimit *= 2.;
0125
0126
0127 std::array<std::vector<BoundVector>, eBoundSize> derivatives;
0128
0129
0130 for (unsigned int i = 0; i < eBoundSize; i++) {
0131 derivatives[i] =
0132 wiggleParameter(opts, start, i, target,
0133 nominalFinalParameters.parameters(), *deviations);
0134 }
0135
0136
0137 if (target.type() == Surface::Disc) {
0138 for ([[maybe_unused]] const auto& d : derivatives) {
0139 assert(!inconsistentDerivativesOnDisc(d));
0140 }
0141 }
0142
0143 return calculateJacobian(*deviations, derivatives);
0144 }
0145
0146 template <typename propagator_t>
0147 bool Acts::RiddersPropagator<propagator_t>::inconsistentDerivativesOnDisc(
0148 const std::vector<Acts::BoundVector>& derivatives) {
0149
0150 for (unsigned int i = 0; i < derivatives.size(); i++) {
0151 bool jumpedAngle = true;
0152 for (unsigned int j = 0; j < derivatives.size(); j++) {
0153
0154
0155 if (i != j && std::abs(derivatives[i](1) - derivatives[j](1)) <
0156 std::numbers::pi / 2.) {
0157 jumpedAngle = false;
0158 break;
0159 }
0160 }
0161
0162 if (jumpedAngle) {
0163 return true;
0164 }
0165 }
0166 return false;
0167 }
0168
0169 template <typename propagator_t>
0170 template <typename propagator_options_t, typename parameters_t>
0171 std::vector<Acts::BoundVector>
0172 Acts::RiddersPropagator<propagator_t>::wiggleParameter(
0173 const propagator_options_t& options, const parameters_t& start,
0174 const unsigned int param, const Surface& target,
0175 const Acts::BoundVector& nominal,
0176 const std::vector<double>& deviations) const {
0177
0178 std::vector<BoundVector> derivatives;
0179 derivatives.reserve(deviations.size());
0180 for (double h : deviations) {
0181
0182 if (param == eBoundTheta) {
0183 const double current_theta = start.template get<eBoundTheta>();
0184 if (current_theta + h > std::numbers::pi) {
0185 h = std::numbers::pi - current_theta;
0186 }
0187 if (current_theta + h < 0) {
0188 h = -current_theta;
0189 }
0190 }
0191
0192
0193 BoundVector values = start.parameters();
0194 values[param] += h;
0195
0196
0197 BoundTrackParameters tp(start.referenceSurface().getSharedPtr(), values,
0198 start.covariance(), start.particleHypothesis());
0199 const auto& r = m_propagator.propagate(tp, target, options).value();
0200
0201 derivatives.push_back((r.endParameters->parameters() - nominal) / h);
0202
0203
0204 if (param == eBoundPhi) {
0205 double phi0 = nominal(Acts::eBoundPhi);
0206 double phi1 = r.endParameters->parameters()(Acts::eBoundPhi);
0207 if (std::abs(phi1 + 2. * std::numbers::pi - phi0) <
0208 std::abs(phi1 - phi0)) {
0209 derivatives.back()[Acts::eBoundPhi] =
0210 (phi1 + 2. * std::numbers::pi - phi0) / h;
0211 } else if (std::abs(phi1 - 2. * std::numbers::pi - phi0) <
0212 std::abs(phi1 - phi0)) {
0213 derivatives.back()[Acts::eBoundPhi] =
0214 (phi1 - 2. * std::numbers::pi - phi0) / h;
0215 }
0216 }
0217 }
0218
0219 return derivatives;
0220 }
0221
0222 template <typename propagator_t>
0223 auto Acts::RiddersPropagator<propagator_t>::calculateJacobian(
0224 const std::vector<double>& deviations,
0225 const std::array<std::vector<Acts::BoundVector>, Acts::eBoundSize>&
0226 derivatives) -> Jacobian {
0227 Jacobian jacobian;
0228 jacobian.col(eBoundLoc0) = fitLinear(deviations, derivatives[eBoundLoc0]);
0229 jacobian.col(eBoundLoc1) = fitLinear(deviations, derivatives[eBoundLoc1]);
0230 jacobian.col(eBoundPhi) = fitLinear(deviations, derivatives[eBoundPhi]);
0231 jacobian.col(eBoundTheta) = fitLinear(deviations, derivatives[eBoundTheta]);
0232 jacobian.col(eBoundQOverP) = fitLinear(deviations, derivatives[eBoundQOverP]);
0233 jacobian.col(eBoundTime) = fitLinear(deviations, derivatives[eBoundTime]);
0234 return jacobian;
0235 }
0236
0237 template <typename propagator_t>
0238 Acts::BoundVector Acts::RiddersPropagator<propagator_t>::fitLinear(
0239 const std::vector<double>& deviations,
0240 const std::vector<Acts::BoundVector>& derivatives) {
0241 assert(!derivatives.empty() && "no fit without data");
0242 if (derivatives.size() == 1) {
0243 return derivatives[0];
0244 }
0245
0246 BoundVector A = BoundVector::Zero();
0247 BoundVector C = BoundVector::Zero();
0248 double B = 0;
0249 double D = 0;
0250 const unsigned int N = deviations.size();
0251
0252 for (unsigned int i = 0; i < N; ++i) {
0253 A += deviations.at(i) * derivatives.at(i);
0254 B += deviations.at(i);
0255 C += derivatives.at(i);
0256 D += deviations.at(i) * deviations.at(i);
0257 }
0258
0259 BoundVector b = (N * A - B * C) / (N * D - B * B);
0260 BoundVector a = (C - B * b) / N;
0261
0262 return a;
0263 }