ECCE @ 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 
10 
11 template <typename B, typename E, typename A>
13  : m_bField(std::move(bField)) {}
14 
15 template <typename B, typename E, typename A>
17  const Surface& surface) const
18  -> BoundState {
20  parameters << state.pos[0], state.pos[1], state.pos[2], state.t, state.dir[0],
21  state.dir[1], state.dir[2], state.q / state.p;
22  return detail::boundState(state.geoContext, state.cov, state.jacobian,
23  state.jacTransport, state.derivative,
24  state.jacToGlobal, parameters, state.covTransport,
25  state.pathAccumulated, surface);
26 }
27 
28 template <typename B, typename E, typename A>
30  -> CurvilinearState {
32  parameters << state.pos[0], state.pos[1], state.pos[2], state.t, state.dir[0],
33  state.dir[1], state.dir[2], state.q / state.p;
35  state.cov, state.jacobian, state.jacTransport, state.derivative,
36  state.jacToGlobal, parameters, state.covTransport, state.pathAccumulated);
37 }
38 
39 template <typename B, typename E, typename A>
41  const BoundParameters& pars) const {
42  const auto& mom = pars.momentum();
43  state.pos = pars.position();
44  state.dir = mom.normalized();
45  state.p = mom.norm();
46  state.t = pars.time();
47  if (pars.covariance()) {
48  state.cov = (*(pars.covariance()));
49  }
50 }
51 
52 template <typename B, typename E, typename A>
54  const Vector3D& uposition,
55  const Vector3D& udirection, double up,
56  double time) const {
57  state.pos = uposition;
58  state.dir = udirection;
59  state.p = up;
60  state.t = time;
61 }
62 
63 template <typename B, typename E, typename A>
66  state.derivative, state.jacToGlobal, state.dir);
67 }
68 
69 template <typename B, typename E, typename A>
71  State& state, const Surface& surface) const {
73  parameters << state.pos[0], state.pos[1], state.pos[2], state.t, state.dir[0],
74  state.dir[1], state.dir[2], state.q / state.p;
76  state.jacTransport, state.derivative,
77  state.jacToGlobal, parameters, surface);
78 }
79 
80 template <typename B, typename E, typename A>
81 template <typename propagator_state_t>
83  propagator_state_t& state) const {
84  using namespace UnitLiterals;
85 
86  // Runge-Kutta integrator state
87  auto& sd = state.stepping.stepData;
88  double error_estimate = 0.;
89  double h2, half_h;
90 
91  // First Runge-Kutta point (at current position)
92  sd.B_first = getField(state.stepping, state.stepping.pos);
93  if (!state.stepping.extension.validExtensionForStep(state, *this) ||
94  !state.stepping.extension.k1(state, *this, sd.k1, sd.B_first, sd.kQoP)) {
95  return 0.;
96  }
97 
98  // The following functor starts to perform a Runge-Kutta step of a certain
99  // size, going up to the point where it can return an estimate of the local
100  // integration error. The results are stated in the local variables above,
101  // allowing integration to continue once the error is deemed satisfactory
102  const auto tryRungeKuttaStep = [&](const ConstrainedStep& h) -> bool {
103  // State the square and half of the step size
104  h2 = h * h;
105  half_h = h * 0.5;
106 
107  // Second Runge-Kutta point
108  const Vector3D pos1 =
109  state.stepping.pos + half_h * state.stepping.dir + h2 * 0.125 * sd.k1;
110  sd.B_middle = getField(state.stepping, pos1);
111  if (!state.stepping.extension.k2(state, *this, sd.k2, sd.B_middle, sd.kQoP,
112  half_h, sd.k1)) {
113  return false;
114  }
115 
116  // Third Runge-Kutta point
117  if (!state.stepping.extension.k3(state, *this, sd.k3, sd.B_middle, sd.kQoP,
118  half_h, sd.k2)) {
119  return false;
120  }
121 
122  // Last Runge-Kutta point
123  const Vector3D pos2 =
124  state.stepping.pos + h * state.stepping.dir + h2 * 0.5 * sd.k3;
125  sd.B_last = getField(state.stepping, pos2);
126  if (!state.stepping.extension.k4(state, *this, sd.k4, sd.B_last, sd.kQoP, h,
127  sd.k3)) {
128  return false;
129  }
130 
131  // Compute and check the local integration error estimate
132  error_estimate = std::max(
133  h2 * ((sd.k1 - sd.k2 - sd.k3 + sd.k4).template lpNorm<1>() +
134  std::abs(sd.kQoP[0] - sd.kQoP[1] - sd.kQoP[2] + sd.kQoP[3])),
135  1e-20);
136  return (error_estimate <= state.options.tolerance);
137  };
138 
139  double stepSizeScaling = 1.;
140  size_t nStepTrials = 0;
141  // Select and adjust the appropriate Runge-Kutta step size as given
142  // ATL-SOFT-PUB-2009-001
143  while (!tryRungeKuttaStep(state.stepping.stepSize)) {
144  stepSizeScaling =
145  std::min(std::max(0.25, std::pow((state.options.tolerance /
146  std::abs(2. * error_estimate)),
147  0.25)),
148  4.);
149  if (stepSizeScaling == 1.) {
150  break;
151  }
152  state.stepping.stepSize = state.stepping.stepSize * stepSizeScaling;
153 
154  // If step size becomes too small the particle remains at the initial
155  // place
156  if (state.stepping.stepSize * state.stepping.stepSize <
157  state.options.stepSizeCutOff * state.options.stepSizeCutOff) {
158  // Not moving due to too low momentum needs an aborter
159  return EigenStepperError::StepSizeStalled;
160  }
161 
162  // If the parameter is off track too much or given stepSize is not
163  // appropriate
164  if (nStepTrials > state.options.maxRungeKuttaStepTrials) {
165  // Too many trials, have to abort
166  return EigenStepperError::StepSizeAdjustmentFailed;
167  }
168  nStepTrials++;
169  }
170 
171  // use the adjusted step size
172  const double h = state.stepping.stepSize;
173 
174  // When doing error propagation, update the associated Jacobian matrix
175  if (state.stepping.covTransport) {
176  // The step transport matrix in global coordinates
177  FreeMatrix D;
178  if (!state.stepping.extension.finalize(state, *this, h, D)) {
179  return EigenStepperError::StepInvalid;
180  }
181 
182  // for moment, only update the transport part
183  state.stepping.jacTransport = D * state.stepping.jacTransport;
184  } else {
185  if (!state.stepping.extension.finalize(state, *this, h)) {
186  return EigenStepperError::StepInvalid;
187  }
188  }
189 
190  // Update the track parameters according to the equations of motion
191  state.stepping.pos +=
192  h * state.stepping.dir + h2 / 6. * (sd.k1 + sd.k2 + sd.k3);
193  state.stepping.dir += h / 6. * (sd.k1 + 2. * (sd.k2 + sd.k3) + sd.k4);
194  state.stepping.dir /= state.stepping.dir.norm();
195  if (state.stepping.covTransport) {
196  state.stepping.derivative.template head<3>() = state.stepping.dir;
197  state.stepping.derivative.template segment<3>(4) = sd.k4;
198  }
199  state.stepping.pathAccumulated += h;
200  return h;
201 }