File indexing completed on 2025-07-13 07:50:14
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011
0012 #include "Acts/Utilities/detail/ReferenceWrapperAnyCompat.hpp"
0013
0014 #include "Acts/Definitions/Algebra.hpp"
0015 #include "Acts/Definitions/Common.hpp"
0016 #include "Acts/Definitions/TrackParametrization.hpp"
0017 #include "Acts/Definitions/Units.hpp"
0018 #include "Acts/EventData/TrackParameters.hpp"
0019 #include "Acts/EventData/TransformationHelpers.hpp"
0020 #include "Acts/EventData/detail/CorrectedTransformationFreeToBound.hpp"
0021 #include "Acts/Geometry/GeometryContext.hpp"
0022 #include "Acts/MagneticField/MagneticFieldProvider.hpp"
0023 #include "Acts/Propagator/ConstrainedStep.hpp"
0024 #include "Acts/Propagator/StepperOptions.hpp"
0025 #include "Acts/Propagator/StepperStatistics.hpp"
0026 #include "Acts/Propagator/detail/SteppingHelper.hpp"
0027 #include "Acts/Surfaces/Surface.hpp"
0028 #include "Acts/Utilities/Intersection.hpp"
0029 #include "Acts/Utilities/Result.hpp"
0030
0031 #include <cmath>
0032
0033 namespace Acts {
0034
0035 class IVolumeMaterial;
0036
0037
0038
0039
0040 class AtlasStepper {
0041 public:
0042 using Jacobian = BoundMatrix;
0043 using Covariance = BoundSquareMatrix;
0044 using BoundState = std::tuple<BoundTrackParameters, Jacobian, double>;
0045
0046 struct Config {
0047 std::shared_ptr<const MagneticFieldProvider> bField;
0048 };
0049
0050 struct Options : public StepperPlainOptions {
0051 Options(const GeometryContext& gctx, const MagneticFieldContext& mctx)
0052 : StepperPlainOptions(gctx, mctx) {}
0053
0054 void setPlainOptions(const StepperPlainOptions& options) {
0055 static_cast<StepperPlainOptions&>(*this) = options;
0056 }
0057 };
0058
0059
0060 struct State {
0061
0062
0063
0064
0065
0066
0067 State(const Options& optionsIn, MagneticFieldProvider::Cache fieldCacheIn)
0068 : options(optionsIn), fieldCache(std::move(fieldCacheIn)) {}
0069
0070 Options options;
0071
0072 ParticleHypothesis particleHypothesis = ParticleHypothesis::pion();
0073
0074
0075 bool state_ready = false;
0076
0077 bool useJacobian = false;
0078 double step = 0;
0079 double maxPathLength = 0;
0080 bool mcondition = false;
0081 bool needgradient = false;
0082 bool newfield = true;
0083
0084 Vector3 field = Vector3::Zero();
0085 std::array<double, 60> pVector{};
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100 double parameters[eBoundSize] = {0., 0., 0., 0., 0., 0.};
0101 const Covariance* covariance = nullptr;
0102 Covariance cov = Covariance::Zero();
0103 bool covTransport = false;
0104 double jacobian[eBoundSize * eBoundSize] = {};
0105
0106
0107 double pathAccumulated = 0.;
0108
0109
0110 std::size_t nSteps = 0;
0111
0112
0113 std::size_t nStepTrials = 0;
0114
0115
0116 ConstrainedStep stepSize;
0117
0118
0119 double previousStepSize = 0.;
0120
0121
0122
0123 MagneticFieldProvider::Cache fieldCache;
0124
0125
0126
0127 bool debug = false;
0128 std::string debugString = "";
0129
0130 std::size_t debugPfxWidth = 30;
0131 std::size_t debugMsgWidth = 50;
0132
0133
0134 StepperStatistics statistics;
0135 };
0136
0137 explicit AtlasStepper(std::shared_ptr<const MagneticFieldProvider> bField)
0138 : m_bField(std::move(bField)) {}
0139
0140 explicit AtlasStepper(const Config& config) : m_bField(config.bField) {}
0141
0142 State makeState(const Options& options) const {
0143 State state{options, m_bField->makeCache(options.magFieldContext)};
0144 return state;
0145 }
0146
0147 void initialize(State& state, const BoundTrackParameters& par) const {
0148 initialize(state, par.parameters(), par.covariance(),
0149 par.particleHypothesis(), par.referenceSurface());
0150 }
0151
0152 void initialize(State& state, const BoundVector& boundParams,
0153 const std::optional<BoundMatrix>& cov,
0154 ParticleHypothesis particleHypothesis,
0155 const Surface& surface) const {
0156 state.particleHypothesis = particleHypothesis;
0157
0158 state.pathAccumulated = 0;
0159 state.nSteps = 0;
0160 state.nStepTrials = 0;
0161 state.stepSize = ConstrainedStep();
0162 state.stepSize.setAccuracy(state.options.initialStepSize);
0163 state.stepSize.setUser(state.options.maxStepSize);
0164 state.previousStepSize = 0;
0165 state.statistics = StepperStatistics();
0166
0167
0168
0169
0170
0171 const auto& Vp = boundParams;
0172
0173 double Sf = std::sin(Vp[eBoundPhi]);
0174 double Cf = std::cos(Vp[eBoundPhi]);
0175 double Se = std::sin(Vp[eBoundTheta]);
0176 double Ce = std::cos(Vp[eBoundTheta]);
0177
0178 const Vector3 dir = {Cf * Se, Sf * Se, Ce};
0179 const auto pos = surface.localToGlobal(
0180 state.options.geoContext, boundParams.segment<2>(eBoundLoc0), dir);
0181
0182 double* pVector = state.pVector.data();
0183
0184 pVector[0] = pos[ePos0];
0185 pVector[1] = pos[ePos1];
0186 pVector[2] = pos[ePos2];
0187 pVector[3] = boundParams[eBoundTime];
0188 pVector[4] = dir[ePos0];
0189 pVector[5] = dir[ePos1];
0190 pVector[6] = dir[ePos2];
0191 pVector[7] = Vp[eBoundQOverP];
0192
0193
0194 if (std::abs(pVector[7]) < .000000000000001) {
0195 pVector[7] < 0. ? pVector[7] = -.000000000000001
0196 : pVector[7] = .000000000000001;
0197 }
0198
0199
0200 state.covTransport = cov.has_value();
0201 if (state.covTransport) {
0202
0203 state.covariance = new BoundSquareMatrix(*cov);
0204 state.useJacobian = true;
0205 const auto transform =
0206 surface.referenceFrame(state.options.geoContext, pos, dir);
0207
0208 pVector[8] = transform(0, eBoundLoc0);
0209 pVector[16] = transform(0, eBoundLoc1);
0210 pVector[24] = 0.;
0211 pVector[32] = 0.;
0212 pVector[40] = 0.;
0213 pVector[48] = 0.;
0214
0215 pVector[9] = transform(1, eBoundLoc0);
0216 pVector[17] = transform(1, eBoundLoc1);
0217 pVector[25] = 0.;
0218 pVector[33] = 0.;
0219 pVector[41] = 0.;
0220 pVector[49] = 0.;
0221
0222 pVector[10] = transform(2, eBoundLoc0);
0223 pVector[18] = transform(2, eBoundLoc1);
0224 pVector[26] = 0.;
0225 pVector[34] = 0.;
0226 pVector[42] = 0.;
0227 pVector[50] = 0.;
0228
0229 pVector[11] = 0.;
0230 pVector[19] = 0.;
0231 pVector[27] = 0.;
0232 pVector[35] = 0.;
0233 pVector[43] = 0.;
0234 pVector[51] = 1.;
0235
0236 pVector[12] = 0.;
0237 pVector[20] = 0.;
0238 pVector[28] = -Sf * Se;
0239 pVector[36] = Cf * Ce;
0240 pVector[44] = 0.;
0241 pVector[52] = 0.;
0242
0243 pVector[13] = 0.;
0244 pVector[21] = 0.;
0245 pVector[29] = Cf * Se;
0246 pVector[37] = Sf * Ce;
0247 pVector[45] = 0.;
0248 pVector[53] = 0.;
0249
0250 pVector[14] = 0.;
0251 pVector[22] = 0.;
0252 pVector[30] = 0.;
0253 pVector[38] = -Se;
0254 pVector[46] = 0.;
0255 pVector[54] = 0.;
0256
0257 pVector[15] = 0.;
0258 pVector[23] = 0.;
0259 pVector[31] = 0.;
0260 pVector[39] = 0.;
0261 pVector[47] = 1.;
0262 pVector[55] = 0.;
0263
0264 pVector[56] = 0.;
0265 pVector[57] = 0.;
0266 pVector[58] = 0.;
0267 pVector[59] = 0.;
0268
0269
0270
0271 if (surface.type() == Surface::Disc) {
0272 double lCf = std::cos(Vp[1]);
0273 double lSf = std::sin(Vp[1]);
0274 double Ax[3] = {transform(0, 0), transform(1, 0), transform(2, 0)};
0275 double Ay[3] = {transform(0, 1), transform(1, 1), transform(2, 1)};
0276 double d0 = lCf * Ax[0] + lSf * Ay[0];
0277 double d1 = lCf * Ax[1] + lSf * Ay[1];
0278 double d2 = lCf * Ax[2] + lSf * Ay[2];
0279 pVector[8] = d0;
0280 pVector[9] = d1;
0281 pVector[10] = d2;
0282 pVector[16] = Vp[0] * (lCf * Ay[0] - lSf * Ax[0]);
0283 pVector[17] = Vp[0] * (lCf * Ay[1] - lSf * Ax[1]);
0284 pVector[18] = Vp[0] * (lCf * Ay[2] - lSf * Ax[2]);
0285 }
0286
0287
0288 if (surface.type() == Surface::Perigee ||
0289 surface.type() == Surface::Straw) {
0290
0291
0292 double B[3] = {transform(0, 0), transform(1, 0), transform(2, 0)};
0293
0294 double A[3] = {transform(0, 1), transform(1, 1), transform(2, 1)};
0295
0296 double C[3] = {transform(0, 2), transform(1, 2), transform(2, 2)};
0297
0298
0299 double PC = pVector[4] * C[0] + pVector[5] * C[1] + pVector[6] * C[2];
0300 double Bn = 1. / PC;
0301
0302 double Bx2 = -A[2] * pVector[29];
0303 double Bx3 = A[1] * pVector[38] - A[2] * pVector[37];
0304
0305 double By2 = A[2] * pVector[28];
0306 double By3 = A[2] * pVector[36] - A[0] * pVector[38];
0307
0308 double Bz2 = A[0] * pVector[29] - A[1] * pVector[28];
0309 double Bz3 = A[0] * pVector[37] - A[1] * pVector[36];
0310
0311 double B2 = B[0] * Bx2 + B[1] * By2 + B[2] * Bz2;
0312 double B3 = B[0] * Bx3 + B[1] * By3 + B[2] * Bz3;
0313
0314 Bx2 = (Bx2 - B[0] * B2) * Bn;
0315 Bx3 = (Bx3 - B[0] * B3) * Bn;
0316 By2 = (By2 - B[1] * B2) * Bn;
0317 By3 = (By3 - B[1] * B3) * Bn;
0318 Bz2 = (Bz2 - B[2] * B2) * Bn;
0319 Bz3 = (Bz3 - B[2] * B3) * Bn;
0320
0321
0322 pVector[24] = Bx2 * Vp[0];
0323 pVector[32] = Bx3 * Vp[0];
0324 pVector[25] = By2 * Vp[0];
0325 pVector[33] = By3 * Vp[0];
0326 pVector[26] = Bz2 * Vp[0];
0327 pVector[34] = Bz3 * Vp[0];
0328 }
0329 }
0330
0331
0332 state.state_ready = true;
0333 }
0334
0335
0336
0337
0338
0339
0340
0341
0342 Result<Vector3> getField(State& state, const Vector3& pos) const {
0343
0344 auto res = m_bField->getField(pos, state.fieldCache);
0345 if (res.ok()) {
0346 state.field = *res;
0347 }
0348 return res;
0349 }
0350
0351 Vector3 position(const State& state) const {
0352 return Vector3(state.pVector[0], state.pVector[1], state.pVector[2]);
0353 }
0354
0355 Vector3 direction(const State& state) const {
0356 return Vector3(state.pVector[4], state.pVector[5], state.pVector[6]);
0357 }
0358
0359 double qOverP(const State& state) const { return state.pVector[7]; }
0360
0361
0362
0363
0364 double absoluteMomentum(const State& state) const {
0365 return particleHypothesis(state).extractMomentum(qOverP(state));
0366 }
0367
0368 Vector3 momentum(const State& state) const {
0369 return absoluteMomentum(state) * direction(state);
0370 }
0371
0372
0373
0374
0375 double charge(const State& state) const {
0376 return particleHypothesis(state).extractCharge(qOverP(state));
0377 }
0378
0379
0380
0381
0382 const ParticleHypothesis& particleHypothesis(const State& state) const {
0383 return state.particleHypothesis;
0384 }
0385
0386
0387 double overstepLimit(const State& ) const {
0388 return -m_overstepLimit;
0389 }
0390
0391
0392 double time(const State& state) const { return state.pVector[3]; }
0393
0394
0395
0396
0397
0398
0399
0400
0401
0402
0403
0404
0405
0406
0407
0408
0409 IntersectionStatus updateSurfaceStatus(
0410 State& state, const Surface& surface, std::uint8_t index,
0411 Direction navDir, const BoundaryTolerance& boundaryTolerance,
0412 double surfaceTolerance, ConstrainedStep::Type stype,
0413 const Logger& logger = getDummyLogger()) const {
0414 return detail::updateSingleSurfaceStatus<AtlasStepper>(
0415 *this, state, surface, index, navDir, boundaryTolerance,
0416 surfaceTolerance, stype, logger);
0417 }
0418
0419
0420
0421
0422
0423
0424
0425
0426
0427
0428 template <typename object_intersection_t>
0429 void updateStepSize(State& state, const object_intersection_t& oIntersection,
0430 Direction direction, ConstrainedStep::Type stype) const {
0431 (void)direction;
0432 double stepSize = oIntersection.pathLength();
0433 updateStepSize(state, stepSize, stype);
0434 }
0435
0436
0437
0438
0439
0440
0441 void updateStepSize(State& state, double stepSize,
0442 ConstrainedStep::Type stype) const {
0443 state.previousStepSize = state.stepSize.value();
0444 state.stepSize.update(stepSize, stype);
0445 }
0446
0447
0448
0449
0450
0451 void releaseStepSize(State& state, ConstrainedStep::Type stype) const {
0452 state.stepSize.release(stype);
0453 }
0454
0455
0456
0457
0458
0459 double getStepSize(const State& state, ConstrainedStep::Type stype) const {
0460 return state.stepSize.value(stype);
0461 }
0462
0463
0464
0465
0466 std::string outputStepSize(const State& state) const {
0467 return state.stepSize.toString();
0468 }
0469
0470
0471
0472
0473
0474
0475
0476
0477
0478
0479
0480
0481
0482 Result<BoundState> boundState(
0483 State& state, const Surface& surface, bool transportCov = true,
0484 const FreeToBoundCorrection& freeToBoundCorrection =
0485 FreeToBoundCorrection(false)) const {
0486
0487 state.state_ready = false;
0488
0489 Acts::Vector4 pos4;
0490 pos4[ePos0] = state.pVector[0];
0491 pos4[ePos1] = state.pVector[1];
0492 pos4[ePos2] = state.pVector[2];
0493 pos4[eTime] = state.pVector[3];
0494 Acts::Vector3 dir;
0495 dir[eMom0] = state.pVector[4];
0496 dir[eMom1] = state.pVector[5];
0497 dir[eMom2] = state.pVector[6];
0498 const auto qOverP = state.pVector[7];
0499
0500
0501 std::optional<Covariance> covOpt = std::nullopt;
0502 if (state.covTransport && transportCov) {
0503 transportCovarianceToBound(state, surface, freeToBoundCorrection);
0504 }
0505 if (state.cov != Covariance::Zero()) {
0506 covOpt = state.cov;
0507 }
0508
0509
0510 auto parameters = BoundTrackParameters::create(
0511 state.options.geoContext, surface.getSharedPtr(), pos4, dir, qOverP,
0512 std::move(covOpt), state.particleHypothesis);
0513 if (!parameters.ok()) {
0514 return parameters.error();
0515 }
0516
0517 Jacobian jacobian(state.jacobian);
0518
0519 return BoundState(std::move(*parameters), jacobian.transpose(),
0520 state.pathAccumulated);
0521 }
0522
0523
0524
0525
0526
0527
0528
0529
0530 bool prepareCurvilinearState(State& state) const {
0531 (void)state;
0532 return true;
0533 }
0534
0535
0536
0537
0538
0539
0540
0541
0542
0543
0544
0545 BoundState curvilinearState(State& state, bool transportCov = true) const {
0546
0547 state.state_ready = false;
0548
0549 Acts::Vector4 pos4;
0550 pos4[ePos0] = state.pVector[0];
0551 pos4[ePos1] = state.pVector[1];
0552 pos4[ePos2] = state.pVector[2];
0553 pos4[eTime] = state.pVector[3];
0554 Acts::Vector3 dir;
0555 dir[eMom0] = state.pVector[4];
0556 dir[eMom1] = state.pVector[5];
0557 dir[eMom2] = state.pVector[6];
0558 const auto qOverP = state.pVector[7];
0559
0560 std::optional<Covariance> covOpt = std::nullopt;
0561 if (state.covTransport && transportCov) {
0562 transportCovarianceToCurvilinear(state);
0563 }
0564 if (state.cov != Covariance::Zero()) {
0565 covOpt = state.cov;
0566 }
0567
0568 BoundTrackParameters parameters = BoundTrackParameters::createCurvilinear(
0569 pos4, dir, qOverP, std::move(covOpt), state.particleHypothesis);
0570
0571 Jacobian jacobian(state.jacobian);
0572
0573 return BoundState(std::move(parameters), jacobian.transpose(),
0574 state.pathAccumulated);
0575 }
0576
0577
0578
0579
0580
0581
0582
0583
0584 void update(State& state, const FreeVector& parameters,
0585 const BoundVector& boundParams, const Covariance& covariance,
0586 const Surface& surface) const {
0587 Vector3 direction = parameters.template segment<3>(eFreeDir0).normalized();
0588 state.pVector[0] = parameters[eFreePos0];
0589 state.pVector[1] = parameters[eFreePos1];
0590 state.pVector[2] = parameters[eFreePos2];
0591 state.pVector[3] = parameters[eFreeTime];
0592 state.pVector[4] = direction.x();
0593 state.pVector[5] = direction.y();
0594 state.pVector[6] = direction.z();
0595 state.pVector[7] = std::copysign(parameters[eFreeQOverP], state.pVector[7]);
0596
0597
0598 if (std::abs(state.pVector[7]) < .000000000000001) {
0599 state.pVector[7] < 0. ? state.pVector[7] = -.000000000000001
0600 : state.pVector[7] = .000000000000001;
0601 }
0602
0603
0604
0605
0606 Vector3 pos(state.pVector[0], state.pVector[1], state.pVector[2]);
0607 Vector3 mom(state.pVector[4], state.pVector[5], state.pVector[6]);
0608
0609 double Sf = std::sin(boundParams[eBoundPhi]);
0610 double Cf = std::cos(boundParams[eBoundPhi]);
0611 double Se = std::sin(boundParams[eBoundTheta]);
0612 double Ce = std::cos(boundParams[eBoundTheta]);
0613
0614 const auto transform =
0615 surface.referenceFrame(state.options.geoContext, pos, mom);
0616
0617 state.pVector[8] = transform(0, eBoundLoc0);
0618 state.pVector[16] = transform(0, eBoundLoc1);
0619 state.pVector[24] = 0.;
0620 state.pVector[32] = 0.;
0621 state.pVector[40] = 0.;
0622 state.pVector[48] = 0.;
0623
0624 state.pVector[9] = transform(1, eBoundLoc0);
0625 state.pVector[17] = transform(1, eBoundLoc1);
0626 state.pVector[25] = 0.;
0627 state.pVector[33] = 0.;
0628 state.pVector[41] = 0.;
0629 state.pVector[49] = 0.;
0630
0631 state.pVector[10] = transform(2, eBoundLoc0);
0632 state.pVector[18] = transform(2, eBoundLoc1);
0633 state.pVector[26] = 0.;
0634 state.pVector[34] = 0.;
0635 state.pVector[42] = 0.;
0636 state.pVector[50] = 0.;
0637
0638 state.pVector[11] = 0.;
0639 state.pVector[19] = 0.;
0640 state.pVector[27] = 0.;
0641 state.pVector[35] = 0.;
0642 state.pVector[43] = 0.;
0643 state.pVector[51] = 1.;
0644
0645 state.pVector[12] = 0.;
0646 state.pVector[20] = 0.;
0647 state.pVector[28] = -Sf * Se;
0648 state.pVector[36] = Cf * Ce;
0649 state.pVector[44] = 0.;
0650 state.pVector[52] = 0.;
0651
0652 state.pVector[13] = 0.;
0653 state.pVector[21] = 0.;
0654 state.pVector[29] = Cf * Se;
0655 state.pVector[37] = Sf * Ce;
0656 state.pVector[45] = 0.;
0657 state.pVector[53] = 0.;
0658
0659 state.pVector[14] = 0.;
0660 state.pVector[22] = 0.;
0661 state.pVector[30] = 0.;
0662 state.pVector[38] = -Se;
0663 state.pVector[46] = 0.;
0664 state.pVector[54] = 0.;
0665
0666 state.pVector[15] = 0.;
0667 state.pVector[23] = 0.;
0668 state.pVector[31] = 0.;
0669 state.pVector[39] = 0.;
0670 state.pVector[47] = 1.;
0671 state.pVector[55] = 0.;
0672
0673 state.pVector[56] = 0.;
0674 state.pVector[57] = 0.;
0675 state.pVector[58] = 0.;
0676 state.pVector[59] = 0.;
0677
0678
0679
0680 if (surface.type() == Surface::Disc) {
0681 double lCf = std::cos(boundParams[eBoundLoc1]);
0682 double lSf = std::sin(boundParams[eBoundLoc1]);
0683 double Ax[3] = {transform(0, 0), transform(1, 0), transform(2, 0)};
0684 double Ay[3] = {transform(0, 1), transform(1, 1), transform(2, 1)};
0685 double d0 = lCf * Ax[0] + lSf * Ay[0];
0686 double d1 = lCf * Ax[1] + lSf * Ay[1];
0687 double d2 = lCf * Ax[2] + lSf * Ay[2];
0688 state.pVector[8] = d0;
0689 state.pVector[9] = d1;
0690 state.pVector[10] = d2;
0691 state.pVector[16] = boundParams[eBoundLoc0] * (lCf * Ay[0] - lSf * Ax[0]);
0692 state.pVector[17] = boundParams[eBoundLoc0] * (lCf * Ay[1] - lSf * Ax[1]);
0693 state.pVector[18] = boundParams[eBoundLoc0] * (lCf * Ay[2] - lSf * Ax[2]);
0694 }
0695
0696
0697 if (surface.type() == Surface::Perigee ||
0698 surface.type() == Surface::Straw) {
0699
0700
0701 double B[3] = {transform(0, 0), transform(1, 0), transform(2, 0)};
0702
0703 double A[3] = {transform(0, 1), transform(1, 1), transform(2, 1)};
0704
0705 double C[3] = {transform(0, 2), transform(1, 2), transform(2, 2)};
0706
0707
0708 double PC = state.pVector[4] * C[0] + state.pVector[5] * C[1] +
0709 state.pVector[6] * C[2];
0710 double Bn = 1. / PC;
0711
0712 double Bx2 = -A[2] * state.pVector[29];
0713 double Bx3 = A[1] * state.pVector[38] - A[2] * state.pVector[37];
0714
0715 double By2 = A[2] * state.pVector[28];
0716 double By3 = A[2] * state.pVector[36] - A[0] * state.pVector[38];
0717
0718 double Bz2 = A[0] * state.pVector[29] - A[1] * state.pVector[28];
0719 double Bz3 = A[0] * state.pVector[37] - A[1] * state.pVector[36];
0720
0721 double B2 = B[0] * Bx2 + B[1] * By2 + B[2] * Bz2;
0722 double B3 = B[0] * Bx3 + B[1] * By3 + B[2] * Bz3;
0723
0724 Bx2 = (Bx2 - B[0] * B2) * Bn;
0725 Bx3 = (Bx3 - B[0] * B3) * Bn;
0726 By2 = (By2 - B[1] * B2) * Bn;
0727 By3 = (By3 - B[1] * B3) * Bn;
0728 Bz2 = (Bz2 - B[2] * B2) * Bn;
0729 Bz3 = (Bz3 - B[2] * B3) * Bn;
0730
0731
0732 state.pVector[24] = Bx2 * boundParams[eBoundLoc0];
0733 state.pVector[32] = Bx3 * boundParams[eBoundLoc0];
0734 state.pVector[25] = By2 * boundParams[eBoundLoc0];
0735 state.pVector[33] = By3 * boundParams[eBoundLoc0];
0736 state.pVector[26] = Bz2 * boundParams[eBoundLoc0];
0737 state.pVector[34] = Bz3 * boundParams[eBoundLoc0];
0738 }
0739
0740 state.covariance = new BoundSquareMatrix(covariance);
0741 state.covTransport = true;
0742 state.useJacobian = true;
0743
0744
0745 state.state_ready = true;
0746 }
0747
0748
0749
0750
0751
0752
0753
0754
0755 void update(State& state, const Vector3& uposition, const Vector3& udirection,
0756 double qop, double time) const {
0757
0758 state.pVector[0] = uposition[0];
0759 state.pVector[1] = uposition[1];
0760 state.pVector[2] = uposition[2];
0761 state.pVector[3] = time;
0762 state.pVector[4] = udirection[0];
0763 state.pVector[5] = udirection[1];
0764 state.pVector[6] = udirection[2];
0765 state.pVector[7] = qop;
0766 }
0767
0768
0769
0770
0771
0772
0773 void transportCovarianceToCurvilinear(State& state) const {
0774 double P[60];
0775 for (unsigned int i = 0; i < 60; ++i) {
0776 P[i] = state.pVector[i];
0777 }
0778
0779 double p = 1. / P[7];
0780 P[40] *= p;
0781 P[41] *= p;
0782 P[42] *= p;
0783 P[44] *= p;
0784 P[45] *= p;
0785 P[46] *= p;
0786
0787 double An = std::sqrt(P[4] * P[4] + P[5] * P[5]);
0788 double Ax[3];
0789 if (An != 0.) {
0790 Ax[0] = -P[5] / An;
0791 Ax[1] = P[4] / An;
0792 Ax[2] = 0.;
0793 } else {
0794 Ax[0] = 1.;
0795 Ax[1] = 0.;
0796 Ax[2] = 0.;
0797 }
0798
0799 double Ay[3] = {-Ax[1] * P[6], Ax[0] * P[6], An};
0800 double S[3] = {P[4], P[5], P[6]};
0801
0802 double A = P[4] * S[0] + P[5] * S[1] + P[6] * S[2];
0803 if (A != 0.) {
0804 A = 1. / A;
0805 }
0806 S[0] *= A;
0807 S[1] *= A;
0808 S[2] *= A;
0809
0810 double s0 = P[8] * S[0] + P[9] * S[1] + P[10] * S[2];
0811 double s1 = P[16] * S[0] + P[17] * S[1] + P[18] * S[2];
0812 double s2 = P[24] * S[0] + P[25] * S[1] + P[26] * S[2];
0813 double s3 = P[32] * S[0] + P[33] * S[1] + P[34] * S[2];
0814 double s4 = P[40] * S[0] + P[41] * S[1] + P[42] * S[2];
0815
0816 P[8] -= (s0 * P[4]);
0817 P[9] -= (s0 * P[5]);
0818 P[10] -= (s0 * P[6]);
0819 P[11] -= (s0 * P[59]);
0820 P[12] -= (s0 * P[56]);
0821 P[13] -= (s0 * P[57]);
0822 P[14] -= (s0 * P[58]);
0823 P[16] -= (s1 * P[4]);
0824 P[17] -= (s1 * P[5]);
0825 P[18] -= (s1 * P[6]);
0826 P[19] -= (s1 * P[59]);
0827 P[20] -= (s1 * P[56]);
0828 P[21] -= (s1 * P[57]);
0829 P[22] -= (s1 * P[58]);
0830 P[24] -= (s2 * P[4]);
0831 P[25] -= (s2 * P[5]);
0832 P[26] -= (s2 * P[6]);
0833 P[27] -= (s2 * P[59]);
0834 P[28] -= (s2 * P[56]);
0835 P[29] -= (s2 * P[57]);
0836 P[30] -= (s2 * P[58]);
0837 P[32] -= (s3 * P[4]);
0838 P[33] -= (s3 * P[5]);
0839 P[34] -= (s3 * P[6]);
0840 P[35] -= (s3 * P[59]);
0841 P[36] -= (s3 * P[56]);
0842 P[37] -= (s3 * P[57]);
0843 P[38] -= (s3 * P[58]);
0844 P[40] -= (s4 * P[4]);
0845 P[41] -= (s4 * P[5]);
0846 P[42] -= (s4 * P[6]);
0847 P[43] -= (s4 * P[59]);
0848 P[44] -= (s4 * P[56]);
0849 P[45] -= (s4 * P[57]);
0850 P[46] -= (s4 * P[58]);
0851
0852 double P3 = 0, P4 = 0, C = P[4] * P[4] + P[5] * P[5];
0853 if (C > 1.e-20) {
0854 C = 1. / C;
0855 P3 = P[4] * C;
0856 P4 = P[5] * C;
0857 C = -sqrt(C);
0858 } else {
0859 C = -1.e10;
0860 P3 = 1.;
0861 P4 = 0.;
0862 }
0863
0864
0865
0866 state.jacobian[0] = Ax[0] * P[8] + Ax[1] * P[9];
0867 state.jacobian[1] = Ax[0] * P[16] + Ax[1] * P[17];
0868 state.jacobian[2] = Ax[0] * P[24] + Ax[1] * P[25];
0869 state.jacobian[3] = Ax[0] * P[32] + Ax[1] * P[33];
0870 state.jacobian[4] = Ax[0] * P[40] + Ax[1] * P[41];
0871 state.jacobian[5] = 0.;
0872
0873 state.jacobian[6] = Ay[0] * P[8] + Ay[1] * P[9] + Ay[2] * P[10];
0874 state.jacobian[7] =
0875 Ay[0] * P[16] + Ay[1] * P[17] + Ay[2] * P[18];
0876 state.jacobian[8] =
0877 Ay[0] * P[24] + Ay[1] * P[25] + Ay[2] * P[26];
0878 state.jacobian[9] =
0879 Ay[0] * P[32] + Ay[1] * P[33] + Ay[2] * P[34];
0880 state.jacobian[10] =
0881 Ay[0] * P[40] + Ay[1] * P[41] + Ay[2] * P[42];
0882 state.jacobian[11] = 0.;
0883
0884 state.jacobian[12] = P3 * P[13] - P4 * P[12];
0885 state.jacobian[13] = P3 * P[21] - P4 * P[20];
0886 state.jacobian[14] = P3 * P[29] - P4 * P[28];
0887 state.jacobian[15] = P3 * P[37] - P4 * P[36];
0888 state.jacobian[16] = P3 * P[45] - P4 * P[44];
0889 state.jacobian[17] = 0.;
0890
0891 state.jacobian[18] = C * P[14];
0892 state.jacobian[19] = C * P[22];
0893 state.jacobian[20] = C * P[30];
0894 state.jacobian[21] = C * P[38];
0895 state.jacobian[22] = C * P[46];
0896 state.jacobian[23] = 0.;
0897
0898 state.jacobian[24] = 0.;
0899 state.jacobian[25] = 0.;
0900 state.jacobian[26] = 0.;
0901 state.jacobian[27] = 0.;
0902 state.jacobian[28] = P[47];
0903 state.jacobian[29] = 0.;
0904
0905 state.jacobian[30] = P[11];
0906 state.jacobian[31] = P[19];
0907 state.jacobian[32] = P[27];
0908 state.jacobian[33] = P[35];
0909 state.jacobian[34] = P[43];
0910 state.jacobian[35] = P[51];
0911
0912 Eigen::Map<Eigen::Matrix<double, eBoundSize, eBoundSize, Eigen::RowMajor>>
0913 J(state.jacobian);
0914 state.cov = J * (*state.covariance) * J.transpose();
0915 }
0916
0917
0918
0919
0920
0921
0922
0923 void transportCovarianceToBound(
0924 State& state, const Surface& surface,
0925 const FreeToBoundCorrection& =
0926 FreeToBoundCorrection(false)) const {
0927 Acts::Vector3 gp(state.pVector[0], state.pVector[1], state.pVector[2]);
0928 Acts::Vector3 mom(state.pVector[4], state.pVector[5], state.pVector[6]);
0929
0930 double P[60];
0931 for (unsigned int i = 0; i < 60; ++i) {
0932 P[i] = state.pVector[i];
0933 }
0934
0935 mom /= std::abs(state.pVector[7]);
0936
0937 double p = 1. / state.pVector[7];
0938 P[40] *= p;
0939 P[41] *= p;
0940 P[42] *= p;
0941 P[44] *= p;
0942 P[45] *= p;
0943 P[46] *= p;
0944
0945 const auto fFrame =
0946 surface.referenceFrame(state.options.geoContext, gp, mom);
0947
0948 double Ax[3] = {fFrame(0, 0), fFrame(1, 0), fFrame(2, 0)};
0949 double Ay[3] = {fFrame(0, 1), fFrame(1, 1), fFrame(2, 1)};
0950 double S[3] = {fFrame(0, 2), fFrame(1, 2), fFrame(2, 2)};
0951
0952
0953 double A = P[4] * S[0] + P[5] * S[1] + P[6] * S[2];
0954
0955 if (A != 0.) {
0956 A = 1. / A;
0957 }
0958
0959 S[0] *= A;
0960 S[1] *= A;
0961 S[2] *= A;
0962
0963 double s0 = P[8] * S[0] + P[9] * S[1] + P[10] * S[2];
0964 double s1 = P[16] * S[0] + P[17] * S[1] + P[18] * S[2];
0965 double s2 = P[24] * S[0] + P[25] * S[1] + P[26] * S[2];
0966 double s3 = P[32] * S[0] + P[33] * S[1] + P[34] * S[2];
0967 double s4 = P[40] * S[0] + P[41] * S[1] + P[42] * S[2];
0968
0969
0970
0971
0972 if (surface.type() == Surface::Straw ||
0973 surface.type() == Surface::Perigee) {
0974
0975 double x = P[0] - surface.center(state.options.geoContext).x();
0976 double y = P[1] - surface.center(state.options.geoContext).y();
0977 double z = P[2] - surface.center(state.options.geoContext).z();
0978
0979
0980 double d = P[4] * Ay[0] + P[5] * Ay[1] + P[6] * Ay[2];
0981
0982
0983 double a = (1. - d) * (1. + d);
0984 if (a != 0.) {
0985 a = 1. / a;
0986 }
0987
0988
0989 double X = d * Ay[0] - P[4];
0990 double Y = d * Ay[1] - P[5];
0991 double Z = d * Ay[2] - P[6];
0992
0993
0994 double d0 = P[12] * Ay[0] + P[13] * Ay[1] + P[14] * Ay[2];
0995 double d1 = P[20] * Ay[0] + P[21] * Ay[1] + P[22] * Ay[2];
0996 double d2 = P[28] * Ay[0] + P[29] * Ay[1] + P[30] * Ay[2];
0997 double d3 = P[36] * Ay[0] + P[37] * Ay[1] + P[38] * Ay[2];
0998 double d4 = P[44] * Ay[0] + P[45] * Ay[1] + P[46] * Ay[2];
0999
1000 s0 = (((P[8] * X + P[9] * Y + P[10] * Z) + x * (d0 * Ay[0] - P[12])) +
1001 (y * (d0 * Ay[1] - P[13]) + z * (d0 * Ay[2] - P[14]))) *
1002 (-a);
1003
1004 s1 = (((P[16] * X + P[17] * Y + P[18] * Z) + x * (d1 * Ay[0] - P[20])) +
1005 (y * (d1 * Ay[1] - P[21]) + z * (d1 * Ay[2] - P[22]))) *
1006 (-a);
1007 s2 = (((P[24] * X + P[25] * Y + P[26] * Z) + x * (d2 * Ay[0] - P[28])) +
1008 (y * (d2 * Ay[1] - P[29]) + z * (d2 * Ay[2] - P[30]))) *
1009 (-a);
1010 s3 = (((P[32] * X + P[33] * Y + P[34] * Z) + x * (d3 * Ay[0] - P[36])) +
1011 (y * (d3 * Ay[1] - P[37]) + z * (d3 * Ay[2] - P[38]))) *
1012 (-a);
1013 s4 = (((P[40] * X + P[41] * Y + P[42] * Z) + x * (d4 * Ay[0] - P[44])) +
1014 (y * (d4 * Ay[1] - P[45]) + z * (d4 * Ay[2] - P[46]))) *
1015 (-a);
1016 }
1017
1018 P[8] -= (s0 * P[4]);
1019 P[9] -= (s0 * P[5]);
1020 P[10] -= (s0 * P[6]);
1021 P[11] -= (s0 * P[59]);
1022 P[12] -= (s0 * P[56]);
1023 P[13] -= (s0 * P[57]);
1024 P[14] -= (s0 * P[58]);
1025
1026 P[16] -= (s1 * P[4]);
1027 P[17] -= (s1 * P[5]);
1028 P[18] -= (s1 * P[6]);
1029 P[19] -= (s1 * P[59]);
1030 P[20] -= (s1 * P[56]);
1031 P[21] -= (s1 * P[57]);
1032 P[22] -= (s1 * P[58]);
1033
1034 P[24] -= (s2 * P[4]);
1035 P[25] -= (s2 * P[5]);
1036 P[26] -= (s2 * P[6]);
1037 P[27] -= (s2 * P[59]);
1038 P[28] -= (s2 * P[56]);
1039 P[29] -= (s2 * P[57]);
1040 P[30] -= (s2 * P[58]);
1041
1042 P[32] -= (s3 * P[4]);
1043 P[33] -= (s3 * P[5]);
1044 P[34] -= (s3 * P[6]);
1045 P[35] -= (s3 * P[59]);
1046 P[36] -= (s3 * P[56]);
1047 P[37] -= (s3 * P[57]);
1048 P[38] -= (s3 * P[58]);
1049
1050 P[40] -= (s4 * P[4]);
1051 P[41] -= (s4 * P[5]);
1052 P[42] -= (s4 * P[6]);
1053 P[43] -= (s4 * P[59]);
1054 P[44] -= (s4 * P[56]);
1055 P[45] -= (s4 * P[57]);
1056 P[46] -= (s4 * P[58]);
1057
1058 double P3 = 0, P4 = 0, C = P[4] * P[4] + P[5] * P[5];
1059 if (C > 1.e-20) {
1060 C = 1. / C;
1061 P3 = P[4] * C;
1062 P4 = P[5] * C;
1063 C = -sqrt(C);
1064 } else {
1065 C = -1.e10;
1066 P3 = 1.;
1067 P4 = 0.;
1068 }
1069
1070 double MA[3] = {Ax[0], Ax[1], Ax[2]};
1071 double MB[3] = {Ay[0], Ay[1], Ay[2]};
1072
1073 if (surface.type() == Surface::Disc) {
1074
1075 const auto& sfc = surface.center(state.options.geoContext);
1076 double d[3] = {P[0] - sfc(0), P[1] - sfc(1), P[2] - sfc(2)};
1077
1078 double RC = d[0] * Ax[0] + d[1] * Ax[1] + d[2] * Ax[2];
1079 double RS = d[0] * Ay[0] + d[1] * Ay[1] + d[2] * Ay[2];
1080 double R2 = RC * RC + RS * RS;
1081
1082
1083 double Ri = 1. / sqrt(R2);
1084 MA[0] = (RC * Ax[0] + RS * Ay[0]) * Ri;
1085 MA[1] = (RC * Ax[1] + RS * Ay[1]) * Ri;
1086 MA[2] = (RC * Ax[2] + RS * Ay[2]) * Ri;
1087 MB[0] = (RC * Ay[0] - RS * Ax[0]) * (Ri = 1. / R2);
1088 MB[1] = (RC * Ay[1] - RS * Ax[1]) * Ri;
1089 MB[2] = (RC * Ay[2] - RS * Ax[2]) * Ri;
1090 }
1091
1092 state.jacobian[0] = MA[0] * P[8] + MA[1] * P[9] + MA[2] * P[10];
1093 state.jacobian[1] =
1094 MA[0] * P[16] + MA[1] * P[17] + MA[2] * P[18];
1095 state.jacobian[2] =
1096 MA[0] * P[24] + MA[1] * P[25] + MA[2] * P[26];
1097 state.jacobian[3] =
1098 MA[0] * P[32] + MA[1] * P[33] + MA[2] * P[34];
1099 state.jacobian[4] =
1100 MA[0] * P[40] + MA[1] * P[41] + MA[2] * P[42];
1101 state.jacobian[5] = 0.;
1102
1103 state.jacobian[6] = MB[0] * P[8] + MB[1] * P[9] + MB[2] * P[10];
1104 state.jacobian[7] =
1105 MB[0] * P[16] + MB[1] * P[17] + MB[2] * P[18];
1106 state.jacobian[8] =
1107 MB[0] * P[24] + MB[1] * P[25] + MB[2] * P[26];
1108 state.jacobian[9] =
1109 MB[0] * P[32] + MB[1] * P[33] + MB[2] * P[34];
1110 state.jacobian[10] =
1111 MB[0] * P[40] + MB[1] * P[41] + MB[2] * P[42];
1112 state.jacobian[11] = 0.;
1113
1114 state.jacobian[12] = P3 * P[13] - P4 * P[12];
1115 state.jacobian[13] = P3 * P[21] - P4 * P[20];
1116 state.jacobian[14] = P3 * P[29] - P4 * P[28];
1117 state.jacobian[15] = P3 * P[37] - P4 * P[36];
1118 state.jacobian[16] = P3 * P[45] - P4 * P[44];
1119 state.jacobian[17] = 0.;
1120
1121 state.jacobian[18] = C * P[14];
1122 state.jacobian[19] = C * P[22];
1123 state.jacobian[20] = C * P[30];
1124 state.jacobian[21] = C * P[38];
1125 state.jacobian[22] = C * P[46];
1126 state.jacobian[23] = 0.;
1127
1128 state.jacobian[24] = 0.;
1129 state.jacobian[25] = 0.;
1130 state.jacobian[26] = 0.;
1131 state.jacobian[27] = 0.;
1132 state.jacobian[28] = P[47];
1133 state.jacobian[29] = 0.;
1134
1135 state.jacobian[30] = P[11];
1136 state.jacobian[31] = P[19];
1137 state.jacobian[32] = P[27];
1138 state.jacobian[33] = P[35];
1139 state.jacobian[34] = P[43];
1140 state.jacobian[35] = P[51];
1141
1142 Eigen::Map<Eigen::Matrix<double, eBoundSize, eBoundSize, Eigen::RowMajor>>
1143 J(state.jacobian);
1144 state.cov = J * (*state.covariance) * J.transpose();
1145 }
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159 Result<double> step(State& state, Direction propDir,
1160 const IVolumeMaterial* material) const {
1161 (void)material;
1162
1163
1164 auto h = state.stepSize.value() * propDir;
1165 bool Jac = state.useJacobian;
1166
1167 double* R = &(state.pVector[0]);
1168 double* A = &(state.pVector[4]);
1169 double* sA = &(state.pVector[56]);
1170
1171 double Pi = 0.5 * state.pVector[7];
1172
1173 Vector3 f0, f;
1174
1175
1176 if (state.newfield) {
1177 const Vector3 pos(R[0], R[1], R[2]);
1178
1179 auto fRes = getField(state, pos);
1180 if (!fRes.ok()) {
1181 return fRes.error();
1182 }
1183 f0 = *fRes;
1184 } else {
1185 f0 = state.field;
1186 }
1187
1188 bool Helix = false;
1189
1190
1191 const auto calcStepSizeScaling =
1192 [&](const double errorEstimate_) -> double {
1193
1194 constexpr double lower = 0.25;
1195 constexpr double upper = 4.0;
1196
1197 constexpr double exponent = 0.25;
1198
1199 double x = state.options.stepTolerance / errorEstimate_;
1200
1201 if constexpr (exponent == 0.25) {
1202
1203 x = std::sqrt(std::sqrt(x));
1204 } else {
1205 x = std::pow(x, exponent);
1206 }
1207
1208 return std::clamp(x, lower, upper);
1209 };
1210
1211 const auto isErrorTolerable = [&](const double errorEstimate_) {
1212
1213 constexpr double marginFactor = 4.0;
1214
1215 return errorEstimate_ <= marginFactor * state.options.stepTolerance;
1216 };
1217
1218 double EST = 0;
1219 double initialH = h;
1220
1221 std::size_t nStepTrials = 0;
1222 while (h != 0.) {
1223 nStepTrials++;
1224
1225
1226 double S3 = (1. / 3.) * h, S4 = .25 * h, PS2 = Pi * h;
1227
1228
1229
1230
1231 double H0[3] = {f0[0] * PS2, f0[1] * PS2, f0[2] * PS2};
1232
1233 double A0 = A[1] * H0[2] - A[2] * H0[1];
1234 double B0 = A[2] * H0[0] - A[0] * H0[2];
1235 double C0 = A[0] * H0[1] - A[1] * H0[0];
1236
1237 double A2 = A0 + A[0];
1238 double B2 = B0 + A[1];
1239 double C2 = C0 + A[2];
1240
1241 double A1 = A2 + A[0];
1242 double B1 = B2 + A[1];
1243 double C1 = C2 + A[2];
1244
1245
1246
1247 if (!Helix) {
1248
1249 const Vector3 pos(R[0] + A1 * S4, R[1] + B1 * S4, R[2] + C1 * S4);
1250
1251 auto fRes = getField(state, pos);
1252 if (!fRes.ok()) {
1253 return fRes.error();
1254 }
1255 f = *fRes;
1256 } else {
1257 f = f0;
1258 }
1259
1260
1261 double H1[3] = {f[0] * PS2, f[1] * PS2, f[2] * PS2};
1262
1263 double A3 = (A[0] + B2 * H1[2]) - C2 * H1[1];
1264 double B3 = (A[1] + C2 * H1[0]) - A2 * H1[2];
1265 double C3 = (A[2] + A2 * H1[1]) - B2 * H1[0];
1266
1267 double A4 = (A[0] + B3 * H1[2]) - C3 * H1[1];
1268 double B4 = (A[1] + C3 * H1[0]) - A3 * H1[2];
1269 double C4 = (A[2] + A3 * H1[1]) - B3 * H1[0];
1270
1271 double A5 = 2. * A4 - A[0];
1272 double B5 = 2. * B4 - A[1];
1273 double C5 = 2. * C4 - A[2];
1274
1275
1276
1277 if (!Helix) {
1278
1279 const Vector3 pos(R[0] + h * A4, R[1] + h * B4, R[2] + h * C4);
1280
1281 auto fRes = getField(state, pos);
1282 if (!fRes.ok()) {
1283 return fRes.error();
1284 }
1285 f = *fRes;
1286 } else {
1287 f = f0;
1288 }
1289
1290
1291 double H2[3] = {f[0] * PS2, f[1] * PS2, f[2] * PS2};
1292
1293 double A6 = B5 * H2[2] - C5 * H2[1];
1294 double B6 = C5 * H2[0] - A5 * H2[2];
1295 double C6 = A5 * H2[1] - B5 * H2[0];
1296
1297
1298
1299
1300
1301 EST = 2. * std::abs(h) *
1302 (std::abs((A1 + A6) - (A3 + A4)) + std::abs((B1 + B6) - (B3 + B4)) +
1303 std::abs((C1 + C6) - (C3 + C4)));
1304 EST = std::max(1e-20, EST);
1305 if (!isErrorTolerable(EST)) {
1306 const double stepSizeScaling = calcStepSizeScaling(EST);
1307 h *= stepSizeScaling;
1308
1309 state.stepSize.setAccuracy(h * propDir);
1310
1311 continue;
1312 }
1313
1314
1315
1316
1317
1318 double A00 = A[0], A11 = A[1], A22 = A[2];
1319
1320 A[0] = 2. * A3 + (A0 + A5 + A6);
1321 A[1] = 2. * B3 + (B0 + B5 + B6);
1322 A[2] = 2. * C3 + (C0 + C5 + C6);
1323
1324 double D = (A[0] * A[0] + A[1] * A[1]) + (A[2] * A[2] - 9.);
1325 double Sl = 2. / h;
1326 D = (1. / 3.) - ((1. / 648.) * D) * (12. - D);
1327
1328 R[0] += (A2 + A3 + A4) * S3;
1329 R[1] += (B2 + B3 + B4) * S3;
1330 R[2] += (C2 + C3 + C4) * S3;
1331 A[0] *= D;
1332 A[1] *= D;
1333 A[2] *= D;
1334 sA[0] = A6 * Sl;
1335 sA[1] = B6 * Sl;
1336 sA[2] = C6 * Sl;
1337
1338 double mass = particleHypothesis(state).mass();
1339 double momentum = absoluteMomentum(state);
1340
1341
1342 double dtds = std::sqrt(1 + mass * mass / (momentum * momentum));
1343 state.pVector[3] += h * dtds;
1344 state.pVector[59] = dtds;
1345 state.field = f;
1346 state.newfield = false;
1347
1348 if (Jac) {
1349 double dtdl = h * mass * mass * qOverP(state) / dtds;
1350 state.pVector[43] += dtdl;
1351
1352
1353
1354 double* d2A = &state.pVector[28];
1355 double* d3A = &state.pVector[36];
1356 double* d4A = &state.pVector[44];
1357 double d2A0 = H0[2] * d2A[1] - H0[1] * d2A[2];
1358 double d2B0 = H0[0] * d2A[2] - H0[2] * d2A[0];
1359 double d2C0 = H0[1] * d2A[0] - H0[0] * d2A[1];
1360 double d3A0 = H0[2] * d3A[1] - H0[1] * d3A[2];
1361 double d3B0 = H0[0] * d3A[2] - H0[2] * d3A[0];
1362 double d3C0 = H0[1] * d3A[0] - H0[0] * d3A[1];
1363 double d4A0 = (A0 + H0[2] * d4A[1]) - H0[1] * d4A[2];
1364 double d4B0 = (B0 + H0[0] * d4A[2]) - H0[2] * d4A[0];
1365 double d4C0 = (C0 + H0[1] * d4A[0]) - H0[0] * d4A[1];
1366 double d2A2 = d2A0 + d2A[0];
1367 double d2B2 = d2B0 + d2A[1];
1368 double d2C2 = d2C0 + d2A[2];
1369 double d3A2 = d3A0 + d3A[0];
1370 double d3B2 = d3B0 + d3A[1];
1371 double d3C2 = d3C0 + d3A[2];
1372 double d4A2 = d4A0 + d4A[0];
1373 double d4B2 = d4B0 + d4A[1];
1374 double d4C2 = d4C0 + d4A[2];
1375 double d0 = d4A[0] - A00;
1376 double d1 = d4A[1] - A11;
1377 double d2 = d4A[2] - A22;
1378 double d2A3 = (d2A[0] + d2B2 * H1[2]) - d2C2 * H1[1];
1379 double d2B3 = (d2A[1] + d2C2 * H1[0]) - d2A2 * H1[2];
1380 double d2C3 = (d2A[2] + d2A2 * H1[1]) - d2B2 * H1[0];
1381 double d3A3 = (d3A[0] + d3B2 * H1[2]) - d3C2 * H1[1];
1382 double d3B3 = (d3A[1] + d3C2 * H1[0]) - d3A2 * H1[2];
1383 double d3C3 = (d3A[2] + d3A2 * H1[1]) - d3B2 * H1[0];
1384 double d4A3 = ((A3 + d0) + d4B2 * H1[2]) - d4C2 * H1[1];
1385 double d4B3 = ((B3 + d1) + d4C2 * H1[0]) - d4A2 * H1[2];
1386 double d4C3 = ((C3 + d2) + d4A2 * H1[1]) - d4B2 * H1[0];
1387 double d2A4 = (d2A[0] + d2B3 * H1[2]) - d2C3 * H1[1];
1388 double d2B4 = (d2A[1] + d2C3 * H1[0]) - d2A3 * H1[2];
1389 double d2C4 = (d2A[2] + d2A3 * H1[1]) - d2B3 * H1[0];
1390 double d3A4 = (d3A[0] + d3B3 * H1[2]) - d3C3 * H1[1];
1391 double d3B4 = (d3A[1] + d3C3 * H1[0]) - d3A3 * H1[2];
1392 double d3C4 = (d3A[2] + d3A3 * H1[1]) - d3B3 * H1[0];
1393 double d4A4 = ((A4 + d0) + d4B3 * H1[2]) - d4C3 * H1[1];
1394 double d4B4 = ((B4 + d1) + d4C3 * H1[0]) - d4A3 * H1[2];
1395 double d4C4 = ((C4 + d2) + d4A3 * H1[1]) - d4B3 * H1[0];
1396 double d2A5 = 2. * d2A4 - d2A[0];
1397 double d2B5 = 2. * d2B4 - d2A[1];
1398 double d2C5 = 2. * d2C4 - d2A[2];
1399 double d3A5 = 2. * d3A4 - d3A[0];
1400 double d3B5 = 2. * d3B4 - d3A[1];
1401 double d3C5 = 2. * d3C4 - d3A[2];
1402 double d4A5 = 2. * d4A4 - d4A[0];
1403 double d4B5 = 2. * d4B4 - d4A[1];
1404 double d4C5 = 2. * d4C4 - d4A[2];
1405 double d2A6 = d2B5 * H2[2] - d2C5 * H2[1];
1406 double d2B6 = d2C5 * H2[0] - d2A5 * H2[2];
1407 double d2C6 = d2A5 * H2[1] - d2B5 * H2[0];
1408 double d3A6 = d3B5 * H2[2] - d3C5 * H2[1];
1409 double d3B6 = d3C5 * H2[0] - d3A5 * H2[2];
1410 double d3C6 = d3A5 * H2[1] - d3B5 * H2[0];
1411 double d4A6 = d4B5 * H2[2] - d4C5 * H2[1];
1412 double d4B6 = d4C5 * H2[0] - d4A5 * H2[2];
1413 double d4C6 = d4A5 * H2[1] - d4B5 * H2[0];
1414
1415 double* dR = &state.pVector[24];
1416 dR[0] += (d2A2 + d2A3 + d2A4) * S3;
1417 dR[1] += (d2B2 + d2B3 + d2B4) * S3;
1418 dR[2] += (d2C2 + d2C3 + d2C4) * S3;
1419 d2A[0] = ((d2A0 + 2. * d2A3) + (d2A5 + d2A6)) * (1. / 3.);
1420 d2A[1] = ((d2B0 + 2. * d2B3) + (d2B5 + d2B6)) * (1. / 3.);
1421 d2A[2] = ((d2C0 + 2. * d2C3) + (d2C5 + d2C6)) * (1. / 3.);
1422
1423 dR = &state.pVector[32];
1424 dR[0] += (d3A2 + d3A3 + d3A4) * S3;
1425 dR[1] += (d3B2 + d3B3 + d3B4) * S3;
1426 dR[2] += (d3C2 + d3C3 + d3C4) * S3;
1427 d3A[0] = ((d3A0 + 2. * d3A3) + (d3A5 + d3A6)) * (1. / 3.);
1428 d3A[1] = ((d3B0 + 2. * d3B3) + (d3B5 + d3B6)) * (1. / 3.);
1429 d3A[2] = ((d3C0 + 2. * d3C3) + (d3C5 + d3C6)) * (1. / 3.);
1430
1431 dR = &state.pVector[40];
1432 dR[0] += (d4A2 + d4A3 + d4A4) * S3;
1433 dR[1] += (d4B2 + d4B3 + d4B4) * S3;
1434 dR[2] += (d4C2 + d4C3 + d4C4) * S3;
1435 d4A[0] = ((d4A0 + 2. * d4A3) + (d4A5 + d4A6 + A6)) * (1. / 3.);
1436 d4A[1] = ((d4B0 + 2. * d4B3) + (d4B5 + d4B6 + B6)) * (1. / 3.);
1437 d4A[2] = ((d4C0 + 2. * d4C3) + (d4C5 + d4C6 + C6)) * (1. / 3.);
1438 }
1439
1440 break;
1441 }
1442
1443 state.pathAccumulated += h;
1444 ++state.nSteps;
1445 state.nStepTrials += nStepTrials;
1446
1447 const double stepSizeScaling = calcStepSizeScaling(EST);
1448 const double nextAccuracy = std::abs(h * stepSizeScaling);
1449 const double previousAccuracy = std::abs(state.stepSize.accuracy());
1450 const double initialStepLength = std::abs(initialH);
1451 if (nextAccuracy < initialStepLength || nextAccuracy > previousAccuracy) {
1452 state.stepSize.setAccuracy(nextAccuracy);
1453 }
1454
1455 return h;
1456 }
1457
1458
1459
1460
1461
1462 void setIdentityJacobian(State& state) const {
1463 state.jacobian[0] = 1.;
1464 state.jacobian[1] = 0.;
1465 state.jacobian[2] = 0.;
1466 state.jacobian[3] = 0.;
1467 state.jacobian[4] = 0.;
1468 state.jacobian[5] = 0.;
1469
1470 state.jacobian[6] = 0.;
1471 state.jacobian[7] = 1.;
1472 state.jacobian[8] = 0.;
1473 state.jacobian[9] = 0.;
1474 state.jacobian[10] = 0.;
1475 state.jacobian[11] = 0.;
1476
1477 state.jacobian[12] = 0.;
1478 state.jacobian[13] = 0.;
1479 state.jacobian[14] = 1.;
1480 state.jacobian[15] = 0.;
1481 state.jacobian[16] = 0.;
1482 state.jacobian[17] = 0.;
1483
1484 state.jacobian[18] = 0.;
1485 state.jacobian[19] = 0.;
1486 state.jacobian[20] = 0.;
1487 state.jacobian[21] = 1.;
1488 state.jacobian[22] = 0.;
1489 state.jacobian[23] = 0.;
1490
1491 state.jacobian[24] = 0.;
1492 state.jacobian[25] = 0.;
1493 state.jacobian[26] = 0.;
1494 state.jacobian[27] = 0.;
1495 state.jacobian[28] = 1.;
1496 state.jacobian[29] = 0.;
1497
1498 state.jacobian[30] = 0.;
1499 state.jacobian[31] = 0.;
1500 state.jacobian[32] = 0.;
1501 state.jacobian[33] = 0.;
1502 state.jacobian[34] = 0.;
1503 state.jacobian[35] = 1.;
1504 }
1505
1506 private:
1507 std::shared_ptr<const MagneticFieldProvider> m_bField;
1508
1509
1510 double m_overstepLimit = 100 * UnitConstants::um;
1511 };
1512
1513 }