ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
RiddersPropagator.ipp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file RiddersPropagator.ipp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2017-2019 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 
9 template <typename propagator_t>
10 template <typename parameters_t, typename propagator_options_t>
12  const parameters_t& start, const propagator_options_t& options) const
15  typename propagator_options_t::action_list_type>> {
16  // Launch nominal propagation and collect results
17  auto nominalResult = m_propagator.propagate(start, options).value();
18  const BoundVector& nominalParameters =
19  nominalResult.endParameters->parameters();
20  // Pick the surface of the propagation as target
21  const Surface& surface = nominalResult.endParameters->referenceSurface();
22 
23  // Steps for estimating derivatives
24  std::vector<double> deviations = {-4e-4, -2e-4, 2e-4, 4e-4};
25 
26  // Allow larger distances for the oscillation
27  propagator_options_t opts = options;
28  opts.pathLimit *= 2.;
29 
30  // Derivations of each parameter around the nominal parameters
31  std::array<std::vector<BoundVector>, eBoundParametersSize> derivatives;
32 
33  // Wiggle each dimension individually
34  for (unsigned int i = 0; i < eBoundParametersSize; i++) {
35  derivatives[i] =
36  wiggleDimension(opts, start, i, surface, nominalParameters, deviations);
37  }
38  // Exchange the result by Ridders Covariance
39  const FullParameterSet& parSet =
40  nominalResult.endParameters->getParameterSet();
41  FullParameterSet* mParSet = const_cast<FullParameterSet*>(&parSet);
42  if (start.covariance()) {
43  mParSet->setCovariance(
44  calculateCovariance(derivatives, *start.covariance(), deviations));
45  }
46 
47  return std::move(nominalResult);
48 }
49 
50 template <typename propagator_t>
51 template <typename parameters_t, typename propagator_options_t>
53  const parameters_t& start, const Surface& target,
54  const propagator_options_t& options) const
56  BoundParameters, typename propagator_options_t::action_list_type>> {
57  // Launch nominal propagation and collect results
58  auto nominalResult = m_propagator.propagate(start, target, options).value();
59  const BoundVector& nominalParameters =
60  nominalResult.endParameters->parameters();
61 
62  // Steps for estimating derivatives
63  std::vector<double> deviations = {-4e-4, -2e-4, 2e-4, 4e-4};
64  if (target.type() == Surface::Disc) {
65  deviations = {{-3e-5, -1e-5, 1e-5, 3e-5}};
66  }
67 
68  // - for planar surfaces the dest surface is a perfect destination
69  // surface for the numerical propagation, as reference frame
70  // aligns with the referenceSurface.transform().rotation() at
71  // at any given time
72  //
73  // - for straw & cylinder, where the error is given
74  // in the reference frame that re-aligns with a slightly different
75  // intersection solution
76 
77  // Allow larger distances for the oscillation
78  propagator_options_t opts = options;
79  opts.pathLimit *= 2.;
80 
81  // Derivations of each parameter around the nominal parameters
82  std::array<std::vector<BoundVector>, eBoundParametersSize> derivatives;
83 
84  // Wiggle each dimension individually
85  for (unsigned int i = 0; i < eBoundParametersSize; i++) {
86  derivatives[i] =
87  wiggleDimension(opts, start, i, target, nominalParameters, deviations);
88  }
89  // Exchange the result by Ridders Covariance
90  const FullParameterSet& parSet =
91  nominalResult.endParameters->getParameterSet();
92  FullParameterSet* mParSet = const_cast<FullParameterSet*>(&parSet);
93  if (start.covariance()) {
94  // Test if target is disc - this may lead to inconsistent results
95  if (target.type() == Surface::Disc) {
96  for (const std::vector<BoundVector>& deriv : derivatives) {
97  if (inconsistentDerivativesOnDisc(deriv)) {
98  // Set covariance to zero and return
99  // TODO: This should be changed to indicate that something went
100  // wrong
101  mParSet->setCovariance(Covariance::Zero());
102  return std::move(nominalResult);
103  }
104  }
105  }
106  mParSet->setCovariance(
107  calculateCovariance(derivatives, *start.covariance(), deviations));
108  }
109  return std::move(nominalResult);
110 }
111 
112 template <typename propagator_t>
114  const std::vector<Acts::BoundVector>& derivatives) const {
115  // Test each component with each other
116  for (unsigned int i = 0; i < derivatives.size(); i++) {
117  bool jumpedAngle = true;
118  for (unsigned int j = 0; j < derivatives.size(); j++) {
119  // If there is at least one with a similar angle then it seems to work
120  // properly
121  if (i != j &&
122  std::abs(derivatives[i](1) - derivatives[j](1)) < 0.5 * M_PI) {
123  jumpedAngle = false;
124  break;
125  }
126  }
127  // Break if a jump was detected
128  if (jumpedAngle) {
129  return true;
130  }
131  }
132  return false;
133 }
134 
135 template <typename propagator_t>
136 template <typename options_t, typename parameters_t>
137 std::vector<Acts::BoundVector>
139  const options_t& options, const parameters_t& startPars,
140  const unsigned int param, const Surface& target,
141  const Acts::BoundVector& nominal,
142  const std::vector<double>& deviations) const {
143  // Storage of the results
144  std::vector<BoundVector> derivatives;
145  derivatives.reserve(deviations.size());
146  for (double h : deviations) {
147  parameters_t tp = startPars;
148 
149  // Treatment for theta
150  if (param == eTHETA) {
151  const double current_theta = tp.template get<eTHETA>();
152  if (current_theta + h > M_PI) {
153  h = M_PI - current_theta;
154  }
155  if (current_theta + h < 0) {
156  h = -current_theta;
157  }
158  }
159 
160  // Modify start parameter and propagate
161  switch (param) {
162  case 0: {
163  tp.template set<eLOC_0>(options.geoContext,
164  tp.template get<eLOC_0>() + h);
165  break;
166  }
167  case 1: {
168  tp.template set<eLOC_1>(options.geoContext,
169  tp.template get<eLOC_1>() + h);
170  break;
171  }
172  case 2: {
173  tp.template set<ePHI>(options.geoContext, tp.template get<ePHI>() + h);
174  break;
175  }
176  case 3: {
177  tp.template set<eTHETA>(options.geoContext,
178  tp.template get<eTHETA>() + h);
179  break;
180  }
181  case 4: {
182  tp.template set<eQOP>(options.geoContext, tp.template get<eQOP>() + h);
183  break;
184  }
185  case 5: {
186  tp.template set<eT>(options.geoContext, tp.template get<eT>() + h);
187  break;
188  }
189  default:
190  return {};
191  }
192  const auto& r = m_propagator.propagate(tp, target, options).value();
193  // Collect the slope
194  derivatives.push_back((r.endParameters->parameters() - nominal) / h);
195 
196  // Correct for a possible variation of phi around
197  if (param == 2) {
198  double phi0 = nominal(Acts::ePHI);
199  double phi1 = r.endParameters->parameters()(Acts::ePHI);
200  if (std::abs(phi1 + 2. * M_PI - phi0) < std::abs(phi1 - phi0))
201  derivatives.back()[Acts::ePHI] = (phi1 + 2. * M_PI - phi0) / h;
202  else if (std::abs(phi1 - 2. * M_PI - phi0) < std::abs(phi1 - phi0))
203  derivatives.back()[Acts::ePHI] = (phi1 - 2. * M_PI - phi0) / h;
204  }
205  }
206  return derivatives;
207 }
208 
209 template <typename propagator_t>
211  const std::array<std::vector<Acts::BoundVector>,
212  Acts::eBoundParametersSize>& derivatives,
213  const Acts::BoundSymMatrix& startCov,
214  const std::vector<double>& deviations) const -> const Covariance {
215  Jacobian jacobian;
216  jacobian.setIdentity();
217  jacobian.col(eLOC_0) = fitLinear(derivatives[eLOC_0], deviations);
218  jacobian.col(eLOC_1) = fitLinear(derivatives[eLOC_1], deviations);
219  jacobian.col(ePHI) = fitLinear(derivatives[ePHI], deviations);
220  jacobian.col(eTHETA) = fitLinear(derivatives[eTHETA], deviations);
221  jacobian.col(eQOP) = fitLinear(derivatives[eQOP], deviations);
222  jacobian.col(eT) = fitLinear(derivatives[eT], deviations);
223  return jacobian * startCov * jacobian.transpose();
224 }
225 
226 template <typename propagator_t>
228  const std::vector<Acts::BoundVector>& values,
229  const std::vector<double>& deviations) const {
230  BoundVector A;
231  BoundVector C;
232  A.setZero();
233  C.setZero();
234  double B = 0;
235  double D = 0;
236  const unsigned int N = deviations.size();
237 
238  for (unsigned int i = 0; i < N; ++i) {
239  A += deviations.at(i) * values.at(i);
240  B += deviations.at(i);
241  C += values.at(i);
242  D += deviations.at(i) * deviations.at(i);
243  }
244 
245  BoundVector b = (N * A - B * C) / (N * D - B * B);
246  BoundVector a = (C - B * b) / N;
247 
248  return a;
249 }