EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
EigenStepper.ipp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file EigenStepper.ipp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2019-2020 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 
11 
12 template <typename B, typename E, typename A>
14  : m_bField(std::move(bField)) {}
15 
16 template <typename B, typename E, typename A>
18  const BoundVector& boundParams,
19  const BoundSymMatrix& cov,
20  const Surface& surface,
22  const double stepSize) const {
23  // Update the stepping state
24  update(state,
26  boundParams),
27  cov);
28  state.navDir = navDir;
29  state.stepSize = ConstrainedStep(stepSize);
30  state.pathAccumulated = 0.;
31 
32  // Reinitialize the stepping jacobian
33  surface.initJacobianToGlobal(state.geoContext, state.jacToGlobal,
34  position(state), direction(state), boundParams);
35  state.jacobian = BoundMatrix::Identity();
36  state.jacTransport = FreeMatrix::Identity();
37  state.derivative = FreeVector::Zero();
38 }
39 
40 template <typename B, typename E, typename A>
42  const Surface& surface) const
43  -> BoundState {
45  parameters << state.pos[0], state.pos[1], state.pos[2], state.t, state.dir[0],
46  state.dir[1], state.dir[2], state.q / state.p;
47  return detail::boundState(state.geoContext, state.cov, state.jacobian,
48  state.jacTransport, state.derivative,
49  state.jacToGlobal, parameters, state.covTransport,
50  state.pathAccumulated, surface);
51 }
52 
53 template <typename B, typename E, typename A>
55  -> CurvilinearState {
57  parameters << state.pos[0], state.pos[1], state.pos[2], state.t, state.dir[0],
58  state.dir[1], state.dir[2], state.q / state.p;
60  state.cov, state.jacobian, state.jacTransport, state.derivative,
61  state.jacToGlobal, parameters, state.covTransport, state.pathAccumulated);
62 }
63 
64 template <typename B, typename E, typename A>
66  const FreeVector& parameters,
67  const Covariance& covariance) const {
68  state.pos = parameters.template segment<3>(eFreePos0);
69  state.dir = parameters.template segment<3>(eFreeDir0).normalized();
70  state.p = std::abs(1. / parameters[eFreeQOverP]);
71  state.t = parameters[eFreeTime];
72 
73  state.cov = covariance;
74 }
75 
76 template <typename B, typename E, typename A>
78  const Vector3D& uposition,
79  const Vector3D& udirection, double up,
80  double time) const {
81  state.pos = uposition;
82  state.dir = udirection;
83  state.p = up;
84  state.t = time;
85 }
86 
87 template <typename B, typename E, typename A>
90  state.derivative, state.jacToGlobal, state.dir);
91 }
92 
93 template <typename B, typename E, typename A>
95  State& state, const Surface& surface) const {
97  parameters << state.pos[0], state.pos[1], state.pos[2], state.t, state.dir[0],
98  state.dir[1], state.dir[2], state.q / state.p;
100  state.jacTransport, state.derivative,
101  state.jacToGlobal, parameters, surface);
102 }
103 
104 template <typename B, typename E, typename A>
105 template <typename propagator_state_t>
107  propagator_state_t& state) const {
108  using namespace UnitLiterals;
109 
110  // Runge-Kutta integrator state
111  auto& sd = state.stepping.stepData;
112  double error_estimate = 0.;
113  double h2, half_h;
114 
115  // First Runge-Kutta point (at current position)
116  sd.B_first = getField(state.stepping, state.stepping.pos);
117  if (!state.stepping.extension.validExtensionForStep(state, *this) ||
118  !state.stepping.extension.k1(state, *this, sd.k1, sd.B_first, sd.kQoP)) {
119  return 0.;
120  }
121 
122  // The following functor starts to perform a Runge-Kutta step of a certain
123  // size, going up to the point where it can return an estimate of the local
124  // integration error. The results are stated in the local variables above,
125  // allowing integration to continue once the error is deemed satisfactory
126  const auto tryRungeKuttaStep = [&](const ConstrainedStep& h) -> bool {
127  // State the square and half of the step size
128  h2 = h * h;
129  half_h = h * 0.5;
130 
131  // Second Runge-Kutta point
132  const Vector3D pos1 =
133  state.stepping.pos + half_h * state.stepping.dir + h2 * 0.125 * sd.k1;
134  sd.B_middle = getField(state.stepping, pos1);
135  if (!state.stepping.extension.k2(state, *this, sd.k2, sd.B_middle, sd.kQoP,
136  half_h, sd.k1)) {
137  return false;
138  }
139 
140  // Third Runge-Kutta point
141  if (!state.stepping.extension.k3(state, *this, sd.k3, sd.B_middle, sd.kQoP,
142  half_h, sd.k2)) {
143  return false;
144  }
145 
146  // Last Runge-Kutta point
147  const Vector3D pos2 =
148  state.stepping.pos + h * state.stepping.dir + h2 * 0.5 * sd.k3;
149  sd.B_last = getField(state.stepping, pos2);
150  if (!state.stepping.extension.k4(state, *this, sd.k4, sd.B_last, sd.kQoP, h,
151  sd.k3)) {
152  return false;
153  }
154 
155  // Compute and check the local integration error estimate
156  error_estimate = std::max(
157  h2 * ((sd.k1 - sd.k2 - sd.k3 + sd.k4).template lpNorm<1>() +
158  std::abs(sd.kQoP[0] - sd.kQoP[1] - sd.kQoP[2] + sd.kQoP[3])),
159  1e-20);
160  return (error_estimate <= state.options.tolerance);
161  };
162 
163  double stepSizeScaling = 1.;
164  size_t nStepTrials = 0;
165  // Select and adjust the appropriate Runge-Kutta step size as given
166  // ATL-SOFT-PUB-2009-001
167  while (!tryRungeKuttaStep(state.stepping.stepSize)) {
168  stepSizeScaling =
169  std::min(std::max(0.25, std::pow((state.options.tolerance /
170  std::abs(2. * error_estimate)),
171  0.25)),
172  4.);
173 
174  state.stepping.stepSize = state.stepping.stepSize * stepSizeScaling;
175 
176  // If step size becomes too small the particle remains at the initial
177  // place
178  if (state.stepping.stepSize * state.stepping.stepSize <
179  state.options.stepSizeCutOff * state.options.stepSizeCutOff) {
180  // Not moving due to too low momentum needs an aborter
181  return EigenStepperError::StepSizeStalled;
182  }
183 
184  // If the parameter is off track too much or given stepSize is not
185  // appropriate
186  if (nStepTrials > state.options.maxRungeKuttaStepTrials) {
187  // Too many trials, have to abort
188  return EigenStepperError::StepSizeAdjustmentFailed;
189  }
190  nStepTrials++;
191  }
192 
193  // use the adjusted step size
194  const double h = state.stepping.stepSize;
195 
196  // When doing error propagation, update the associated Jacobian matrix
197  if (state.stepping.covTransport) {
198  // The step transport matrix in global coordinates
199  FreeMatrix D;
200  if (!state.stepping.extension.finalize(state, *this, h, D)) {
201  return EigenStepperError::StepInvalid;
202  }
203 
204  // for moment, only update the transport part
205  state.stepping.jacTransport = D * state.stepping.jacTransport;
206  } else {
207  if (!state.stepping.extension.finalize(state, *this, h)) {
208  return EigenStepperError::StepInvalid;
209  }
210  }
211 
212  // Update the track parameters according to the equations of motion
213  state.stepping.pos +=
214  h * state.stepping.dir + h2 / 6. * (sd.k1 + sd.k2 + sd.k3);
215  state.stepping.dir += h / 6. * (sd.k1 + 2. * (sd.k2 + sd.k3) + sd.k4);
216  state.stepping.dir /= state.stepping.dir.norm();
217  if (state.stepping.covTransport) {
218  state.stepping.derivative.template head<3>() = state.stepping.dir;
219  state.stepping.derivative.template segment<3>(4) = sd.k4;
220  }
221  state.stepping.pathAccumulated += h;
222  return h;
223 }