Analysis Software
Documentation for sPHENIX simulation 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-2022 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 // Workaround for building on clang+libstdc++
13 
27 
28 #include <cmath>
29 #include <functional>
30 
31 // This is based original stepper code from the ATLAS RungeKuttaPropagator
32 namespace Acts {
33 
35 class AtlasStepper {
36  public:
39  using BoundState = std::tuple<BoundTrackParameters, Jacobian, double>;
40  using CurvilinearState =
41  std::tuple<CurvilinearTrackParameters, Jacobian, double>;
42 
44  struct State {
46  State() = delete;
47 
57  template <typename Parameters>
59  MagneticFieldProvider::Cache fieldCacheIn, const Parameters& pars,
60  double ssize = std::numeric_limits<double>::max(),
61  double stolerance = s_onSurfaceTolerance)
63  field(0., 0., 0.),
64  stepSize(ssize),
65  tolerance(stolerance),
66  fieldCache(std::move(fieldCacheIn)),
67  geoContext(gctx) {
68  // The rest of this constructor is copy&paste of AtlasStepper::update() -
69  // this is a nasty but working solution for the stepper state without
70  // functions
71 
72  const auto pos = pars.position(gctx);
73  const auto Vp = pars.parameters();
74 
75  double Sf = std::sin(Vp[eBoundPhi]);
76  double Cf = std::cos(Vp[eBoundPhi]);
77  double Se = std::sin(Vp[eBoundTheta]);
78  double Ce = std::cos(Vp[eBoundTheta]);
79 
80  pVector[0] = pos[ePos0];
81  pVector[1] = pos[ePos1];
82  pVector[2] = pos[ePos2];
83  pVector[3] = pars.time();
84  pVector[4] = Cf * Se;
85  pVector[5] = Sf * Se;
86  pVector[6] = Ce;
87  pVector[7] = Vp[eBoundQOverP];
88 
89  // @todo: remove magic numbers - is that the charge ?
90  if (std::abs(pVector[7]) < .000000000000001) {
91  pVector[7] < 0. ? pVector[7] = -.000000000000001
92  : pVector[7] = .000000000000001;
93  }
94 
95  // prepare the jacobian if we have a covariance
96  if (pars.covariance()) {
97  // copy the covariance matrix
98  covariance = new BoundSquareMatrix(*pars.covariance());
99  covTransport = true;
100  useJacobian = true;
101  const auto transform = pars.referenceSurface().referenceFrame(
102  geoContext, pos, pars.direction());
103 
104  pVector[8] = transform(0, eBoundLoc0);
105  pVector[16] = transform(0, eBoundLoc1);
106  pVector[24] = 0.;
107  pVector[32] = 0.;
108  pVector[40] = 0.;
109  pVector[48] = 0.; // dX /
110 
111  pVector[9] = transform(1, eBoundLoc0);
112  pVector[17] = transform(1, eBoundLoc1);
113  pVector[25] = 0.;
114  pVector[33] = 0.;
115  pVector[41] = 0.;
116  pVector[49] = 0.; // dY /
117 
118  pVector[10] = transform(2, eBoundLoc0);
119  pVector[18] = transform(2, eBoundLoc1);
120  pVector[26] = 0.;
121  pVector[34] = 0.;
122  pVector[42] = 0.;
123  pVector[50] = 0.; // dZ /
124 
125  pVector[11] = 0.;
126  pVector[19] = 0.;
127  pVector[27] = 0.;
128  pVector[35] = 0.;
129  pVector[43] = 0.;
130  pVector[51] = 1.; // dT/
131 
132  pVector[12] = 0.;
133  pVector[20] = 0.;
134  pVector[28] = -Sf * Se; // - sin(phi) * cos(theta)
135  pVector[36] = Cf * Ce; // cos(phi) * cos(theta)
136  pVector[44] = 0.;
137  pVector[52] = 0.; // dAx/
138 
139  pVector[13] = 0.;
140  pVector[21] = 0.;
141  pVector[29] = Cf * Se; // cos(phi) * sin(theta)
142  pVector[37] = Sf * Ce; // sin(phi) * cos(theta)
143  pVector[45] = 0.;
144  pVector[53] = 0.; // dAy/
145 
146  pVector[14] = 0.;
147  pVector[22] = 0.;
148  pVector[30] = 0.;
149  pVector[38] = -Se; // - sin(theta)
150  pVector[46] = 0.;
151  pVector[54] = 0.; // dAz/
152 
153  pVector[15] = 0.;
154  pVector[23] = 0.;
155  pVector[31] = 0.;
156  pVector[39] = 0.;
157  pVector[47] = 1.;
158  pVector[55] = 0.; // dCM/
159 
160  pVector[56] = 0.;
161  pVector[57] = 0.;
162  pVector[58] = 0.;
163  pVector[59] = 0.;
164 
165  // special treatment for surface types
166  const auto& surface = pars.referenceSurface();
167  // the disc needs polar coordinate adaptations
168  if (surface.type() == Surface::Disc) {
169  double lCf = std::cos(Vp[1]);
170  double lSf = std::sin(Vp[1]);
171  double Ax[3] = {transform(0, 0), transform(1, 0), transform(2, 0)};
172  double Ay[3] = {transform(0, 1), transform(1, 1), transform(2, 1)};
173  double d0 = lCf * Ax[0] + lSf * Ay[0];
174  double d1 = lCf * Ax[1] + lSf * Ay[1];
175  double d2 = lCf * Ax[2] + lSf * Ay[2];
176  pVector[8] = d0;
177  pVector[9] = d1;
178  pVector[10] = d2;
179  pVector[16] = Vp[0] * (lCf * Ay[0] - lSf * Ax[0]);
180  pVector[17] = Vp[0] * (lCf * Ay[1] - lSf * Ax[1]);
181  pVector[18] = Vp[0] * (lCf * Ay[2] - lSf * Ax[2]);
182  }
183  // the line needs components that relate direction change
184  // with global frame change
185  if (surface.type() == Surface::Perigee ||
186  surface.type() == Surface::Straw) {
187  // sticking to the nomenclature of the original RkPropagator
188  // - axis pointing along the drift/transverse direction
189  double B[3] = {transform(0, 0), transform(1, 0), transform(2, 0)};
190  // - axis along the straw
191  double A[3] = {transform(0, 1), transform(1, 1), transform(2, 1)};
192  // - normal vector of the reference frame
193  double C[3] = {transform(0, 2), transform(1, 2), transform(2, 2)};
194 
195  // projection of direction onto normal vector of reference frame
196  double PC = pVector[4] * C[0] + pVector[5] * C[1] + pVector[6] * C[2];
197  double Bn = 1. / PC;
198 
199  double Bx2 = -A[2] * pVector[29];
200  double Bx3 = A[1] * pVector[38] - A[2] * pVector[37];
201 
202  double By2 = A[2] * pVector[28];
203  double By3 = A[2] * pVector[36] - A[0] * pVector[38];
204 
205  double Bz2 = A[0] * pVector[29] - A[1] * pVector[28];
206  double Bz3 = A[0] * pVector[37] - A[1] * pVector[36];
207 
208  double B2 = B[0] * Bx2 + B[1] * By2 + B[2] * Bz2;
209  double B3 = B[0] * Bx3 + B[1] * By3 + B[2] * Bz3;
210 
211  Bx2 = (Bx2 - B[0] * B2) * Bn;
212  Bx3 = (Bx3 - B[0] * B3) * Bn;
213  By2 = (By2 - B[1] * B2) * Bn;
214  By3 = (By3 - B[1] * B3) * Bn;
215  Bz2 = (Bz2 - B[2] * B2) * Bn;
216  Bz3 = (Bz3 - B[2] * B3) * Bn;
217 
218  // /dPhi | /dThe |
219  pVector[24] = Bx2 * Vp[0];
220  pVector[32] = Bx3 * Vp[0]; // dX/
221  pVector[25] = By2 * Vp[0];
222  pVector[33] = By3 * Vp[0]; // dY/
223  pVector[26] = Bz2 * Vp[0];
224  pVector[34] = Bz3 * Vp[0]; // dZ/
225  }
226  }
227  // now declare the state as ready
228  state_ready = true;
229  }
230 
232 
233  // optimisation that init is not called twice
234  bool state_ready = false;
235  // configuration
236  bool useJacobian = false;
237  double step = 0;
238  double maxPathLength = 0;
239  bool mcondition = false;
240  bool needgradient = false;
241  bool newfield = true;
242  // internal parameters to be used
244  std::array<double, 60> pVector{};
245 
257 
258  // result
259  double parameters[eBoundSize] = {0., 0., 0., 0., 0., 0.};
260  const Covariance* covariance = nullptr;
261  Covariance cov = Covariance::Zero();
262  bool covTransport = false;
264 
265  // accummulated path length cache
266  double pathAccumulated = 0.;
267 
268  // Adaptive step size of the runge-kutta integration
270 
271  // Previous step size for overstep estimation
272  double previousStepSize = 0.;
273 
276 
280 
282  std::reference_wrapper<const GeometryContext> geoContext;
283 
286  bool debug = false;
289  size_t debugPfxWidth = 30;
290  size_t debugMsgWidth = 50;
291  };
292 
293  AtlasStepper(std::shared_ptr<const MagneticFieldProvider> bField)
294  : m_bField(std::move(bField)) {}
295 
296  State makeState(std::reference_wrapper<const GeometryContext> gctx,
297  std::reference_wrapper<const MagneticFieldContext> mctx,
298  const BoundTrackParameters& par,
299  double ssize = std::numeric_limits<double>::max(),
300  double stolerance = s_onSurfaceTolerance) const {
301  return State{gctx, m_bField->makeCache(mctx), par, ssize, stolerance};
302  }
303 
312  State& state, const BoundVector& boundParams,
313  const BoundSquareMatrix& cov, const Surface& surface,
314  const double stepSize = std::numeric_limits<double>::max()) const {
315  // Update the stepping state
316  update(state,
318  boundParams),
319  boundParams, cov, surface);
321  state.pathAccumulated = 0.;
322 
323  setIdentityJacobian(state);
324  }
325 
333  Result<Vector3> getField(State& state, const Vector3& pos) const {
334  // get the field from the cell
335  auto res = m_bField->getField(pos, state.fieldCache);
336  if (res.ok()) {
337  state.field = *res;
338  }
339  return res;
340  }
341 
342  Vector3 position(const State& state) const {
343  return Vector3(state.pVector[0], state.pVector[1], state.pVector[2]);
344  }
345 
346  Vector3 direction(const State& state) const {
347  return Vector3(state.pVector[4], state.pVector[5], state.pVector[6]);
348  }
349 
350  double qOverP(const State& state) const { return state.pVector[7]; }
351 
355  double absoluteMomentum(const State& state) const {
356  return particleHypothesis(state).extractMomentum(qOverP(state));
357  }
358 
359  Vector3 momentum(const State& state) const {
360  return absoluteMomentum(state) * direction(state);
361  }
362 
366  double charge(const State& state) const {
367  return particleHypothesis(state).extractCharge(qOverP(state));
368  }
369 
373  const ParticleHypothesis& particleHypothesis(const State& state) const {
374  return state.particleHypothesis;
375  }
376 
380  double overstepLimit(const State& state) const {
381  (void)state;
382  return -m_overstepLimit;
383  }
384 
386  double time(const State& state) const { return state.pVector[3]; }
387 
402  State& state, const Surface& surface, Direction navDir,
403  const BoundaryCheck& bcheck,
404  ActsScalar surfaceTolerance = s_onSurfaceTolerance,
405  const Logger& logger = getDummyLogger()) const {
406  return detail::updateSingleSurfaceStatus<AtlasStepper>(
407  *this, state, surface, navDir, bcheck, surfaceTolerance, logger);
408  }
409 
418  template <typename object_intersection_t>
419  void updateStepSize(State& state, const object_intersection_t& oIntersection,
420  Direction /*direction*/, bool release = true) const {
421  detail::updateSingleStepSize<AtlasStepper>(state, oIntersection, release);
422  }
423 
430  void setStepSize(State& state, double stepSize,
432  bool release = true) const {
433  state.previousStepSize = state.stepSize.value();
434  state.stepSize.update(stepSize, stype, release);
435  }
436 
441  double getStepSize(const State& state, ConstrainedStep::Type stype) const {
442  return state.stepSize.value(stype);
443  }
444 
448  void releaseStepSize(State& state) const {
450  }
451 
455  std::string outputStepSize(const State& state) const {
456  return state.stepSize.toString();
457  }
458 
472  State& state, const Surface& surface, bool transportCov = true,
473  const FreeToBoundCorrection& freeToBoundCorrection =
474  FreeToBoundCorrection(false)) const {
475  // the convert method invalidates the state (in case it's reused)
476  state.state_ready = false;
477  // extract state information
479  pos4[ePos0] = state.pVector[0];
480  pos4[ePos1] = state.pVector[1];
481  pos4[ePos2] = state.pVector[2];
482  pos4[eTime] = state.pVector[3];
483  Acts::Vector3 dir;
484  dir[eMom0] = state.pVector[4];
485  dir[eMom1] = state.pVector[5];
486  dir[eMom2] = state.pVector[6];
487  const auto qOverP = state.pVector[7];
488 
489  // The transport of the covariance
490  std::optional<Covariance> covOpt = std::nullopt;
491  if (state.covTransport && transportCov) {
492  transportCovarianceToBound(state, surface, freeToBoundCorrection);
493  }
494  if (state.cov != Covariance::Zero()) {
495  covOpt = state.cov;
496  }
497 
498  // Fill the end parameters
500  surface.getSharedPtr(), state.geoContext, pos4, dir, qOverP,
501  std::move(covOpt), state.particleHypothesis);
502  if (!parameters.ok()) {
503  return parameters.error();
504  }
505 
506  Jacobian jacobian(state.jacobian);
507 
508  return BoundState(std::move(*parameters), jacobian.transpose(),
509  state.pathAccumulated);
510  }
511 
523  bool transportCov = true) const {
524  // the convert method invalidates the state (in case it's reused)
525  state.state_ready = false;
526  // extract state information
528  pos4[ePos0] = state.pVector[0];
529  pos4[ePos1] = state.pVector[1];
530  pos4[ePos2] = state.pVector[2];
531  pos4[eTime] = state.pVector[3];
532  Acts::Vector3 dir;
533  dir[eMom0] = state.pVector[4];
534  dir[eMom1] = state.pVector[5];
535  dir[eMom2] = state.pVector[6];
536  const auto qOverP = state.pVector[7];
537 
538  std::optional<Covariance> covOpt = std::nullopt;
539  if (state.covTransport && transportCov) {
541  }
542  if (state.cov != Covariance::Zero()) {
543  covOpt = state.cov;
544  }
545 
547  state.particleHypothesis);
548 
549  Jacobian jacobian(state.jacobian);
550 
551  return CurvilinearState(std::move(parameters), jacobian.transpose(),
552  state.pathAccumulated);
553  }
554 
562  void update(State& state, const FreeVector& parameters,
563  const BoundVector& boundParams, const Covariance& covariance,
564  const Surface& surface) const {
565  Vector3 direction = parameters.template segment<3>(eFreeDir0).normalized();
566  state.pVector[0] = parameters[eFreePos0];
567  state.pVector[1] = parameters[eFreePos1];
568  state.pVector[2] = parameters[eFreePos2];
569  state.pVector[3] = parameters[eFreeTime];
570  state.pVector[4] = direction.x();
571  state.pVector[5] = direction.y();
572  state.pVector[6] = direction.z();
573  state.pVector[7] = std::copysign(parameters[eFreeQOverP], state.pVector[7]);
574 
575  // @todo: remove magic numbers - is that the charge ?
576  if (std::abs(state.pVector[7]) < .000000000000001) {
577  state.pVector[7] < 0. ? state.pVector[7] = -.000000000000001
578  : state.pVector[7] = .000000000000001;
579  }
580 
581  // prepare the jacobian if we have a covariance
582  // copy the covariance matrix
583 
584  Vector3 pos(state.pVector[0], state.pVector[1], state.pVector[2]);
585  Vector3 mom(state.pVector[4], state.pVector[5], state.pVector[6]);
586 
587  double Sf = std::sin(boundParams[eBoundPhi]);
588  double Cf = std::cos(boundParams[eBoundPhi]);
589  double Se = std::sin(boundParams[eBoundTheta]);
590  double Ce = std::cos(boundParams[eBoundTheta]);
591 
592  const auto transform = surface.referenceFrame(state.geoContext, pos, mom);
593 
594  state.pVector[8] = transform(0, eBoundLoc0);
595  state.pVector[16] = transform(0, eBoundLoc1);
596  state.pVector[24] = 0.;
597  state.pVector[32] = 0.;
598  state.pVector[40] = 0.;
599  state.pVector[48] = 0.; // dX /
600 
601  state.pVector[9] = transform(1, eBoundLoc0);
602  state.pVector[17] = transform(1, eBoundLoc1);
603  state.pVector[25] = 0.;
604  state.pVector[33] = 0.;
605  state.pVector[41] = 0.;
606  state.pVector[49] = 0.; // dY /
607 
608  state.pVector[10] = transform(2, eBoundLoc0);
609  state.pVector[18] = transform(2, eBoundLoc1);
610  state.pVector[26] = 0.;
611  state.pVector[34] = 0.;
612  state.pVector[42] = 0.;
613  state.pVector[50] = 0.; // dZ /
614 
615  state.pVector[11] = 0.;
616  state.pVector[19] = 0.;
617  state.pVector[27] = 0.;
618  state.pVector[35] = 0.;
619  state.pVector[43] = 0.;
620  state.pVector[51] = 1.; // dT/
621 
622  state.pVector[12] = 0.;
623  state.pVector[20] = 0.;
624  state.pVector[28] = -Sf * Se; // - sin(phi) * cos(theta)
625  state.pVector[36] = Cf * Ce; // cos(phi) * cos(theta)
626  state.pVector[44] = 0.;
627  state.pVector[52] = 0.; // dAx/
628 
629  state.pVector[13] = 0.;
630  state.pVector[21] = 0.;
631  state.pVector[29] = Cf * Se; // cos(phi) * sin(theta)
632  state.pVector[37] = Sf * Ce; // sin(phi) * cos(theta)
633  state.pVector[45] = 0.;
634  state.pVector[53] = 0.; // dAy/
635 
636  state.pVector[14] = 0.;
637  state.pVector[22] = 0.;
638  state.pVector[30] = 0.;
639  state.pVector[38] = -Se; // - sin(theta)
640  state.pVector[46] = 0.;
641  state.pVector[54] = 0.; // dAz/
642 
643  state.pVector[15] = 0.;
644  state.pVector[23] = 0.;
645  state.pVector[31] = 0.;
646  state.pVector[39] = 0.;
647  state.pVector[47] = 1.;
648  state.pVector[55] = 0.; // dCM/
649 
650  state.pVector[56] = 0.;
651  state.pVector[57] = 0.;
652  state.pVector[58] = 0.;
653  state.pVector[59] = 0.;
654 
655  // special treatment for surface types
656  // the disc needs polar coordinate adaptations
657  if (surface.type() == Surface::Disc) {
658  double lCf = std::cos(boundParams[eBoundLoc1]);
659  double lSf = std::sin(boundParams[eBoundLoc1]);
660  double Ax[3] = {transform(0, 0), transform(1, 0), transform(2, 0)};
661  double Ay[3] = {transform(0, 1), transform(1, 1), transform(2, 1)};
662  double d0 = lCf * Ax[0] + lSf * Ay[0];
663  double d1 = lCf * Ax[1] + lSf * Ay[1];
664  double d2 = lCf * Ax[2] + lSf * Ay[2];
665  state.pVector[8] = d0;
666  state.pVector[9] = d1;
667  state.pVector[10] = d2;
668  state.pVector[16] = boundParams[eBoundLoc0] * (lCf * Ay[0] - lSf * Ax[0]);
669  state.pVector[17] = boundParams[eBoundLoc0] * (lCf * Ay[1] - lSf * Ax[1]);
670  state.pVector[18] = boundParams[eBoundLoc0] * (lCf * Ay[2] - lSf * Ax[2]);
671  }
672  // the line needs components that relate direction change
673  // with global frame change
674  if (surface.type() == Surface::Perigee ||
675  surface.type() == Surface::Straw) {
676  // sticking to the nomenclature of the original RkPropagator
677  // - axis pointing along the drift/transverse direction
678  double B[3] = {transform(0, 0), transform(1, 0), transform(2, 0)};
679  // - axis along the straw
680  double A[3] = {transform(0, 1), transform(1, 1), transform(2, 1)};
681  // - normal vector of the reference frame
682  double C[3] = {transform(0, 2), transform(1, 2), transform(2, 2)};
683 
684  // projection of direction onto normal vector of reference frame
685  double PC = state.pVector[4] * C[0] + state.pVector[5] * C[1] +
686  state.pVector[6] * C[2];
687  double Bn = 1. / PC;
688 
689  double Bx2 = -A[2] * state.pVector[29];
690  double Bx3 = A[1] * state.pVector[38] - A[2] * state.pVector[37];
691 
692  double By2 = A[2] * state.pVector[28];
693  double By3 = A[2] * state.pVector[36] - A[0] * state.pVector[38];
694 
695  double Bz2 = A[0] * state.pVector[29] - A[1] * state.pVector[28];
696  double Bz3 = A[0] * state.pVector[37] - A[1] * state.pVector[36];
697 
698  double B2 = B[0] * Bx2 + B[1] * By2 + B[2] * Bz2;
699  double B3 = B[0] * Bx3 + B[1] * By3 + B[2] * Bz3;
700 
701  Bx2 = (Bx2 - B[0] * B2) * Bn;
702  Bx3 = (Bx3 - B[0] * B3) * Bn;
703  By2 = (By2 - B[1] * B2) * Bn;
704  By3 = (By3 - B[1] * B3) * Bn;
705  Bz2 = (Bz2 - B[2] * B2) * Bn;
706  Bz3 = (Bz3 - B[2] * B3) * Bn;
707 
708  // /dPhi | /dThe |
709  state.pVector[24] = Bx2 * boundParams[eBoundLoc0];
710  state.pVector[32] = Bx3 * boundParams[eBoundLoc0]; // dX/
711  state.pVector[25] = By2 * boundParams[eBoundLoc0];
712  state.pVector[33] = By3 * boundParams[eBoundLoc0]; // dY/
713  state.pVector[26] = Bz2 * boundParams[eBoundLoc0];
714  state.pVector[34] = Bz3 * boundParams[eBoundLoc0]; // dZ/
715  }
716 
717  state.covariance = new BoundSquareMatrix(covariance);
718  state.covTransport = true;
719  state.useJacobian = true;
720 
721  // declare the state as ready
722  state.state_ready = true;
723  }
724 
732  void update(State& state, const Vector3& uposition, const Vector3& udirection,
733  double qop, double time) const {
734  // update the vector
735  state.pVector[0] = uposition[0];
736  state.pVector[1] = uposition[1];
737  state.pVector[2] = uposition[2];
738  state.pVector[3] = time;
739  state.pVector[4] = udirection[0];
740  state.pVector[5] = udirection[1];
741  state.pVector[6] = udirection[2];
742  state.pVector[7] = qop;
743  }
744 
751  double P[60];
752  for (unsigned int i = 0; i < 60; ++i) {
753  P[i] = state.pVector[i];
754  }
755 
756  double p = 1. / P[7];
757  P[40] *= p;
758  P[41] *= p;
759  P[42] *= p;
760  P[44] *= p;
761  P[45] *= p;
762  P[46] *= p;
763 
764  double An = std::hypot(P[4], P[5]);
765  double Ax[3];
766  if (An != 0.) {
767  Ax[0] = -P[5] / An;
768  Ax[1] = P[4] / An;
769  Ax[2] = 0.;
770  } else {
771  Ax[0] = 1.;
772  Ax[1] = 0.;
773  Ax[2] = 0.;
774  }
775 
776  double Ay[3] = {-Ax[1] * P[6], Ax[0] * P[6], An};
777  double S[3] = {P[4], P[5], P[6]};
778 
779  double A = P[4] * S[0] + P[5] * S[1] + P[6] * S[2];
780  if (A != 0.) {
781  A = 1. / A;
782  }
783  S[0] *= A;
784  S[1] *= A;
785  S[2] *= A;
786 
787  double s0 = P[8] * S[0] + P[9] * S[1] + P[10] * S[2];
788  double s1 = P[16] * S[0] + P[17] * S[1] + P[18] * S[2];
789  double s2 = P[24] * S[0] + P[25] * S[1] + P[26] * S[2];
790  double s3 = P[32] * S[0] + P[33] * S[1] + P[34] * S[2];
791  double s4 = P[40] * S[0] + P[41] * S[1] + P[42] * S[2];
792 
793  P[8] -= (s0 * P[4]);
794  P[9] -= (s0 * P[5]);
795  P[10] -= (s0 * P[6]);
796  P[11] -= (s0 * P[59]);
797  P[12] -= (s0 * P[56]);
798  P[13] -= (s0 * P[57]);
799  P[14] -= (s0 * P[58]);
800  P[16] -= (s1 * P[4]);
801  P[17] -= (s1 * P[5]);
802  P[18] -= (s1 * P[6]);
803  P[19] -= (s1 * P[59]);
804  P[20] -= (s1 * P[56]);
805  P[21] -= (s1 * P[57]);
806  P[22] -= (s1 * P[58]);
807  P[24] -= (s2 * P[4]);
808  P[25] -= (s2 * P[5]);
809  P[26] -= (s2 * P[6]);
810  P[27] -= (s2 * P[59]);
811  P[28] -= (s2 * P[56]);
812  P[29] -= (s2 * P[57]);
813  P[30] -= (s2 * P[58]);
814  P[32] -= (s3 * P[4]);
815  P[33] -= (s3 * P[5]);
816  P[34] -= (s3 * P[6]);
817  P[35] -= (s3 * P[59]);
818  P[36] -= (s3 * P[56]);
819  P[37] -= (s3 * P[57]);
820  P[38] -= (s3 * P[58]);
821  P[40] -= (s4 * P[4]);
822  P[41] -= (s4 * P[5]);
823  P[42] -= (s4 * P[6]);
824  P[43] -= (s4 * P[59]);
825  P[44] -= (s4 * P[56]);
826  P[45] -= (s4 * P[57]);
827  P[46] -= (s4 * P[58]);
828 
829  double P3 = 0, P4 = 0, C = P[4] * P[4] + P[5] * P[5];
830  if (C > 1.e-20) {
831  C = 1. / C;
832  P3 = P[4] * C;
833  P4 = P[5] * C;
834  C = -sqrt(C);
835  } else {
836  C = -1.e10;
837  P3 = 1.;
838  P4 = 0.;
839  }
840 
841  // Jacobian production
842  //
843  state.jacobian[0] = Ax[0] * P[8] + Ax[1] * P[9]; // dL0/dL0
844  state.jacobian[1] = Ax[0] * P[16] + Ax[1] * P[17]; // dL0/dL1
845  state.jacobian[2] = Ax[0] * P[24] + Ax[1] * P[25]; // dL0/dPhi
846  state.jacobian[3] = Ax[0] * P[32] + Ax[1] * P[33]; // dL0/dThe
847  state.jacobian[4] = Ax[0] * P[40] + Ax[1] * P[41]; // dL0/dCM
848  state.jacobian[5] = 0.; // dL0/dT
849 
850  state.jacobian[6] = Ay[0] * P[8] + Ay[1] * P[9] + Ay[2] * P[10]; // dL1/dL0
851  state.jacobian[7] =
852  Ay[0] * P[16] + Ay[1] * P[17] + Ay[2] * P[18]; // dL1/dL1
853  state.jacobian[8] =
854  Ay[0] * P[24] + Ay[1] * P[25] + Ay[2] * P[26]; // dL1/dPhi
855  state.jacobian[9] =
856  Ay[0] * P[32] + Ay[1] * P[33] + Ay[2] * P[34]; // dL1/dThe
857  state.jacobian[10] =
858  Ay[0] * P[40] + Ay[1] * P[41] + Ay[2] * P[42]; // dL1/dCM
859  state.jacobian[11] = 0.; // dL1/dT
860 
861  state.jacobian[12] = P3 * P[13] - P4 * P[12]; // dPhi/dL0
862  state.jacobian[13] = P3 * P[21] - P4 * P[20]; // dPhi/dL1
863  state.jacobian[14] = P3 * P[29] - P4 * P[28]; // dPhi/dPhi
864  state.jacobian[15] = P3 * P[37] - P4 * P[36]; // dPhi/dThe
865  state.jacobian[16] = P3 * P[45] - P4 * P[44]; // dPhi/dCM
866  state.jacobian[17] = 0.; // dPhi/dT
867 
868  state.jacobian[18] = C * P[14]; // dThe/dL0
869  state.jacobian[19] = C * P[22]; // dThe/dL1
870  state.jacobian[20] = C * P[30]; // dThe/dPhi
871  state.jacobian[21] = C * P[38]; // dThe/dThe
872  state.jacobian[22] = C * P[46]; // dThe/dCM
873  state.jacobian[23] = 0.; // dThe/dT
874 
875  state.jacobian[24] = 0.; // dCM /dL0
876  state.jacobian[25] = 0.; // dCM /dL1
877  state.jacobian[26] = 0.; // dCM /dPhi
878  state.jacobian[27] = 0.; // dCM /dTheta
879  state.jacobian[28] = P[47]; // dCM /dCM
880  state.jacobian[29] = 0.; // dCM/dT
881 
882  state.jacobian[30] = P[11]; // dT/dL0
883  state.jacobian[31] = P[19]; // dT/dL1
884  state.jacobian[32] = P[27]; // dT/dPhi
885  state.jacobian[33] = P[35]; // dT/dThe
886  state.jacobian[34] = P[43]; // dT/dCM
887  state.jacobian[35] = P[51]; // dT/dT
888 
889  Eigen::Map<Eigen::Matrix<double, eBoundSize, eBoundSize, Eigen::RowMajor>>
890  J(state.jacobian);
891  state.cov = J * (*state.covariance) * J.transpose();
892  }
893 
901  State& state, const Surface& surface,
902  const FreeToBoundCorrection& /*freeToBoundCorrection*/ =
903  FreeToBoundCorrection(false)) const {
904  Acts::Vector3 gp(state.pVector[0], state.pVector[1], state.pVector[2]);
905  Acts::Vector3 mom(state.pVector[4], state.pVector[5], state.pVector[6]);
906 
907  double P[60];
908  for (unsigned int i = 0; i < 60; ++i) {
909  P[i] = state.pVector[i];
910  }
911 
912  mom /= std::abs(state.pVector[7]);
913 
914  double p = 1. / state.pVector[7];
915  P[40] *= p;
916  P[41] *= p;
917  P[42] *= p;
918  P[44] *= p;
919  P[45] *= p;
920  P[46] *= p;
921 
922  const auto fFrame = surface.referenceFrame(state.geoContext, gp, mom);
923 
924  double Ax[3] = {fFrame(0, 0), fFrame(1, 0), fFrame(2, 0)};
925  double Ay[3] = {fFrame(0, 1), fFrame(1, 1), fFrame(2, 1)};
926  double S[3] = {fFrame(0, 2), fFrame(1, 2), fFrame(2, 2)};
927 
928  // this is the projection of direction onto the local normal vector
929  double A = P[4] * S[0] + P[5] * S[1] + P[6] * S[2];
930 
931  if (A != 0.) {
932  A = 1. / A;
933  }
934 
935  S[0] *= A;
936  S[1] *= A;
937  S[2] *= A;
938 
939  double s0 = P[8] * S[0] + P[9] * S[1] + P[10] * S[2];
940  double s1 = P[16] * S[0] + P[17] * S[1] + P[18] * S[2];
941  double s2 = P[24] * S[0] + P[25] * S[1] + P[26] * S[2];
942  double s3 = P[32] * S[0] + P[33] * S[1] + P[34] * S[2];
943  double s4 = P[40] * S[0] + P[41] * S[1] + P[42] * S[2];
944 
945  // in case of line-type surfaces - we need to take into account that
946  // the reference frame changes with variations of all local
947  // parameters
948  if (surface.type() == Surface::Straw ||
949  surface.type() == Surface::Perigee) {
950  // vector from position to center
951  double x = P[0] - surface.center(state.geoContext).x();
952  double y = P[1] - surface.center(state.geoContext).y();
953  double z = P[2] - surface.center(state.geoContext).z();
954 
955  // this is the projection of the direction onto the local y axis
956  double d = P[4] * Ay[0] + P[5] * Ay[1] + P[6] * Ay[2];
957 
958  // this is cos(beta)
959  double a = (1. - d) * (1. + d);
960  if (a != 0.) {
961  a = 1. / a; // i.e. 1./(1-d^2)
962  }
963 
964  // that's the modified norm vector
965  double X = d * Ay[0] - P[4]; //
966  double Y = d * Ay[1] - P[5]; //
967  double Z = d * Ay[2] - P[6]; //
968 
969  // d0 to d1
970  double d0 = P[12] * Ay[0] + P[13] * Ay[1] + P[14] * Ay[2];
971  double d1 = P[20] * Ay[0] + P[21] * Ay[1] + P[22] * Ay[2];
972  double d2 = P[28] * Ay[0] + P[29] * Ay[1] + P[30] * Ay[2];
973  double d3 = P[36] * Ay[0] + P[37] * Ay[1] + P[38] * Ay[2];
974  double d4 = P[44] * Ay[0] + P[45] * Ay[1] + P[46] * Ay[2];
975 
976  s0 = (((P[8] * X + P[9] * Y + P[10] * Z) + x * (d0 * Ay[0] - P[12])) +
977  (y * (d0 * Ay[1] - P[13]) + z * (d0 * Ay[2] - P[14]))) *
978  (-a);
979 
980  s1 = (((P[16] * X + P[17] * Y + P[18] * Z) + x * (d1 * Ay[0] - P[20])) +
981  (y * (d1 * Ay[1] - P[21]) + z * (d1 * Ay[2] - P[22]))) *
982  (-a);
983  s2 = (((P[24] * X + P[25] * Y + P[26] * Z) + x * (d2 * Ay[0] - P[28])) +
984  (y * (d2 * Ay[1] - P[29]) + z * (d2 * Ay[2] - P[30]))) *
985  (-a);
986  s3 = (((P[32] * X + P[33] * Y + P[34] * Z) + x * (d3 * Ay[0] - P[36])) +
987  (y * (d3 * Ay[1] - P[37]) + z * (d3 * Ay[2] - P[38]))) *
988  (-a);
989  s4 = (((P[40] * X + P[41] * Y + P[42] * Z) + x * (d4 * Ay[0] - P[44])) +
990  (y * (d4 * Ay[1] - P[45]) + z * (d4 * Ay[2] - P[46]))) *
991  (-a);
992  }
993 
994  P[8] -= (s0 * P[4]);
995  P[9] -= (s0 * P[5]);
996  P[10] -= (s0 * P[6]);
997  P[11] -= (s0 * P[59]);
998  P[12] -= (s0 * P[56]);
999  P[13] -= (s0 * P[57]);
1000  P[14] -= (s0 * P[58]);
1001 
1002  P[16] -= (s1 * P[4]);
1003  P[17] -= (s1 * P[5]);
1004  P[18] -= (s1 * P[6]);
1005  P[19] -= (s1 * P[59]);
1006  P[20] -= (s1 * P[56]);
1007  P[21] -= (s1 * P[57]);
1008  P[22] -= (s1 * P[58]);
1009 
1010  P[24] -= (s2 * P[4]);
1011  P[25] -= (s2 * P[5]);
1012  P[26] -= (s2 * P[6]);
1013  P[27] -= (s2 * P[59]);
1014  P[28] -= (s2 * P[56]);
1015  P[29] -= (s2 * P[57]);
1016  P[30] -= (s2 * P[58]);
1017 
1018  P[32] -= (s3 * P[4]);
1019  P[33] -= (s3 * P[5]);
1020  P[34] -= (s3 * P[6]);
1021  P[35] -= (s3 * P[59]);
1022  P[36] -= (s3 * P[56]);
1023  P[37] -= (s3 * P[57]);
1024  P[38] -= (s3 * P[58]);
1025 
1026  P[40] -= (s4 * P[4]);
1027  P[41] -= (s4 * P[5]);
1028  P[42] -= (s4 * P[6]);
1029  P[43] -= (s4 * P[59]);
1030  P[44] -= (s4 * P[56]);
1031  P[45] -= (s4 * P[57]);
1032  P[46] -= (s4 * P[58]);
1033 
1034  double P3 = 0, P4 = 0, C = P[4] * P[4] + P[5] * P[5];
1035  if (C > 1.e-20) {
1036  C = 1. / C;
1037  P3 = P[4] * C;
1038  P4 = P[5] * C;
1039  C = -sqrt(C);
1040  } else {
1041  C = -1.e10;
1042  P3 = 1.;
1043  P4 = 0.;
1044  }
1045 
1046  double MA[3] = {Ax[0], Ax[1], Ax[2]};
1047  double MB[3] = {Ay[0], Ay[1], Ay[2]};
1048  // Jacobian production of transport and to_local
1049  if (surface.type() == Surface::Disc) {
1050  // the vector from the disc surface to the p
1051  const auto& sfc = surface.center(state.geoContext);
1052  double d[3] = {P[0] - sfc(0), P[1] - sfc(1), P[2] - sfc(2)};
1053  // this needs the transformation to polar coordinates
1054  double RC = d[0] * Ax[0] + d[1] * Ax[1] + d[2] * Ax[2];
1055  double RS = d[0] * Ay[0] + d[1] * Ay[1] + d[2] * Ay[2];
1056  double R2 = RC * RC + RS * RS;
1057 
1058  // inverse radius
1059  double Ri = 1. / sqrt(R2);
1060  MA[0] = (RC * Ax[0] + RS * Ay[0]) * Ri;
1061  MA[1] = (RC * Ax[1] + RS * Ay[1]) * Ri;
1062  MA[2] = (RC * Ax[2] + RS * Ay[2]) * Ri;
1063  MB[0] = (RC * Ay[0] - RS * Ax[0]) * (Ri = 1. / R2);
1064  MB[1] = (RC * Ay[1] - RS * Ax[1]) * Ri;
1065  MB[2] = (RC * Ay[2] - RS * Ax[2]) * Ri;
1066  }
1067 
1068  state.jacobian[0] = MA[0] * P[8] + MA[1] * P[9] + MA[2] * P[10]; // dL0/dL0
1069  state.jacobian[1] =
1070  MA[0] * P[16] + MA[1] * P[17] + MA[2] * P[18]; // dL0/dL1
1071  state.jacobian[2] =
1072  MA[0] * P[24] + MA[1] * P[25] + MA[2] * P[26]; // dL0/dPhi
1073  state.jacobian[3] =
1074  MA[0] * P[32] + MA[1] * P[33] + MA[2] * P[34]; // dL0/dThe
1075  state.jacobian[4] =
1076  MA[0] * P[40] + MA[1] * P[41] + MA[2] * P[42]; // dL0/dCM
1077  state.jacobian[5] = 0.; // dL0/dT
1078 
1079  state.jacobian[6] = MB[0] * P[8] + MB[1] * P[9] + MB[2] * P[10]; // dL1/dL0
1080  state.jacobian[7] =
1081  MB[0] * P[16] + MB[1] * P[17] + MB[2] * P[18]; // dL1/dL1
1082  state.jacobian[8] =
1083  MB[0] * P[24] + MB[1] * P[25] + MB[2] * P[26]; // dL1/dPhi
1084  state.jacobian[9] =
1085  MB[0] * P[32] + MB[1] * P[33] + MB[2] * P[34]; // dL1/dThe
1086  state.jacobian[10] =
1087  MB[0] * P[40] + MB[1] * P[41] + MB[2] * P[42]; // dL1/dCM
1088  state.jacobian[11] = 0.; // dL1/dT
1089 
1090  state.jacobian[12] = P3 * P[13] - P4 * P[12]; // dPhi/dL0
1091  state.jacobian[13] = P3 * P[21] - P4 * P[20]; // dPhi/dL1
1092  state.jacobian[14] = P3 * P[29] - P4 * P[28]; // dPhi/dPhi
1093  state.jacobian[15] = P3 * P[37] - P4 * P[36]; // dPhi/dThe
1094  state.jacobian[16] = P3 * P[45] - P4 * P[44]; // dPhi/dCM
1095  state.jacobian[17] = 0.; // dPhi/dT
1096 
1097  state.jacobian[18] = C * P[14]; // dThe/dL0
1098  state.jacobian[19] = C * P[22]; // dThe/dL1
1099  state.jacobian[20] = C * P[30]; // dThe/dPhi
1100  state.jacobian[21] = C * P[38]; // dThe/dThe
1101  state.jacobian[22] = C * P[46]; // dThe/dCM
1102  state.jacobian[23] = 0.; // dThe/dT
1103 
1104  state.jacobian[24] = 0.; // dCM /dL0
1105  state.jacobian[25] = 0.; // dCM /dL1
1106  state.jacobian[26] = 0.; // dCM /dPhi
1107  state.jacobian[27] = 0.; // dCM /dTheta
1108  state.jacobian[28] = P[47]; // dCM /dCM
1109  state.jacobian[29] = 0.; // dCM/dT
1110 
1111  state.jacobian[30] = P[11]; // dT/dL0
1112  state.jacobian[31] = P[19]; // dT/dL1
1113  state.jacobian[32] = P[27]; // dT/dPhi
1114  state.jacobian[33] = P[35]; // dT/dThe
1115  state.jacobian[34] = P[43]; // dT/dCM
1116  state.jacobian[35] = P[51]; // dT/dT
1117 
1118  Eigen::Map<Eigen::Matrix<double, eBoundSize, eBoundSize, Eigen::RowMajor>>
1119  J(state.jacobian);
1120  state.cov = J * (*state.covariance) * J.transpose();
1121  }
1122 
1126  template <typename propagator_state_t, typename navigator_t>
1127  Result<double> step(propagator_state_t& state,
1128  const navigator_t& /*navigator*/) const {
1129  // we use h for keeping the nominclature with the original atlas code
1130  auto h = state.stepping.stepSize.value() * state.options.direction;
1131  bool Jac = state.stepping.useJacobian;
1132 
1133  double* R = &(state.stepping.pVector[0]); // Coordinates
1134  double* A = &(state.stepping.pVector[4]); // Directions
1135  double* sA = &(state.stepping.pVector[56]);
1136  // Invert mometum/2.
1137  double Pi = 0.5 * state.stepping.pVector[7];
1138  // double dltm = 0.0002 * .03;
1139  Vector3 f0, f;
1140 
1141  // if new field is required get it
1142  if (state.stepping.newfield) {
1143  const Vector3 pos(R[0], R[1], R[2]);
1144  // This is sd.B_first in EigenStepper
1145  auto fRes = getField(state.stepping, pos);
1146  if (!fRes.ok()) {
1147  return fRes.error();
1148  }
1149  f0 = *fRes;
1150  } else {
1151  f0 = state.stepping.field;
1152  }
1153 
1154  bool Helix = false;
1155  // if (std::abs(S) < m_cfg.helixStep) Helix = true;
1156 
1157  size_t nStepTrials = 0;
1158  while (h != 0.) {
1159  // PS2 is h/(2*momentum) in EigenStepper
1160  double S3 = (1. / 3.) * h, S4 = .25 * h, PS2 = Pi * h;
1161 
1162  // First point
1163  //
1164  // H0 is (h/(2*momentum) * sd.B_first) in EigenStepper
1165  double H0[3] = {f0[0] * PS2, f0[1] * PS2, f0[2] * PS2};
1166  // { A0, B0, C0 } is (h/2 * sd.k1) in EigenStepper
1167  double A0 = A[1] * H0[2] - A[2] * H0[1];
1168  double B0 = A[2] * H0[0] - A[0] * H0[2];
1169  double C0 = A[0] * H0[1] - A[1] * H0[0];
1170  // { A2, B2, C2 } is (h/2 * sd.k1 + direction) in EigenStepper
1171  double A2 = A0 + A[0];
1172  double B2 = B0 + A[1];
1173  double C2 = C0 + A[2];
1174  // { A1, B1, C1 } is (h/2 * sd.k1 + 2*direction) in EigenStepper
1175  double A1 = A2 + A[0];
1176  double B1 = B2 + A[1];
1177  double C1 = C2 + A[2];
1178 
1179  // Second point
1180  //
1181  if (!Helix) {
1182  // This is pos1 in EigenStepper
1183  const Vector3 pos(R[0] + A1 * S4, R[1] + B1 * S4, R[2] + C1 * S4);
1184  // This is sd.B_middle in EigenStepper
1185  auto fRes = getField(state.stepping, pos);
1186  if (!fRes.ok()) {
1187  return fRes.error();
1188  }
1189  f = *fRes;
1190  } else {
1191  f = f0;
1192  }
1193 
1194  // H1 is (h/(2*momentum) * sd.B_middle) in EigenStepper
1195  double H1[3] = {f[0] * PS2, f[1] * PS2, f[2] * PS2};
1196  // { A3, B3, C3 } is (direction + h/2 * sd.k2) in EigenStepper
1197  double A3 = (A[0] + B2 * H1[2]) - C2 * H1[1];
1198  double B3 = (A[1] + C2 * H1[0]) - A2 * H1[2];
1199  double C3 = (A[2] + A2 * H1[1]) - B2 * H1[0];
1200  // { A4, B4, C4 } is (direction + h/2 * sd.k3) in EigenStepper
1201  double A4 = (A[0] + B3 * H1[2]) - C3 * H1[1];
1202  double B4 = (A[1] + C3 * H1[0]) - A3 * H1[2];
1203  double C4 = (A[2] + A3 * H1[1]) - B3 * H1[0];
1204  // { A5, B5, C5 } is (direction + h * sd.k3) in EigenStepper
1205  double A5 = 2. * A4 - A[0];
1206  double B5 = 2. * B4 - A[1];
1207  double C5 = 2. * C4 - A[2];
1208 
1209  // Last point
1210  //
1211  if (!Helix) {
1212  // This is pos2 in EigenStepper
1213  const Vector3 pos(R[0] + h * A4, R[1] + h * B4, R[2] + h * C4);
1214  // This is sd.B_last in Eigen stepper
1215  auto fRes = getField(state.stepping, pos);
1216  if (!fRes.ok()) {
1217  return fRes.error();
1218  }
1219  f = *fRes;
1220  } else {
1221  f = f0;
1222  }
1223 
1224  // H2 is (h/(2*momentum) * sd.B_last) in EigenStepper
1225  double H2[3] = {f[0] * PS2, f[1] * PS2, f[2] * PS2};
1226  // { A6, B6, C6 } is (h/2 * sd.k4) in EigenStepper
1227  double A6 = B5 * H2[2] - C5 * H2[1];
1228  double B6 = C5 * H2[0] - A5 * H2[2];
1229  double C6 = A5 * H2[1] - B5 * H2[0];
1230 
1231  // Test approximation quality on give step and possible step reduction
1232  //
1233  // This is (h2 * (sd.k1 - sd.k2 - sd.k3 + sd.k4).template lpNorm<1>())
1234  // in EigenStepper
1235  double EST =
1236  2. * h *
1237  (std::abs((A1 + A6) - (A3 + A4)) + std::abs((B1 + B6) - (B3 + B4)) +
1238  std::abs((C1 + C6) - (C3 + C4)));
1239  if (std::abs(EST) > std::abs(state.options.tolerance)) {
1240  h = h * .5;
1241  // neutralize the sign of h again
1242  state.stepping.stepSize.setAccuracy(h * state.options.direction);
1243  // dltm = 0.;
1244  nStepTrials++;
1245  continue;
1246  }
1247 
1248  // if (EST < dltm) h *= 2.;
1249 
1250  // Parameters calculation
1251  //
1252  double A00 = A[0], A11 = A[1], A22 = A[2];
1253 
1254  A[0] = 2. * A3 + (A0 + A5 + A6);
1255  A[1] = 2. * B3 + (B0 + B5 + B6);
1256  A[2] = 2. * C3 + (C0 + C5 + C6);
1257 
1258  double D = (A[0] * A[0] + A[1] * A[1]) + (A[2] * A[2] - 9.);
1259  double Sl = 2. / h;
1260  D = (1. / 3.) - ((1. / 648.) * D) * (12. - D);
1261 
1262  R[0] += (A2 + A3 + A4) * S3;
1263  R[1] += (B2 + B3 + B4) * S3;
1264  R[2] += (C2 + C3 + C4) * S3;
1265  A[0] *= D;
1266  A[1] *= D;
1267  A[2] *= D;
1268  sA[0] = A6 * Sl;
1269  sA[1] = B6 * Sl;
1270  sA[2] = C6 * Sl;
1271 
1272  double mass = particleHypothesis(state.stepping).mass();
1273 
1274  // Evaluate the time propagation
1275  double dtds = std::hypot(1, mass / absoluteMomentum(state.stepping));
1276  state.stepping.pVector[3] += h * dtds;
1277  state.stepping.pVector[59] = dtds;
1278  state.stepping.field = f;
1279  state.stepping.newfield = false;
1280 
1281  if (Jac) {
1282  double dtdl = h * mass * mass * charge(state.stepping) /
1283  (absoluteMomentum(state.stepping) * dtds);
1284  state.stepping.pVector[43] += dtdl;
1285 
1286  // Jacobian calculation
1287  //
1288  double* d2A = &state.stepping.pVector[28];
1289  double* d3A = &state.stepping.pVector[36];
1290  double* d4A = &state.stepping.pVector[44];
1291  double d2A0 = H0[2] * d2A[1] - H0[1] * d2A[2];
1292  double d2B0 = H0[0] * d2A[2] - H0[2] * d2A[0];
1293  double d2C0 = H0[1] * d2A[0] - H0[0] * d2A[1];
1294  double d3A0 = H0[2] * d3A[1] - H0[1] * d3A[2];
1295  double d3B0 = H0[0] * d3A[2] - H0[2] * d3A[0];
1296  double d3C0 = H0[1] * d3A[0] - H0[0] * d3A[1];
1297  double d4A0 = (A0 + H0[2] * d4A[1]) - H0[1] * d4A[2];
1298  double d4B0 = (B0 + H0[0] * d4A[2]) - H0[2] * d4A[0];
1299  double d4C0 = (C0 + H0[1] * d4A[0]) - H0[0] * d4A[1];
1300  double d2A2 = d2A0 + d2A[0];
1301  double d2B2 = d2B0 + d2A[1];
1302  double d2C2 = d2C0 + d2A[2];
1303  double d3A2 = d3A0 + d3A[0];
1304  double d3B2 = d3B0 + d3A[1];
1305  double d3C2 = d3C0 + d3A[2];
1306  double d4A2 = d4A0 + d4A[0];
1307  double d4B2 = d4B0 + d4A[1];
1308  double d4C2 = d4C0 + d4A[2];
1309  double d0 = d4A[0] - A00;
1310  double d1 = d4A[1] - A11;
1311  double d2 = d4A[2] - A22;
1312  double d2A3 = (d2A[0] + d2B2 * H1[2]) - d2C2 * H1[1];
1313  double d2B3 = (d2A[1] + d2C2 * H1[0]) - d2A2 * H1[2];
1314  double d2C3 = (d2A[2] + d2A2 * H1[1]) - d2B2 * H1[0];
1315  double d3A3 = (d3A[0] + d3B2 * H1[2]) - d3C2 * H1[1];
1316  double d3B3 = (d3A[1] + d3C2 * H1[0]) - d3A2 * H1[2];
1317  double d3C3 = (d3A[2] + d3A2 * H1[1]) - d3B2 * H1[0];
1318  double d4A3 = ((A3 + d0) + d4B2 * H1[2]) - d4C2 * H1[1];
1319  double d4B3 = ((B3 + d1) + d4C2 * H1[0]) - d4A2 * H1[2];
1320  double d4C3 = ((C3 + d2) + d4A2 * H1[1]) - d4B2 * H1[0];
1321  double d2A4 = (d2A[0] + d2B3 * H1[2]) - d2C3 * H1[1];
1322  double d2B4 = (d2A[1] + d2C3 * H1[0]) - d2A3 * H1[2];
1323  double d2C4 = (d2A[2] + d2A3 * H1[1]) - d2B3 * H1[0];
1324  double d3A4 = (d3A[0] + d3B3 * H1[2]) - d3C3 * H1[1];
1325  double d3B4 = (d3A[1] + d3C3 * H1[0]) - d3A3 * H1[2];
1326  double d3C4 = (d3A[2] + d3A3 * H1[1]) - d3B3 * H1[0];
1327  double d4A4 = ((A4 + d0) + d4B3 * H1[2]) - d4C3 * H1[1];
1328  double d4B4 = ((B4 + d1) + d4C3 * H1[0]) - d4A3 * H1[2];
1329  double d4C4 = ((C4 + d2) + d4A3 * H1[1]) - d4B3 * H1[0];
1330  double d2A5 = 2. * d2A4 - d2A[0];
1331  double d2B5 = 2. * d2B4 - d2A[1];
1332  double d2C5 = 2. * d2C4 - d2A[2];
1333  double d3A5 = 2. * d3A4 - d3A[0];
1334  double d3B5 = 2. * d3B4 - d3A[1];
1335  double d3C5 = 2. * d3C4 - d3A[2];
1336  double d4A5 = 2. * d4A4 - d4A[0];
1337  double d4B5 = 2. * d4B4 - d4A[1];
1338  double d4C5 = 2. * d4C4 - d4A[2];
1339  double d2A6 = d2B5 * H2[2] - d2C5 * H2[1];
1340  double d2B6 = d2C5 * H2[0] - d2A5 * H2[2];
1341  double d2C6 = d2A5 * H2[1] - d2B5 * H2[0];
1342  double d3A6 = d3B5 * H2[2] - d3C5 * H2[1];
1343  double d3B6 = d3C5 * H2[0] - d3A5 * H2[2];
1344  double d3C6 = d3A5 * H2[1] - d3B5 * H2[0];
1345  double d4A6 = d4B5 * H2[2] - d4C5 * H2[1];
1346  double d4B6 = d4C5 * H2[0] - d4A5 * H2[2];
1347  double d4C6 = d4A5 * H2[1] - d4B5 * H2[0];
1348 
1349  double* dR = &state.stepping.pVector[24];
1350  dR[0] += (d2A2 + d2A3 + d2A4) * S3;
1351  dR[1] += (d2B2 + d2B3 + d2B4) * S3;
1352  dR[2] += (d2C2 + d2C3 + d2C4) * S3;
1353  d2A[0] = ((d2A0 + 2. * d2A3) + (d2A5 + d2A6)) * (1. / 3.);
1354  d2A[1] = ((d2B0 + 2. * d2B3) + (d2B5 + d2B6)) * (1. / 3.);
1355  d2A[2] = ((d2C0 + 2. * d2C3) + (d2C5 + d2C6)) * (1. / 3.);
1356 
1357  dR = &state.stepping.pVector[32];
1358  dR[0] += (d3A2 + d3A3 + d3A4) * S3;
1359  dR[1] += (d3B2 + d3B3 + d3B4) * S3;
1360  dR[2] += (d3C2 + d3C3 + d3C4) * S3;
1361  d3A[0] = ((d3A0 + 2. * d3A3) + (d3A5 + d3A6)) * (1. / 3.);
1362  d3A[1] = ((d3B0 + 2. * d3B3) + (d3B5 + d3B6)) * (1. / 3.);
1363  d3A[2] = ((d3C0 + 2. * d3C3) + (d3C5 + d3C6)) * (1. / 3.);
1364 
1365  dR = &state.stepping.pVector[40];
1366  dR[0] += (d4A2 + d4A3 + d4A4) * S3;
1367  dR[1] += (d4B2 + d4B3 + d4B4) * S3;
1368  dR[2] += (d4C2 + d4C3 + d4C4) * S3;
1369  d4A[0] = ((d4A0 + 2. * d4A3) + (d4A5 + d4A6 + A6)) * (1. / 3.);
1370  d4A[1] = ((d4B0 + 2. * d4B3) + (d4B5 + d4B6 + B6)) * (1. / 3.);
1371  d4A[2] = ((d4C0 + 2. * d4C3) + (d4C5 + d4C6 + C6)) * (1. / 3.);
1372  }
1373 
1374  state.stepping.pathAccumulated += h;
1375  state.stepping.stepSize.nStepTrials = nStepTrials;
1376  return h;
1377  }
1378 
1379  // that exit path should actually not happen
1380  state.stepping.pathAccumulated += h;
1381  return h;
1382  }
1383 
1388  void setIdentityJacobian(State& state) const {
1389  state.jacobian[0] = 1.; // dL0/dL0
1390  state.jacobian[1] = 0.; // dL0/dL1
1391  state.jacobian[2] = 0.; // dL0/dPhi
1392  state.jacobian[3] = 0.; // dL0/dThe
1393  state.jacobian[4] = 0.; // dL0/dCM
1394  state.jacobian[5] = 0.; // dL0/dT
1395 
1396  state.jacobian[6] = 0.; // dL1/dL0
1397  state.jacobian[7] = 1.; // dL1/dL1
1398  state.jacobian[8] = 0.; // dL1/dPhi
1399  state.jacobian[9] = 0.; // dL1/dThe
1400  state.jacobian[10] = 0.; // dL1/dCM
1401  state.jacobian[11] = 0.; // dL1/dT
1402 
1403  state.jacobian[12] = 0.; // dPhi/dL0
1404  state.jacobian[13] = 0.; // dPhi/dL1
1405  state.jacobian[14] = 1.; // dPhi/dPhi
1406  state.jacobian[15] = 0.; // dPhi/dThe
1407  state.jacobian[16] = 0.; // dPhi/dCM
1408  state.jacobian[17] = 0.; // dPhi/dT
1409 
1410  state.jacobian[18] = 0.; // dThe/dL0
1411  state.jacobian[19] = 0.; // dThe/dL1
1412  state.jacobian[20] = 0.; // dThe/dPhi
1413  state.jacobian[21] = 1.; // dThe/dThe
1414  state.jacobian[22] = 0.; // dThe/dCM
1415  state.jacobian[23] = 0.; // dThe/dT
1416 
1417  state.jacobian[24] = 0.; // dCM /dL0
1418  state.jacobian[25] = 0.; // dCM /dL1
1419  state.jacobian[26] = 0.; // dCM /dPhi
1420  state.jacobian[27] = 0.; // dCM /dTheta
1421  state.jacobian[28] = 1.; // dCM /dCM
1422  state.jacobian[29] = 0.; // dCM/dT
1423 
1424  state.jacobian[30] = 0.; // dT/dL0
1425  state.jacobian[31] = 0.; // dT/dL1
1426  state.jacobian[32] = 0.; // dT/dPhi
1427  state.jacobian[33] = 0.; // dT/dThe
1428  state.jacobian[34] = 0.; // dT/dCM
1429  state.jacobian[35] = 1.; // dT/dT
1430  }
1431 
1432  private:
1433  std::shared_ptr<const MagneticFieldProvider> m_bField;
1434 
1437 };
1438 
1439 } // namespace Acts