ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
AtlasStepper.hpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file AtlasStepper.hpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2016-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 #pragma once
10 
11 #include <cmath>
12 #include <functional>
22 #include "Acts/Utilities/Units.hpp"
23 
24 // This is based original stepper code from the ATLAS RungeKuttePropagagor
25 namespace Acts {
26 
27 using namespace Acts::UnitLiterals;
28 
30 template <typename bfield_t>
31 class AtlasStepper {
32  public:
35  using BoundState = std::tuple<BoundParameters, Jacobian, double>;
36  using CurvilinearState = std::tuple<CurvilinearParameters, Jacobian, double>;
37 
38  using BField = bfield_t;
39 
41  struct State {
43  State() = delete;
44 
55  template <typename Parameters>
56  State(std::reference_wrapper<const GeometryContext> gctx,
57  std::reference_wrapper<const MagneticFieldContext> mctx,
58  const Parameters& pars, NavigationDirection ndir = forward,
59  double ssize = std::numeric_limits<double>::max(),
60  double stolerance = s_onSurfaceTolerance)
61  : navDir(ndir),
62  useJacobian(false),
63  step(0.),
64  maxPathLength(0.),
65  mcondition(false),
66  needgradient(false),
67  newfield(true),
68  field(0., 0., 0.),
69  covariance(nullptr),
70  stepSize(ndir * std::abs(ssize)),
71  tolerance(stolerance),
72  fieldCache(mctx),
73  geoContext(gctx) {
74  // The rest of this constructor is copy&paste of AtlasStepper::update() -
75  // this is a nasty but working solution for the stepper state without
76  // functions
77 
78  const ActsVectorD<3> pos = pars.position();
79  const auto Vp = pars.parameters();
80 
81  double Sf, Cf, Ce, Se;
82  Sf = sin(Vp(2));
83  Cf = cos(Vp(2));
84  Se = sin(Vp(3));
85  Ce = cos(Vp(3));
86 
87  pVector[0] = pos(0);
88  pVector[1] = pos(1);
89  pVector[2] = pos(2);
90  pVector[3] = pars.time();
91  pVector[4] = Cf * Se;
92  pVector[5] = Sf * Se;
93  pVector[6] = Ce;
94  pVector[7] = Vp[4];
95 
96  // @todo: remove magic numbers - is that the charge ?
97  if (std::abs(pVector[7]) < .000000000000001) {
98  pVector[7] < 0. ? pVector[7] = -.000000000000001
99  : pVector[7] = .000000000000001;
100  }
101 
102  // prepare the jacobian if we have a covariance
103  if (pars.covariance()) {
104  // copy the covariance matrix
105  covariance =
106  new ActsSymMatrixD<eBoundParametersSize>(*pars.covariance());
107  covTransport = true;
108  useJacobian = true;
109  const auto transform = pars.referenceSurface().referenceFrame(
110  geoContext, pos, pars.momentum());
111 
112  pVector[8] = transform(0, eLOC_0);
113  pVector[16] = transform(0, eLOC_1);
114  pVector[24] = 0.;
115  pVector[32] = 0.;
116  pVector[40] = 0.;
117  pVector[48] = 0.; // dX /
118 
119  pVector[9] = transform(1, eLOC_0);
120  pVector[17] = transform(1, eLOC_1);
121  pVector[25] = 0.;
122  pVector[33] = 0.;
123  pVector[41] = 0.;
124  pVector[49] = 0.; // dY /
125 
126  pVector[10] = transform(2, eLOC_0);
127  pVector[18] = transform(2, eLOC_1);
128  pVector[26] = 0.;
129  pVector[34] = 0.;
130  pVector[42] = 0.;
131  pVector[50] = 0.; // dZ /
132 
133  pVector[11] = 0.;
134  pVector[19] = 0.;
135  pVector[27] = 0.;
136  pVector[35] = 0.;
137  pVector[43] = 0.;
138  pVector[51] = 1.; // dT/
139 
140  pVector[12] = 0.;
141  pVector[20] = 0.;
142  pVector[28] = -Sf * Se; // - sin(phi) * cos(theta)
143  pVector[36] = Cf * Ce; // cos(phi) * cos(theta)
144  pVector[44] = 0.;
145  pVector[52] = 0.; // dAx/
146 
147  pVector[13] = 0.;
148  pVector[21] = 0.;
149  pVector[29] = Cf * Se; // cos(phi) * sin(theta)
150  pVector[37] = Sf * Ce; // sin(phi) * cos(theta)
151  pVector[45] = 0.;
152  pVector[53] = 0.; // dAy/
153 
154  pVector[14] = 0.;
155  pVector[22] = 0.;
156  pVector[30] = 0.;
157  pVector[38] = -Se; // - sin(theta)
158  pVector[46] = 0.;
159  pVector[54] = 0.; // dAz/
160 
161  pVector[15] = 0.;
162  pVector[23] = 0.;
163  pVector[31] = 0.;
164  pVector[39] = 0.;
165  pVector[47] = 1.;
166  pVector[55] = 0.; // dCM/
167 
168  pVector[56] = 0.;
169  pVector[57] = 0.;
170  pVector[58] = 0.;
171  pVector[59] = 0.;
172 
173  // special treatment for surface types
174  const auto& surface = pars.referenceSurface();
175  // the disc needs polar coordinate adaptations
176  if (surface.type() == Surface::Disc) {
177  double lCf = cos(Vp[1]);
178  double lSf = sin(Vp[1]);
179  double Ax[3] = {transform(0, 0), transform(1, 0), transform(2, 0)};
180  double Ay[3] = {transform(0, 1), transform(1, 1), transform(2, 1)};
181  double d0 = lCf * Ax[0] + lSf * Ay[0];
182  double d1 = lCf * Ax[1] + lSf * Ay[1];
183  double d2 = lCf * Ax[2] + lSf * Ay[2];
184  pVector[8] = d0;
185  pVector[9] = d1;
186  pVector[10] = d2;
187  pVector[16] = Vp[0] * (lCf * Ay[0] - lSf * Ax[0]);
188  pVector[17] = Vp[0] * (lCf * Ay[1] - lSf * Ax[1]);
189  pVector[18] = Vp[0] * (lCf * Ay[2] - lSf * Ax[2]);
190  }
191  // the line needs components that relate direction change
192  // with global frame change
193  if (surface.type() == Surface::Perigee ||
194  surface.type() == Surface::Straw) {
195  // sticking to the nomenclature of the original RkPropagator
196  // - axis pointing along the drift/transverse direction
197  double B[3] = {transform(0, 0), transform(1, 0), transform(2, 0)};
198  // - axis along the straw
199  double A[3] = {transform(0, 1), transform(1, 1), transform(2, 1)};
200  // - normal vector of the reference frame
201  double C[3] = {transform(0, 2), transform(1, 2), transform(2, 2)};
202 
203  // projection of direction onto normal vector of reference frame
204  double PC = pVector[4] * C[0] + pVector[5] * C[1] + pVector[6] * C[2];
205  double Bn = 1. / PC;
206 
207  double Bx2 = -A[2] * pVector[29];
208  double Bx3 = A[1] * pVector[38] - A[2] * pVector[37];
209 
210  double By2 = A[2] * pVector[28];
211  double By3 = A[2] * pVector[36] - A[0] * pVector[38];
212 
213  double Bz2 = A[0] * pVector[29] - A[1] * pVector[28];
214  double Bz3 = A[0] * pVector[37] - A[1] * pVector[36];
215 
216  double B2 = B[0] * Bx2 + B[1] * By2 + B[2] * Bz2;
217  double B3 = B[0] * Bx3 + B[1] * By3 + B[2] * Bz3;
218 
219  Bx2 = (Bx2 - B[0] * B2) * Bn;
220  Bx3 = (Bx3 - B[0] * B3) * Bn;
221  By2 = (By2 - B[1] * B2) * Bn;
222  By3 = (By3 - B[1] * B3) * Bn;
223  Bz2 = (Bz2 - B[2] * B2) * Bn;
224  Bz3 = (Bz3 - B[2] * B3) * Bn;
225 
226  // /dPhi | /dThe |
227  pVector[24] = Bx2 * Vp[0];
228  pVector[32] = Bx3 * Vp[0]; // dX/
229  pVector[25] = By2 * Vp[0];
230  pVector[33] = By3 * Vp[0]; // dY/
231  pVector[26] = Bz2 * Vp[0];
232  pVector[34] = Bz3 * Vp[0]; // dZ/
233  }
234  }
235  // now declare the state as ready
236  state_ready = true;
237  }
238 
239  // optimisation that init is not called twice
240  bool state_ready = false;
241  // configuration
244  double step;
248  bool newfield;
249  // internal parameters to be used
251  std::array<double, 60> pVector;
252 
264 
265  // result
266  double parameters[eBoundParametersSize] = {0., 0., 0., 0., 0., 0.};
268  Covariance cov = Covariance::Zero();
269  bool covTransport = false;
271 
272  // accummulated path length cache
273  double pathAccumulated = 0.;
274 
275  // Adaptive step size of the runge-kutta integration
277 
278  // Previous step size for overstep estimation
279  double previousStepSize = 0.;
280 
282  double tolerance = s_onSurfaceTolerance;
283 
286  typename bfield_t::Cache fieldCache;
287 
289  std::reference_wrapper<const GeometryContext> geoContext;
290 
293  bool debug = false;
294  std::string debugString = "";
296  size_t debugPfxWidth = 30;
297  size_t debugMsgWidth = 50;
298  };
299 
300  AtlasStepper(bfield_t bField = bfield_t()) : m_bField(std::move(bField)){};
301 
309  Vector3D getField(State& state, const Vector3D& pos) const {
310  // get the field from the cell
311  state.field = m_bField.getField(pos, state.fieldCache);
312  return state.field;
313  }
314 
315  Vector3D position(const State& state) const {
316  return Vector3D(state.pVector[0], state.pVector[1], state.pVector[2]);
317  }
318 
319  Vector3D direction(const State& state) const {
320  return Vector3D(state.pVector[4], state.pVector[5], state.pVector[6]);
321  }
322 
323  double momentum(const State& state) const {
324  return 1. / std::abs(state.pVector[7]);
325  }
326 
328  double charge(const State& state) const {
329  return state.pVector[7] > 0. ? 1. : -1.;
330  }
331 
335  double overstepLimit(const State& /*state*/) const { return m_overstepLimit; }
336 
338  double time(const State& state) const { return state.pVector[3]; }
339 
350  Intersection::Status updateSurfaceStatus(State& state, const Surface& surface,
351  const BoundaryCheck& bcheck) const {
352  return detail::updateSingleSurfaceStatus<AtlasStepper>(*this, state,
353  surface, bcheck);
354  }
355 
364  template <typename object_intersection_t>
365  void updateStepSize(State& state, const object_intersection_t& oIntersection,
366  bool release = true) const {
367  detail::updateSingleStepSize<AtlasStepper>(state, oIntersection, release);
368  }
369 
375  void setStepSize(State& state, double stepSize,
377  state.previousStepSize = state.stepSize;
378  state.stepSize.update(stepSize, stype, true);
379  }
380 
384  void releaseStepSize(State& state) const {
385  state.stepSize.release(ConstrainedStep::actor);
386  }
387 
391  std::string outputStepSize(const State& state) const {
392  return state.stepSize.toString();
393  }
394 
405  BoundState boundState(State& state, const Surface& surface) const {
406  // the convert method invalidates the state (in case it's reused)
407  state.state_ready = false;
408 
410  Acts::Vector3D gp(state.pVector[0], state.pVector[1], state.pVector[2]);
411  Acts::Vector3D mom(state.pVector[4], state.pVector[5], state.pVector[6]);
412  mom /= std::abs(state.pVector[7]);
413 
414  // The transport of the covariance
415  std::unique_ptr<const Covariance> cov = nullptr;
416  std::optional<Covariance> covOpt = std::nullopt;
417  if (state.covTransport) {
418  covarianceTransport(state, surface);
419  covOpt = state.cov;
420  }
421 
422  // Fill the end parameters
423  BoundParameters parameters(state.geoContext, std::move(covOpt), gp, mom,
424  charge(state), state.pVector[3],
425  surface.getSharedPtr());
426 
427  return BoundState(std::move(parameters), state.jacobian,
428  state.pathAccumulated);
429  }
430 
441  // the convert method invalidates the state (in case it's reused)
442  state.state_ready = false;
443  //
444  Acts::Vector3D gp(state.pVector[0], state.pVector[1], state.pVector[2]);
445  Acts::Vector3D mom(state.pVector[4], state.pVector[5], state.pVector[6]);
446  mom /= std::abs(state.pVector[7]);
447 
448  std::optional<Covariance> covOpt = std::nullopt;
449  if (state.covTransport) {
450  covarianceTransport(state);
451  covOpt = state.cov;
452  }
453 
454  CurvilinearParameters parameters(std::move(covOpt), gp, mom, charge(state),
455  state.pVector[3]);
456 
457  return CurvilinearState(std::move(parameters), state.jacobian,
458  state.pathAccumulated);
459  }
460 
465  void update(State& state, const BoundParameters& pars) const {
466  // state is ready - noting to do
467  if (state.state_ready) {
468  return;
469  }
470 
471  const ActsVectorD<3> pos = pars.position();
472  const auto Vp = pars.parameters();
473 
474  double Sf, Cf, Ce, Se;
475  Sf = sin(Vp(2));
476  Cf = cos(Vp(2));
477  Se = sin(Vp(3));
478  Ce = cos(Vp(3));
479 
480  state.pVector[0] = pos(0);
481  state.pVector[1] = pos(1);
482  state.pVector[2] = pos(2);
483  state.pVector[3] = pars.time();
484  state.pVector[4] = Cf * Se;
485  state.pVector[5] = Sf * Se;
486  state.pVector[6] = Ce;
487  state.pVector[7] = Vp[4];
488 
489  // @todo: remove magic numbers - is that the charge ?
490  if (std::abs(state.pVector[7]) < .000000000000001) {
491  state.pVector[7] < 0. ? state.pVector[7] = -.000000000000001
492  : state.pVector[7] = .000000000000001;
493  }
494 
495  // prepare the jacobian if we have a covariance
496  if (pars.covariance()) {
497  // copy the covariance matrix
498  state.covariance =
500  state.covTransport = true;
501  state.useJacobian = true;
502  const auto transform = pars.referenceFrame(state.geoContext);
503 
504  state.pVector[8] = transform(0, eLOC_0);
505  state.pVector[16] = transform(0, eLOC_1);
506  state.pVector[24] = 0.;
507  state.pVector[32] = 0.;
508  state.pVector[40] = 0.;
509  state.pVector[48] = 0.; // dX /
510 
511  state.pVector[9] = transform(1, eLOC_0);
512  state.pVector[17] = transform(1, eLOC_1);
513  state.pVector[25] = 0.;
514  state.pVector[33] = 0.;
515  state.pVector[41] = 0.;
516  state.pVector[49] = 0.; // dY /
517 
518  state.pVector[10] = transform(2, eLOC_0);
519  state.pVector[18] = transform(2, eLOC_1);
520  state.pVector[26] = 0.;
521  state.pVector[34] = 0.;
522  state.pVector[42] = 0.;
523  state.pVector[50] = 0.; // dZ /
524 
525  state.pVector[11] = 0.;
526  state.pVector[19] = 0.;
527  state.pVector[27] = 0.;
528  state.pVector[35] = 0.;
529  state.pVector[43] = 0.;
530  state.pVector[51] = 1.; // dT/
531 
532  state.pVector[12] = 0.;
533  state.pVector[20] = 0.;
534  state.pVector[28] = -Sf * Se; // - sin(phi) * cos(theta)
535  state.pVector[36] = Cf * Ce; // cos(phi) * cos(theta)
536  state.pVector[44] = 0.;
537  state.pVector[52] = 0.; // dAx/
538 
539  state.pVector[13] = 0.;
540  state.pVector[21] = 0.;
541  state.pVector[29] = Cf * Se; // cos(phi) * sin(theta)
542  state.pVector[37] = Sf * Ce; // sin(phi) * cos(theta)
543  state.pVector[45] = 0.;
544  state.pVector[53] = 0.; // dAy/
545 
546  state.pVector[14] = 0.;
547  state.pVector[22] = 0.;
548  state.pVector[30] = 0.;
549  state.pVector[38] = -Se; // - sin(theta)
550  state.pVector[46] = 0.;
551  state.pVector[54] = 0.; // dAz/
552 
553  state.pVector[15] = 0.;
554  state.pVector[23] = 0.;
555  state.pVector[31] = 0.;
556  state.pVector[39] = 0.;
557  state.pVector[47] = 1.;
558  state.pVector[55] = 0.; // dCM/
559 
560  state.pVector[56] = 0.;
561  state.pVector[57] = 0.;
562  state.pVector[58] = 0.;
563  state.pVector[59] = 0.;
564 
565  // special treatment for surface types
566  const auto& surface = pars.referenceSurface();
567  // the disc needs polar coordinate adaptations
568  if (surface.type() == Surface::Disc) {
569  double lCf = cos(Vp[1]);
570  double lSf = sin(Vp[1]);
571  double Ax[3] = {transform(0, 0), transform(1, 0), transform(2, 0)};
572  double Ay[3] = {transform(0, 1), transform(1, 1), transform(2, 1)};
573  double d0 = lCf * Ax[0] + lSf * Ay[0];
574  double d1 = lCf * Ax[1] + lSf * Ay[1];
575  double d2 = lCf * Ax[2] + lSf * Ay[2];
576  state.pVector[8] = d0;
577  state.pVector[9] = d1;
578  state.pVector[10] = d2;
579  state.pVector[16] = Vp[0] * (lCf * Ay[0] - lSf * Ax[0]);
580  state.pVector[17] = Vp[0] * (lCf * Ay[1] - lSf * Ax[1]);
581  state.pVector[18] = Vp[0] * (lCf * Ay[2] - lSf * Ax[2]);
582  }
583  // the line needs components that relate direction change
584  // with global frame change
585  if (surface.type() == Surface::Perigee ||
586  surface.type() == Surface::Straw) {
587  // sticking to the nomenclature of the original RkPropagator
588  // - axis pointing along the drift/transverse direction
589  double B[3] = {transform(0, 0), transform(1, 0), transform(2, 0)};
590  // - axis along the straw
591  double A[3] = {transform(0, 1), transform(1, 1), transform(2, 1)};
592  // - normal vector of the reference frame
593  double C[3] = {transform(0, 2), transform(1, 2), transform(2, 2)};
594 
595  // projection of direction onto normal vector of reference frame
596  double PC = state.pVector[4] * C[0] + state.pVector[5] * C[1] +
597  state.pVector[6] * C[2];
598  double Bn = 1. / PC;
599 
600  double Bx2 = -A[2] * state.pVector[29];
601  double Bx3 = A[1] * state.pVector[38] - A[2] * state.pVector[37];
602 
603  double By2 = A[2] * state.pVector[28];
604  double By3 = A[2] * state.pVector[36] - A[0] * state.pVector[38];
605 
606  double Bz2 = A[0] * state.pVector[29] - A[1] * state.pVector[28];
607  double Bz3 = A[0] * state.pVector[37] - A[1] * state.pVector[36];
608 
609  double B2 = B[0] * Bx2 + B[1] * By2 + B[2] * Bz2;
610  double B3 = B[0] * Bx3 + B[1] * By3 + B[2] * Bz3;
611 
612  Bx2 = (Bx2 - B[0] * B2) * Bn;
613  Bx3 = (Bx3 - B[0] * B3) * Bn;
614  By2 = (By2 - B[1] * B2) * Bn;
615  By3 = (By3 - B[1] * B3) * Bn;
616  Bz2 = (Bz2 - B[2] * B2) * Bn;
617  Bz3 = (Bz3 - B[2] * B3) * Bn;
618 
619  // /dPhi | /dThe |
620  state.pVector[24] = Bx2 * Vp[0];
621  state.pVector[32] = Bx3 * Vp[0]; // dX/
622  state.pVector[25] = By2 * Vp[0];
623  state.pVector[33] = By3 * Vp[0]; // dY/
624  state.pVector[26] = Bz2 * Vp[0];
625  state.pVector[34] = Bz3 * Vp[0]; // dZ/
626  }
627  }
628  // now declare the state as ready
629  state.state_ready = true;
630  }
631 
637  void update(State& state, const Vector3D& uposition,
638  const Vector3D& udirection, double up, double time) const {
639  // update the vector
640  state.pVector[0] = uposition[0];
641  state.pVector[1] = uposition[1];
642  state.pVector[2] = uposition[2];
643  state.pVector[3] = time;
644  state.pVector[4] = udirection[0];
645  state.pVector[5] = udirection[1];
646  state.pVector[6] = udirection[2];
647  state.pVector[7] = charge(state) / up;
648  }
649 
657  void covarianceTransport(State& state) const {
658  double P[60];
659  for (unsigned int i = 0; i < 60; ++i) {
660  P[i] = state.pVector[i];
661  }
662 
663  double p = 1. / P[7];
664  P[40] *= p;
665  P[41] *= p;
666  P[42] *= p;
667  P[44] *= p;
668  P[45] *= p;
669  P[46] *= p;
670 
671  double An = sqrt(P[4] * P[4] + P[5] * P[5]);
672  double Ax[3];
673  if (An != 0.) {
674  Ax[0] = -P[5] / An;
675  Ax[1] = P[4] / An;
676  Ax[2] = 0.;
677  } else {
678  Ax[0] = 1.;
679  Ax[1] = 0.;
680  Ax[2] = 0.;
681  }
682 
683  double Ay[3] = {-Ax[1] * P[6], Ax[0] * P[6], An};
684  double S[3] = {P[4], P[5], P[6]};
685 
686  double A = P[4] * S[0] + P[5] * S[1] + P[6] * S[2];
687  if (A != 0.) {
688  A = 1. / A;
689  }
690  S[0] *= A;
691  S[1] *= A;
692  S[2] *= A;
693 
694  double s0 = P[8] * S[0] + P[9] * S[1] + P[10] * S[2];
695  double s1 = P[16] * S[0] + P[17] * S[1] + P[18] * S[2];
696  double s2 = P[24] * S[0] + P[25] * S[1] + P[26] * S[2];
697  double s3 = P[32] * S[0] + P[33] * S[1] + P[34] * S[2];
698  double s4 = P[40] * S[0] + P[41] * S[1] + P[42] * S[2];
699 
700  P[8] -= (s0 * P[4]);
701  P[9] -= (s0 * P[5]);
702  P[10] -= (s0 * P[6]);
703  P[11] -= (s0 * P[59]);
704  P[12] -= (s0 * P[56]);
705  P[13] -= (s0 * P[57]);
706  P[14] -= (s0 * P[58]);
707  P[16] -= (s1 * P[4]);
708  P[17] -= (s1 * P[5]);
709  P[18] -= (s1 * P[6]);
710  P[19] -= (s1 * P[59]);
711  P[20] -= (s1 * P[56]);
712  P[21] -= (s1 * P[57]);
713  P[22] -= (s1 * P[58]);
714  P[24] -= (s2 * P[4]);
715  P[25] -= (s2 * P[5]);
716  P[26] -= (s2 * P[6]);
717  P[27] -= (s2 * P[59]);
718  P[28] -= (s2 * P[56]);
719  P[29] -= (s2 * P[57]);
720  P[30] -= (s2 * P[58]);
721  P[32] -= (s3 * P[4]);
722  P[33] -= (s3 * P[5]);
723  P[34] -= (s3 * P[6]);
724  P[35] -= (s3 * P[59]);
725  P[36] -= (s3 * P[56]);
726  P[37] -= (s3 * P[57]);
727  P[38] -= (s3 * P[58]);
728  P[40] -= (s4 * P[4]);
729  P[41] -= (s4 * P[5]);
730  P[42] -= (s4 * P[6]);
731  P[43] -= (s4 * P[59]);
732  P[44] -= (s4 * P[56]);
733  P[45] -= (s4 * P[57]);
734  P[46] -= (s4 * P[58]);
735 
736  double P3, P4, C = P[4] * P[4] + P[5] * P[5];
737  if (C > 1.e-20) {
738  C = 1. / C;
739  P3 = P[4] * C;
740  P4 = P[5] * C;
741  C = -sqrt(C);
742  } else {
743  C = -1.e10;
744  P3 = 1.;
745  P4 = 0.;
746  }
747 
748  // Jacobian production
749  //
750  state.jacobian[0] = Ax[0] * P[8] + Ax[1] * P[9]; // dL0/dL0
751  state.jacobian[1] = Ax[0] * P[16] + Ax[1] * P[17]; // dL0/dL1
752  state.jacobian[2] = Ax[0] * P[24] + Ax[1] * P[25]; // dL0/dPhi
753  state.jacobian[3] = Ax[0] * P[32] + Ax[1] * P[33]; // dL0/dThe
754  state.jacobian[4] = Ax[0] * P[40] + Ax[1] * P[41]; // dL0/dCM
755  state.jacobian[5] = 0.; // dL0/dT
756 
757  state.jacobian[6] = Ay[0] * P[8] + Ay[1] * P[9] + Ay[2] * P[10]; // dL1/dL0
758  state.jacobian[7] =
759  Ay[0] * P[16] + Ay[1] * P[17] + Ay[2] * P[18]; // dL1/dL1
760  state.jacobian[8] =
761  Ay[0] * P[24] + Ay[1] * P[25] + Ay[2] * P[26]; // dL1/dPhi
762  state.jacobian[9] =
763  Ay[0] * P[32] + Ay[1] * P[33] + Ay[2] * P[34]; // dL1/dThe
764  state.jacobian[10] =
765  Ay[0] * P[40] + Ay[1] * P[41] + Ay[2] * P[42]; // dL1/dCM
766  state.jacobian[11] = 0.; // dL1/dT
767 
768  state.jacobian[12] = P3 * P[13] - P4 * P[12]; // dPhi/dL0
769  state.jacobian[13] = P3 * P[21] - P4 * P[20]; // dPhi/dL1
770  state.jacobian[14] = P3 * P[29] - P4 * P[28]; // dPhi/dPhi
771  state.jacobian[15] = P3 * P[37] - P4 * P[36]; // dPhi/dThe
772  state.jacobian[16] = P3 * P[45] - P4 * P[44]; // dPhi/dCM
773  state.jacobian[17] = 0.; // dPhi/dT
774 
775  state.jacobian[18] = C * P[14]; // dThe/dL0
776  state.jacobian[19] = C * P[22]; // dThe/dL1
777  state.jacobian[20] = C * P[30]; // dThe/dPhi
778  state.jacobian[21] = C * P[38]; // dThe/dThe
779  state.jacobian[22] = C * P[46]; // dThe/dCM
780  state.jacobian[23] = 0.; // dThe/dT
781 
782  state.jacobian[24] = 0.; // dCM /dL0
783  state.jacobian[25] = 0.; // dCM /dL1
784  state.jacobian[26] = 0.; // dCM /dPhi
785  state.jacobian[27] = 0.; // dCM /dTheta
786  state.jacobian[28] = P[47]; // dCM /dCM
787  state.jacobian[29] = 0.; // dCM/dT
788 
789  state.jacobian[30] = P[11]; // dT/dL0
790  state.jacobian[31] = P[19]; // dT/dL1
791  state.jacobian[32] = P[27]; // dT/dPhi
792  state.jacobian[33] = P[35]; // dT/dThe
793  state.jacobian[34] = P[43]; // dT/dCM
794  state.jacobian[35] = P[51]; // dT/dT
795 
796  Eigen::Map<Eigen::Matrix<double, eBoundParametersSize, eBoundParametersSize,
797  Eigen::RowMajor>>
798  J(state.jacobian);
799  state.cov = J * (*state.covariance) * J.transpose();
800  }
801 
808  void covarianceTransport(State& state, const Surface& surface) const {
809  Acts::Vector3D gp(state.pVector[0], state.pVector[1], state.pVector[2]);
810  Acts::Vector3D mom(state.pVector[4], state.pVector[5], state.pVector[6]);
811  mom /= std::abs(state.pVector[7]);
812 
813  double p = 1. / state.pVector[7];
814  state.pVector[40] *= p;
815  state.pVector[41] *= p;
816  state.pVector[42] *= p;
817  state.pVector[44] *= p;
818  state.pVector[45] *= p;
819  state.pVector[46] *= p;
820 
821  const auto fFrame = surface.referenceFrame(state.geoContext, gp, mom);
822 
823  double Ax[3] = {fFrame(0, 0), fFrame(1, 0), fFrame(2, 0)};
824  double Ay[3] = {fFrame(0, 1), fFrame(1, 1), fFrame(2, 1)};
825  double S[3] = {fFrame(0, 2), fFrame(1, 2), fFrame(2, 2)};
826 
827  // this is the projection of direction onto the local normal vector
828  double A = state.pVector[4] * S[0] + state.pVector[5] * S[1] +
829  state.pVector[6] * S[2];
830 
831  if (A != 0.) {
832  A = 1. / A;
833  }
834 
835  S[0] *= A;
836  S[1] *= A;
837  S[2] *= A;
838 
839  double s0 = state.pVector[8] * S[0] + state.pVector[9] * S[1] +
840  state.pVector[10] * S[2];
841  double s1 = state.pVector[16] * S[0] + state.pVector[17] * S[1] +
842  state.pVector[18] * S[2];
843  double s2 = state.pVector[24] * S[0] + state.pVector[25] * S[1] +
844  state.pVector[26] * S[2];
845  double s3 = state.pVector[32] * S[0] + state.pVector[33] * S[1] +
846  state.pVector[34] * S[2];
847  double s4 = state.pVector[40] * S[0] + state.pVector[41] * S[1] +
848  state.pVector[42] * S[2];
849 
850  // in case of line-type surfaces - we need to take into account that
851  // the reference frame changes with variations of all local
852  // parameters
853  if (surface.type() == Surface::Straw ||
854  surface.type() == Surface::Perigee) {
855  // vector from position to center
856  double x = state.pVector[0] - surface.center(state.geoContext).x();
857  double y = state.pVector[1] - surface.center(state.geoContext).y();
858  double z = state.pVector[2] - surface.center(state.geoContext).z();
859 
860  // this is the projection of the direction onto the local y axis
861  double d = state.pVector[4] * Ay[0] + state.pVector[5] * Ay[1] +
862  state.pVector[6] * Ay[2];
863 
864  // this is cos(beta)
865  double a = (1. - d) * (1. + d);
866  if (a != 0.) {
867  a = 1. / a; // i.e. 1./(1-d^2)
868  }
869 
870  // that's the modified norm vector
871  double X = d * Ay[0] - state.pVector[4]; //
872  double Y = d * Ay[1] - state.pVector[5]; //
873  double Z = d * Ay[2] - state.pVector[6]; //
874 
875  // d0 to d1
876  double d0 = state.pVector[12] * Ay[0] + state.pVector[13] * Ay[1] +
877  state.pVector[14] * Ay[2];
878  double d1 = state.pVector[20] * Ay[0] + state.pVector[21] * Ay[1] +
879  state.pVector[22] * Ay[2];
880  double d2 = state.pVector[28] * Ay[0] + state.pVector[29] * Ay[1] +
881  state.pVector[30] * Ay[2];
882  double d3 = state.pVector[36] * Ay[0] + state.pVector[37] * Ay[1] +
883  state.pVector[38] * Ay[2];
884  double d4 = state.pVector[44] * Ay[0] + state.pVector[45] * Ay[1] +
885  state.pVector[46] * Ay[2];
886 
887  s0 = (((state.pVector[8] * X + state.pVector[9] * Y +
888  state.pVector[10] * Z) +
889  x * (d0 * Ay[0] - state.pVector[12])) +
890  (y * (d0 * Ay[1] - state.pVector[13]) +
891  z * (d0 * Ay[2] - state.pVector[14]))) *
892  (-a);
893 
894  s1 = (((state.pVector[16] * X + state.pVector[17] * Y +
895  state.pVector[18] * Z) +
896  x * (d1 * Ay[0] - state.pVector[20])) +
897  (y * (d1 * Ay[1] - state.pVector[21]) +
898  z * (d1 * Ay[2] - state.pVector[22]))) *
899  (-a);
900  s2 = (((state.pVector[24] * X + state.pVector[25] * Y +
901  state.pVector[26] * Z) +
902  x * (d2 * Ay[0] - state.pVector[28])) +
903  (y * (d2 * Ay[1] - state.pVector[29]) +
904  z * (d2 * Ay[2] - state.pVector[30]))) *
905  (-a);
906  s3 = (((state.pVector[32] * X + state.pVector[33] * Y +
907  state.pVector[34] * Z) +
908  x * (d3 * Ay[0] - state.pVector[36])) +
909  (y * (d3 * Ay[1] - state.pVector[37]) +
910  z * (d3 * Ay[2] - state.pVector[38]))) *
911  (-a);
912  s4 = (((state.pVector[40] * X + state.pVector[41] * Y +
913  state.pVector[42] * Z) +
914  x * (d4 * Ay[0] - state.pVector[44])) +
915  (y * (d4 * Ay[1] - state.pVector[45]) +
916  z * (d4 * Ay[2] - state.pVector[46]))) *
917  (-a);
918  }
919 
920  state.pVector[8] -= (s0 * state.pVector[4]);
921  state.pVector[9] -= (s0 * state.pVector[5]);
922  state.pVector[10] -= (s0 * state.pVector[6]);
923  state.pVector[11] -= (s0 * state.pVector[59]);
924  state.pVector[12] -= (s0 * state.pVector[56]);
925  state.pVector[13] -= (s0 * state.pVector[57]);
926  state.pVector[14] -= (s0 * state.pVector[58]);
927 
928  state.pVector[16] -= (s1 * state.pVector[4]);
929  state.pVector[17] -= (s1 * state.pVector[5]);
930  state.pVector[18] -= (s1 * state.pVector[6]);
931  state.pVector[19] -= (s1 * state.pVector[59]);
932  state.pVector[20] -= (s1 * state.pVector[56]);
933  state.pVector[21] -= (s1 * state.pVector[57]);
934  state.pVector[22] -= (s1 * state.pVector[58]);
935 
936  state.pVector[24] -= (s2 * state.pVector[4]);
937  state.pVector[25] -= (s2 * state.pVector[5]);
938  state.pVector[26] -= (s2 * state.pVector[6]);
939  state.pVector[27] -= (s2 * state.pVector[59]);
940  state.pVector[28] -= (s2 * state.pVector[56]);
941  state.pVector[29] -= (s2 * state.pVector[57]);
942  state.pVector[30] -= (s2 * state.pVector[58]);
943 
944  state.pVector[32] -= (s3 * state.pVector[4]);
945  state.pVector[33] -= (s3 * state.pVector[5]);
946  state.pVector[34] -= (s3 * state.pVector[6]);
947  state.pVector[35] -= (s3 * state.pVector[59]);
948  state.pVector[36] -= (s3 * state.pVector[56]);
949  state.pVector[37] -= (s3 * state.pVector[57]);
950  state.pVector[38] -= (s3 * state.pVector[58]);
951 
952  state.pVector[40] -= (s4 * state.pVector[4]);
953  state.pVector[41] -= (s4 * state.pVector[5]);
954  state.pVector[42] -= (s4 * state.pVector[6]);
955  state.pVector[43] -= (s4 * state.pVector[59]);
956  state.pVector[44] -= (s4 * state.pVector[56]);
957  state.pVector[45] -= (s4 * state.pVector[57]);
958  state.pVector[46] -= (s4 * state.pVector[58]);
959 
960  double P3, P4,
961  C = state.pVector[4] * state.pVector[4] +
962  state.pVector[5] * state.pVector[5];
963  if (C > 1.e-20) {
964  C = 1. / C;
965  P3 = state.pVector[4] * C;
966  P4 = state.pVector[5] * C;
967  C = -sqrt(C);
968  } else {
969  C = -1.e10;
970  P3 = 1.;
971  P4 = 0.;
972  }
973 
974  double MA[3] = {Ax[0], Ax[1], Ax[2]};
975  double MB[3] = {Ay[0], Ay[1], Ay[2]};
976  // Jacobian production of transport and to_local
977  if (surface.type() == Surface::Disc) {
978  // the vector from the disc surface to the p
979  const auto& sfc = surface.center(state.geoContext);
980  double d[3] = {state.pVector[0] - sfc(0), state.pVector[1] - sfc(1),
981  state.pVector[2] - sfc(2)};
982  // this needs the transformation to polar coordinates
983  double RC = d[0] * Ax[0] + d[1] * Ax[1] + d[2] * Ax[2];
984  double RS = d[0] * Ay[0] + d[1] * Ay[1] + d[2] * Ay[2];
985  double R2 = RC * RC + RS * RS;
986 
987  // inverse radius
988  double Ri = 1. / sqrt(R2);
989  MA[0] = (RC * Ax[0] + RS * Ay[0]) * Ri;
990  MA[1] = (RC * Ax[1] + RS * Ay[1]) * Ri;
991  MA[2] = (RC * Ax[2] + RS * Ay[2]) * Ri;
992  MB[0] = (RC * Ay[0] - RS * Ax[0]) * (Ri = 1. / R2);
993  MB[1] = (RC * Ay[1] - RS * Ax[1]) * Ri;
994  MB[2] = (RC * Ay[2] - RS * Ax[2]) * Ri;
995  }
996 
997  state.jacobian[0] = MA[0] * state.pVector[8] + MA[1] * state.pVector[9] +
998  MA[2] * state.pVector[10]; // dL0/dL0
999  state.jacobian[1] = MA[0] * state.pVector[16] + MA[1] * state.pVector[17] +
1000  MA[2] * state.pVector[18]; // dL0/dL1
1001  state.jacobian[2] = MA[0] * state.pVector[24] + MA[1] * state.pVector[25] +
1002  MA[2] * state.pVector[26]; // dL0/dPhi
1003  state.jacobian[3] = MA[0] * state.pVector[32] + MA[1] * state.pVector[33] +
1004  MA[2] * state.pVector[34]; // dL0/dThe
1005  state.jacobian[4] = MA[0] * state.pVector[40] + MA[1] * state.pVector[41] +
1006  MA[2] * state.pVector[42]; // dL0/dCM
1007  state.jacobian[5] = 0.; // dL0/dT
1008 
1009  state.jacobian[6] = MB[0] * state.pVector[8] + MB[1] * state.pVector[9] +
1010  MB[2] * state.pVector[10]; // dL1/dL0
1011  state.jacobian[7] = MB[0] * state.pVector[16] + MB[1] * state.pVector[17] +
1012  MB[2] * state.pVector[18]; // dL1/dL1
1013  state.jacobian[8] = MB[0] * state.pVector[24] + MB[1] * state.pVector[25] +
1014  MB[2] * state.pVector[26]; // dL1/dPhi
1015  state.jacobian[9] = MB[0] * state.pVector[32] + MB[1] * state.pVector[33] +
1016  MB[2] * state.pVector[34]; // dL1/dThe
1017  state.jacobian[10] = MB[0] * state.pVector[40] + MB[1] * state.pVector[41] +
1018  MB[2] * state.pVector[42]; // dL1/dCM
1019  state.jacobian[11] = 0.; // dL1/dT
1020 
1021  state.jacobian[12] =
1022  P3 * state.pVector[13] - P4 * state.pVector[12]; // dPhi/dL0
1023  state.jacobian[13] =
1024  P3 * state.pVector[21] - P4 * state.pVector[20]; // dPhi/dL1
1025  state.jacobian[14] =
1026  P3 * state.pVector[29] - P4 * state.pVector[28]; // dPhi/dPhi
1027  state.jacobian[15] =
1028  P3 * state.pVector[37] - P4 * state.pVector[36]; // dPhi/dThe
1029  state.jacobian[16] =
1030  P3 * state.pVector[45] - P4 * state.pVector[44]; // dPhi/dCM
1031  state.jacobian[17] = 0.; // dPhi/dT
1032 
1033  state.jacobian[18] = C * state.pVector[14]; // dThe/dL0
1034  state.jacobian[19] = C * state.pVector[22]; // dThe/dL1
1035  state.jacobian[20] = C * state.pVector[30]; // dThe/dPhi
1036  state.jacobian[21] = C * state.pVector[38]; // dThe/dThe
1037  state.jacobian[22] = C * state.pVector[46]; // dThe/dCM
1038  state.jacobian[23] = 0.; // dThe/dT
1039 
1040  state.jacobian[24] = 0.; // dCM /dL0
1041  state.jacobian[25] = 0.; // dCM /dL1
1042  state.jacobian[26] = 0.; // dCM /dPhi
1043  state.jacobian[27] = 0.; // dCM /dTheta
1044  state.jacobian[28] = state.pVector[47]; // dCM /dCM
1045  state.jacobian[29] = 0.; // dCM/dT
1046 
1047  state.jacobian[30] = state.pVector[11]; // dT/dL0
1048  state.jacobian[31] = state.pVector[19]; // dT/dL1
1049  state.jacobian[32] = state.pVector[27]; // dT/dPhi
1050  state.jacobian[33] = state.pVector[35]; // dT/dThe
1051  state.jacobian[34] = state.pVector[43]; // dT/dCM
1052  state.jacobian[35] = state.pVector[51]; // dT/dT
1053 
1054  Eigen::Map<Eigen::Matrix<double, eBoundParametersSize, eBoundParametersSize,
1055  Eigen::RowMajor>>
1056  J(state.jacobian);
1057  state.cov = J * (*state.covariance) * J.transpose();
1058  }
1059 
1063  template <typename propagator_state_t>
1064  Result<double> step(propagator_state_t& state) const {
1065  // we use h for keeping the nominclature with the original atlas code
1066  auto& h = state.stepping.stepSize;
1067  bool Jac = state.stepping.useJacobian;
1068 
1069  double* R = &(state.stepping.pVector[0]); // Coordinates
1070  double* A = &(state.stepping.pVector[4]); // Directions
1071  double* sA = &(state.stepping.pVector[56]);
1072  // Invert mometum/2.
1073  double Pi = 0.5 * state.stepping.pVector[7];
1074  // double dltm = 0.0002 * .03;
1075  Vector3D f0, f;
1076 
1077  // if new field is required get it
1078  if (state.stepping.newfield) {
1079  const Vector3D pos(R[0], R[1], R[2]);
1080  // This is sd.B_first in EigenStepper
1081  f0 = getField(state.stepping, pos);
1082  } else {
1083  f0 = state.stepping.field;
1084  }
1085 
1086  bool Helix = false;
1087  // if (std::abs(S) < m_cfg.helixStep) Helix = true;
1088 
1089  while (h != 0.) {
1090  // PS2 is h/(2*momentum) in EigenStepper
1091  double S3 = (1. / 3.) * h, S4 = .25 * h, PS2 = Pi * h;
1092 
1093  // First point
1094  //
1095  // H0 is (h/(2*momentum) * sd.B_first) in EigenStepper
1096  double H0[3] = {f0[0] * PS2, f0[1] * PS2, f0[2] * PS2};
1097  // { A0, B0, C0 } is (h/2 * sd.k1) in EigenStepper
1098  double A0 = A[1] * H0[2] - A[2] * H0[1];
1099  double B0 = A[2] * H0[0] - A[0] * H0[2];
1100  double C0 = A[0] * H0[1] - A[1] * H0[0];
1101  // { A2, B2, C2 } is (h/2 * sd.k1 + direction) in EigenStepper
1102  double A2 = A0 + A[0];
1103  double B2 = B0 + A[1];
1104  double C2 = C0 + A[2];
1105  // { A1, B1, C1 } is (h/2 * sd.k1 + 2*direction) in EigenStepper
1106  double A1 = A2 + A[0];
1107  double B1 = B2 + A[1];
1108  double C1 = C2 + A[2];
1109 
1110  // Second point
1111  //
1112  if (!Helix) {
1113  // This is pos1 in EigenStepper
1114  const Vector3D pos(R[0] + A1 * S4, R[1] + B1 * S4, R[2] + C1 * S4);
1115  // This is sd.B_middle in EigenStepper
1116  f = getField(state.stepping, pos);
1117  } else {
1118  f = f0;
1119  }
1120 
1121  // H1 is (h/(2*momentum) * sd.B_middle) in EigenStepper
1122  double H1[3] = {f[0] * PS2, f[1] * PS2, f[2] * PS2};
1123  // { A3, B3, C3 } is (direction + h/2 * sd.k2) in EigenStepper
1124  double A3 = (A[0] + B2 * H1[2]) - C2 * H1[1];
1125  double B3 = (A[1] + C2 * H1[0]) - A2 * H1[2];
1126  double C3 = (A[2] + A2 * H1[1]) - B2 * H1[0];
1127  // { A4, B4, C4 } is (direction + h/2 * sd.k3) in EigenStepper
1128  double A4 = (A[0] + B3 * H1[2]) - C3 * H1[1];
1129  double B4 = (A[1] + C3 * H1[0]) - A3 * H1[2];
1130  double C4 = (A[2] + A3 * H1[1]) - B3 * H1[0];
1131  // { A5, B5, C5 } is (direction + h * sd.k3) in EigenStepper
1132  double A5 = 2. * A4 - A[0];
1133  double B5 = 2. * B4 - A[1];
1134  double C5 = 2. * C4 - A[2];
1135 
1136  // Last point
1137  //
1138  if (!Helix) {
1139  // This is pos2 in EigenStepper
1140  const Vector3D pos(R[0] + h * A4, R[1] + h * B4, R[2] + h * C4);
1141  // This is sd.B_last in Eigen stepper
1142  f = getField(state.stepping, pos);
1143  } else {
1144  f = f0;
1145  }
1146 
1147  // H2 is (h/(2*momentum) * sd.B_last) in EigenStepper
1148  double H2[3] = {f[0] * PS2, f[1] * PS2, f[2] * PS2};
1149  // { A6, B6, C6 } is (h/2 * sd.k4) in EigenStepper
1150  double A6 = B5 * H2[2] - C5 * H2[1];
1151  double B6 = C5 * H2[0] - A5 * H2[2];
1152  double C6 = A5 * H2[1] - B5 * H2[0];
1153 
1154  // Test approximation quality on give step and possible step reduction
1155  //
1156  // This is (h2 * (sd.k1 - sd.k2 - sd.k3 + sd.k4).template lpNorm<1>())
1157  // in EigenStepper
1158  double EST =
1159  2. * h *
1160  (std::abs((A1 + A6) - (A3 + A4)) + std::abs((B1 + B6) - (B3 + B4)) +
1161  std::abs((C1 + C6) - (C3 + C4)));
1162  if (EST > state.options.tolerance) {
1163  h = h * .5;
1164  // dltm = 0.;
1165  continue;
1166  }
1167 
1168  // if (EST < dltm) h *= 2.;
1169 
1170  // Parameters calculation
1171  //
1172  double A00 = A[0], A11 = A[1], A22 = A[2];
1173 
1174  A[0] = 2. * A3 + (A0 + A5 + A6);
1175  A[1] = 2. * B3 + (B0 + B5 + B6);
1176  A[2] = 2. * C3 + (C0 + C5 + C6);
1177 
1178  double D = (A[0] * A[0] + A[1] * A[1]) + (A[2] * A[2] - 9.);
1179  double Sl = 2. / h;
1180  D = (1. / 3.) - ((1. / 648.) * D) * (12. - D);
1181 
1182  R[0] += (A2 + A3 + A4) * S3;
1183  R[1] += (B2 + B3 + B4) * S3;
1184  R[2] += (C2 + C3 + C4) * S3;
1185  A[0] *= D;
1186  A[1] *= D;
1187  A[2] *= D;
1188  sA[0] = A6 * Sl;
1189  sA[1] = B6 * Sl;
1190  sA[2] = C6 * Sl;
1191 
1192  // Evaluate the time propagation
1193  state.stepping.pVector[3] +=
1194  h * std::hypot(1, state.options.mass / momentum(state.stepping));
1195  state.stepping.pVector[59] =
1196  std::hypot(1, state.options.mass / momentum(state.stepping));
1197  state.stepping.field = f;
1198  state.stepping.newfield = false;
1199 
1200  if (Jac) {
1201  double dtdl =
1202  h * state.options.mass * state.options.mass *
1203  charge(state.stepping) /
1204  (momentum(state.stepping) *
1205  std::hypot(1., state.options.mass / momentum(state.stepping)));
1206  state.stepping.pVector[43] += dtdl;
1207 
1208  // Jacobian calculation
1209  //
1210  double* d2A = &state.stepping.pVector[28];
1211  double* d3A = &state.stepping.pVector[36];
1212  double* d4A = &state.stepping.pVector[44];
1213  double d2A0 = H0[2] * d2A[1] - H0[1] * d2A[2];
1214  double d2B0 = H0[0] * d2A[2] - H0[2] * d2A[0];
1215  double d2C0 = H0[1] * d2A[0] - H0[0] * d2A[1];
1216  double d3A0 = H0[2] * d3A[1] - H0[1] * d3A[2];
1217  double d3B0 = H0[0] * d3A[2] - H0[2] * d3A[0];
1218  double d3C0 = H0[1] * d3A[0] - H0[0] * d3A[1];
1219  double d4A0 = (A0 + H0[2] * d4A[1]) - H0[1] * d4A[2];
1220  double d4B0 = (B0 + H0[0] * d4A[2]) - H0[2] * d4A[0];
1221  double d4C0 = (C0 + H0[1] * d4A[0]) - H0[0] * d4A[1];
1222  double d2A2 = d2A0 + d2A[0];
1223  double d2B2 = d2B0 + d2A[1];
1224  double d2C2 = d2C0 + d2A[2];
1225  double d3A2 = d3A0 + d3A[0];
1226  double d3B2 = d3B0 + d3A[1];
1227  double d3C2 = d3C0 + d3A[2];
1228  double d4A2 = d4A0 + d4A[0];
1229  double d4B2 = d4B0 + d4A[1];
1230  double d4C2 = d4C0 + d4A[2];
1231  double d0 = d4A[0] - A00;
1232  double d1 = d4A[1] - A11;
1233  double d2 = d4A[2] - A22;
1234  double d2A3 = (d2A[0] + d2B2 * H1[2]) - d2C2 * H1[1];
1235  double d2B3 = (d2A[1] + d2C2 * H1[0]) - d2A2 * H1[2];
1236  double d2C3 = (d2A[2] + d2A2 * H1[1]) - d2B2 * H1[0];
1237  double d3A3 = (d3A[0] + d3B2 * H1[2]) - d3C2 * H1[1];
1238  double d3B3 = (d3A[1] + d3C2 * H1[0]) - d3A2 * H1[2];
1239  double d3C3 = (d3A[2] + d3A2 * H1[1]) - d3B2 * H1[0];
1240  double d4A3 = ((A3 + d0) + d4B2 * H1[2]) - d4C2 * H1[1];
1241  double d4B3 = ((B3 + d1) + d4C2 * H1[0]) - d4A2 * H1[2];
1242  double d4C3 = ((C3 + d2) + d4A2 * H1[1]) - d4B2 * H1[0];
1243  double d2A4 = (d2A[0] + d2B3 * H1[2]) - d2C3 * H1[1];
1244  double d2B4 = (d2A[1] + d2C3 * H1[0]) - d2A3 * H1[2];
1245  double d2C4 = (d2A[2] + d2A3 * H1[1]) - d2B3 * H1[0];
1246  double d3A4 = (d3A[0] + d3B3 * H1[2]) - d3C3 * H1[1];
1247  double d3B4 = (d3A[1] + d3C3 * H1[0]) - d3A3 * H1[2];
1248  double d3C4 = (d3A[2] + d3A3 * H1[1]) - d3B3 * H1[0];
1249  double d4A4 = ((A4 + d0) + d4B3 * H1[2]) - d4C3 * H1[1];
1250  double d4B4 = ((B4 + d1) + d4C3 * H1[0]) - d4A3 * H1[2];
1251  double d4C4 = ((C4 + d2) + d4A3 * H1[1]) - d4B3 * H1[0];
1252  double d2A5 = 2. * d2A4 - d2A[0];
1253  double d2B5 = 2. * d2B4 - d2A[1];
1254  double d2C5 = 2. * d2C4 - d2A[2];
1255  double d3A5 = 2. * d3A4 - d3A[0];
1256  double d3B5 = 2. * d3B4 - d3A[1];
1257  double d3C5 = 2. * d3C4 - d3A[2];
1258  double d4A5 = 2. * d4A4 - d4A[0];
1259  double d4B5 = 2. * d4B4 - d4A[1];
1260  double d4C5 = 2. * d4C4 - d4A[2];
1261  double d2A6 = d2B5 * H2[2] - d2C5 * H2[1];
1262  double d2B6 = d2C5 * H2[0] - d2A5 * H2[2];
1263  double d2C6 = d2A5 * H2[1] - d2B5 * H2[0];
1264  double d3A6 = d3B5 * H2[2] - d3C5 * H2[1];
1265  double d3B6 = d3C5 * H2[0] - d3A5 * H2[2];
1266  double d3C6 = d3A5 * H2[1] - d3B5 * H2[0];
1267  double d4A6 = d4B5 * H2[2] - d4C5 * H2[1];
1268  double d4B6 = d4C5 * H2[0] - d4A5 * H2[2];
1269  double d4C6 = d4A5 * H2[1] - d4B5 * H2[0];
1270 
1271  double* dR = &state.stepping.pVector[24];
1272  dR[0] += (d2A2 + d2A3 + d2A4) * S3;
1273  dR[1] += (d2B2 + d2B3 + d2B4) * S3;
1274  dR[2] += (d2C2 + d2C3 + d2C4) * S3;
1275  d2A[0] = ((d2A0 + 2. * d2A3) + (d2A5 + d2A6)) * (1. / 3.);
1276  d2A[1] = ((d2B0 + 2. * d2B3) + (d2B5 + d2B6)) * (1. / 3.);
1277  d2A[2] = ((d2C0 + 2. * d2C3) + (d2C5 + d2C6)) * (1. / 3.);
1278 
1279  dR = &state.stepping.pVector[32];
1280  dR[0] += (d3A2 + d3A3 + d3A4) * S3;
1281  dR[1] += (d3B2 + d3B3 + d3B4) * S3;
1282  dR[2] += (d3C2 + d3C3 + d3C4) * S3;
1283  d3A[0] = ((d3A0 + 2. * d3A3) + (d3A5 + d3A6)) * (1. / 3.);
1284  d3A[1] = ((d3B0 + 2. * d3B3) + (d3B5 + d3B6)) * (1. / 3.);
1285  d3A[2] = ((d3C0 + 2. * d3C3) + (d3C5 + d3C6)) * (1. / 3.);
1286 
1287  dR = &state.stepping.pVector[40];
1288  dR[0] += (d4A2 + d4A3 + d4A4) * S3;
1289  dR[1] += (d4B2 + d4B3 + d4B4) * S3;
1290  dR[2] += (d4C2 + d4C3 + d4C4) * S3;
1291  d4A[0] = ((d4A0 + 2. * d4A3) + (d4A5 + d4A6 + A6)) * (1. / 3.);
1292  d4A[1] = ((d4B0 + 2. * d4B3) + (d4B5 + d4B6 + B6)) * (1. / 3.);
1293  d4A[2] = ((d4C0 + 2. * d4C3) + (d4C5 + d4C6 + C6)) * (1. / 3.);
1294  }
1295 
1296  state.stepping.pathAccumulated += h;
1297  return h;
1298  }
1299 
1300  // that exit path should actually not happen
1301  state.stepping.pathAccumulated += h;
1302  return h;
1303  }
1304 
1305  private:
1307 
1309  double m_overstepLimit = -50_um;
1310 };
1311 
1312 } // namespace Acts