File indexing completed on 2025-01-18 09:10:57
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/Material/Interactions.hpp"
0016 #include "Acts/Material/Material.hpp"
0017 #include "Acts/Material/MaterialSlab.hpp"
0018 #include "Acts/Propagator/EigenStepperDefaultExtension.hpp"
0019 #include "Acts/Propagator/Propagator.hpp"
0020 #include "Acts/Utilities/MathHelpers.hpp"
0021
0022 namespace Acts {
0023
0024
0025
0026
0027
0028
0029 struct EigenStepperDenseExtension {
0030
0031 EigenStepperDefaultExtension defaultExtension;
0032
0033
0034 double currentMomentum = 0.;
0035
0036 double initialMomentum = 0.;
0037
0038
0039 Material material;
0040
0041 std::array<double, 4> dLdl{};
0042
0043 std::array<double, 4> qop{};
0044
0045 std::array<double, 4> dPds{};
0046
0047 double dgdqopValue = 0.;
0048
0049 double g = 0.;
0050
0051 std::array<double, 4> tKi{};
0052
0053 std::array<double, 4> Lambdappi{};
0054
0055 std::array<double, 4> energy{};
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075 template <int i, typename propagator_state_t, typename stepper_t,
0076 typename navigator_t>
0077 bool k(const propagator_state_t& state, const stepper_t& stepper,
0078 const navigator_t& navigator, Vector3& knew, const Vector3& bField,
0079 std::array<double, 4>& kQoP, const double h = 0.,
0080 const Vector3& kprev = Vector3::Zero())
0081 requires(i >= 0 && i <= 3)
0082 {
0083 const auto* volumeMaterial =
0084 navigator.currentVolumeMaterial(state.navigation);
0085 if (volumeMaterial == nullptr) {
0086 return defaultExtension.template k<i>(state, stepper, navigator, knew,
0087 bField, kQoP, h, kprev);
0088 }
0089
0090 double q = stepper.charge(state.stepping);
0091 const auto& particleHypothesis = stepper.particleHypothesis(state.stepping);
0092 float mass = particleHypothesis.mass();
0093
0094
0095 if constexpr (i == 0) {
0096
0097 Vector3 position = stepper.position(state.stepping);
0098 material = volumeMaterial->material(position.template cast<double>());
0099 initialMomentum = stepper.absoluteMomentum(state.stepping);
0100 currentMomentum = initialMomentum;
0101 qop[0] = stepper.qOverP(state.stepping);
0102 initializeEnergyLoss(state, stepper);
0103
0104 knew = qop[0] * stepper.direction(state.stepping).cross(bField);
0105
0106 Lambdappi[0] = -qop[0] * qop[0] * qop[0] * g * energy[0] / (q * q);
0107
0108 tKi[0] = fastHypot(1, mass * qop[0]);
0109 kQoP[0] = Lambdappi[0];
0110 } else {
0111
0112 updateEnergyLoss(mass, h, state, stepper, i);
0113 if (currentMomentum < state.options.stepping.dense.momentumCutOff) {
0114 return false;
0115 }
0116
0117 knew = qop[i] *
0118 (stepper.direction(state.stepping) + h * kprev).cross(bField);
0119
0120 auto qopNew = qop[0] + h * Lambdappi[i - 1];
0121 Lambdappi[i] = -qopNew * qopNew * qopNew * g * energy[i] / (q * q);
0122 tKi[i] = fastHypot(1, mass * qopNew);
0123 kQoP[i] = Lambdappi[i];
0124 }
0125 return true;
0126 }
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143 template <typename propagator_state_t, typename stepper_t,
0144 typename navigator_t>
0145 bool finalize(propagator_state_t& state, const stepper_t& stepper,
0146 const navigator_t& navigator, const double h) const {
0147 const auto* volumeMaterial =
0148 navigator.currentVolumeMaterial(state.navigation);
0149 if (volumeMaterial == nullptr) {
0150 return defaultExtension.finalize(state, stepper, navigator, h);
0151 }
0152
0153 const auto& particleHypothesis = stepper.particleHypothesis(state.stepping);
0154 float mass = particleHypothesis.mass();
0155
0156
0157 auto newMomentum =
0158 stepper.absoluteMomentum(state.stepping) +
0159 (h / 6.) * (dPds[0] + 2. * (dPds[1] + dPds[2]) + dPds[3]);
0160
0161
0162 if (newMomentum < state.options.stepping.dense.momentumCutOff) {
0163 return false;
0164 }
0165
0166
0167 state.stepping.derivative(7) = -fastHypot(mass, newMomentum) * g /
0168 (newMomentum * newMomentum * newMomentum);
0169
0170
0171 state.stepping.pars[eFreeQOverP] =
0172 stepper.charge(state.stepping) / newMomentum;
0173
0174 state.stepping.derivative(3) = fastHypot(1, mass / newMomentum);
0175
0176 state.stepping.pars[eFreeTime] +=
0177 (h / 6.) * (tKi[0] + 2. * (tKi[1] + tKi[2]) + tKi[3]);
0178
0179 return true;
0180 }
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200 template <typename propagator_state_t, typename stepper_t,
0201 typename navigator_t>
0202 bool finalize(propagator_state_t& state, const stepper_t& stepper,
0203 const navigator_t& navigator, const double h,
0204 FreeMatrix& D) const {
0205 const auto* volumeMaterial =
0206 navigator.currentVolumeMaterial(state.navigation);
0207 if (volumeMaterial == nullptr) {
0208 return defaultExtension.finalize(state, stepper, navigator, h, D);
0209 }
0210
0211 return finalize(state, stepper, navigator, h) &&
0212 transportMatrix(state, stepper, h, D);
0213 }
0214
0215 private:
0216
0217
0218
0219
0220
0221
0222
0223
0224
0225
0226
0227 template <typename propagator_state_t, typename stepper_t>
0228 bool transportMatrix(propagator_state_t& state, const stepper_t& stepper,
0229 const double h, FreeMatrix& D) const {
0230
0231
0232
0233
0234
0235
0236
0237
0238
0239
0240
0241
0242
0243
0244
0245
0246
0247
0248
0249
0250 auto& sd = state.stepping.stepData;
0251 auto dir = stepper.direction(state.stepping);
0252 const auto& particleHypothesis = stepper.particleHypothesis(state.stepping);
0253 float mass = particleHypothesis.mass();
0254
0255 D = FreeMatrix::Identity();
0256 const double half_h = h * 0.5;
0257
0258
0259
0260 auto dFdT = D.block<3, 3>(0, 4);
0261 auto dFdL = D.block<3, 1>(0, 7);
0262
0263 auto dGdT = D.block<3, 3>(4, 4);
0264 auto dGdL = D.block<3, 1>(4, 7);
0265
0266 SquareMatrix3 dk1dT = SquareMatrix3::Zero();
0267 SquareMatrix3 dk2dT = SquareMatrix3::Identity();
0268 SquareMatrix3 dk3dT = SquareMatrix3::Identity();
0269 SquareMatrix3 dk4dT = SquareMatrix3::Identity();
0270
0271 Vector3 dk1dL = Vector3::Zero();
0272 Vector3 dk2dL = Vector3::Zero();
0273 Vector3 dk3dL = Vector3::Zero();
0274 Vector3 dk4dL = Vector3::Zero();
0275
0276
0277 std::array<double, 4> jdL{};
0278
0279
0280 jdL[0] = dLdl[0];
0281 dk1dL = dir.cross(sd.B_first);
0282
0283 jdL[1] = dLdl[1] * (1. + half_h * jdL[0]);
0284 dk2dL = (1. + half_h * jdL[0]) * (dir + half_h * sd.k1).cross(sd.B_middle) +
0285 qop[1] * half_h * dk1dL.cross(sd.B_middle);
0286
0287 jdL[2] = dLdl[2] * (1. + half_h * jdL[1]);
0288 dk3dL = (1. + half_h * jdL[1]) * (dir + half_h * sd.k2).cross(sd.B_middle) +
0289 qop[2] * half_h * dk2dL.cross(sd.B_middle);
0290
0291 jdL[3] = dLdl[3] * (1. + h * jdL[2]);
0292 dk4dL = (1. + h * jdL[2]) * (dir + h * sd.k3).cross(sd.B_last) +
0293 qop[3] * h * dk3dL.cross(sd.B_last);
0294
0295 dk1dT(0, 1) = sd.B_first.z();
0296 dk1dT(0, 2) = -sd.B_first.y();
0297 dk1dT(1, 0) = -sd.B_first.z();
0298 dk1dT(1, 2) = sd.B_first.x();
0299 dk1dT(2, 0) = sd.B_first.y();
0300 dk1dT(2, 1) = -sd.B_first.x();
0301 dk1dT *= qop[0];
0302
0303 dk2dT += half_h * dk1dT;
0304 dk2dT = qop[1] * VectorHelpers::cross(dk2dT, sd.B_middle);
0305
0306 dk3dT += half_h * dk2dT;
0307 dk3dT = qop[2] * VectorHelpers::cross(dk3dT, sd.B_middle);
0308
0309 dk4dT += h * dk3dT;
0310 dk4dT = qop[3] * VectorHelpers::cross(dk4dT, sd.B_last);
0311
0312 dFdT.setIdentity();
0313 dFdT += h / 6. * (dk1dT + dk2dT + dk3dT);
0314 dFdT *= h;
0315
0316 dFdL = h * h / 6. * (dk1dL + dk2dL + dk3dL);
0317
0318 dGdT += h / 6. * (dk1dT + 2. * (dk2dT + dk3dT) + dk4dT);
0319
0320 dGdL = h / 6. * (dk1dL + 2. * (dk2dL + dk3dL) + dk4dL);
0321
0322
0323 D(7, 7) += (h / 6.) * (jdL[0] + 2. * (jdL[1] + jdL[2]) + jdL[3]);
0324
0325
0326
0327
0328
0329
0330
0331
0332 double dtp1dl = qop[0] * mass * mass / fastHypot(1, qop[0] * mass);
0333 double qopNew = qop[0] + half_h * Lambdappi[0];
0334
0335
0336
0337
0338
0339
0340 double dtp2dl = qopNew * mass * mass / fastHypot(1, qopNew * mass);
0341 qopNew = qop[0] + half_h * Lambdappi[1];
0342
0343
0344
0345
0346
0347
0348 double dtp3dl = qopNew * mass * mass / fastHypot(1, qopNew * mass);
0349 qopNew = qop[0] + half_h * Lambdappi[2];
0350 double dtp4dl = qopNew * mass * mass / fastHypot(1, qopNew * mass);
0351
0352
0353
0354
0355
0356 D(3, 7) = (h / 6.) * (dtp1dl + 2. * (dtp2dl + dtp3dl) + dtp4dl);
0357 return true;
0358 }
0359
0360
0361
0362
0363
0364
0365
0366
0367
0368 template <typename propagator_state_t, typename stepper_t>
0369 void initializeEnergyLoss(const propagator_state_t& state,
0370 const stepper_t& stepper) {
0371 const auto& particleHypothesis = stepper.particleHypothesis(state.stepping);
0372 float mass = particleHypothesis.mass();
0373 PdgParticle absPdg = particleHypothesis.absolutePdg();
0374 float absQ = particleHypothesis.absoluteCharge();
0375
0376 energy[0] = fastHypot(initialMomentum, mass);
0377
0378 MaterialSlab slab(material, 1);
0379
0380 if (state.options.stepping.dense.meanEnergyLoss) {
0381 g = -computeEnergyLossMean(slab, absPdg, mass, static_cast<float>(qop[0]),
0382 absQ);
0383 } else {
0384
0385
0386 g = -computeEnergyLossMode(slab, absPdg, mass, static_cast<float>(qop[0]),
0387 absQ);
0388 }
0389
0390
0391 dPds[0] = g * energy[0] / initialMomentum;
0392 if (state.stepping.covTransport) {
0393
0394
0395 if (state.options.stepping.dense.includeGradient) {
0396 if (state.options.stepping.dense.meanEnergyLoss) {
0397 dgdqopValue = deriveEnergyLossMeanQOverP(
0398 slab, absPdg, mass, static_cast<float>(qop[0]), absQ);
0399 } else {
0400
0401 dgdqopValue = deriveEnergyLossModeQOverP(
0402 slab, absPdg, mass, static_cast<float>(qop[0]), absQ);
0403 }
0404 }
0405
0406 dLdl[0] = (-qop[0] * qop[0] * g * energy[0] *
0407 (3. - (initialMomentum * initialMomentum) /
0408 (energy[0] * energy[0])) -
0409 qop[0] * qop[0] * qop[0] * energy[0] * dgdqopValue);
0410 }
0411 }
0412
0413
0414
0415
0416
0417
0418
0419
0420
0421
0422
0423
0424 template <typename propagator_state_t, typename stepper_t>
0425 void updateEnergyLoss(const double mass, const double h,
0426 const propagator_state_t& state,
0427 const stepper_t& stepper, const int i) {
0428
0429 currentMomentum = initialMomentum + h * dPds[i - 1];
0430 energy[i] = fastHypot(currentMomentum, mass);
0431 dPds[i] = g * energy[i] / currentMomentum;
0432 qop[i] = stepper.charge(state.stepping) / currentMomentum;
0433
0434 if (state.stepping.covTransport) {
0435 dLdl[i] = (-qop[i] * qop[i] * g * energy[i] *
0436 (3. - (currentMomentum * currentMomentum) /
0437 (energy[i] * energy[i])) -
0438 qop[i] * qop[i] * qop[i] * energy[i] * dgdqopValue);
0439 }
0440 }
0441 };
0442
0443 }