File indexing completed on 2026-08-05 08:41:12
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/Definitions/Common.hpp"
0013 #include "Acts/Definitions/Direction.hpp"
0014 #include "Acts/Definitions/TrackParametrization.hpp"
0015 #include "Acts/Definitions/Units.hpp"
0016 #include "Acts/EventData/ParticleHypothesis.hpp"
0017 #include "Acts/Geometry/GeometryContext.hpp"
0018 #include "Acts/Material/MaterialSlab.hpp"
0019 #include "Acts/Surfaces/Surface.hpp"
0020
0021 #include <algorithm>
0022 #include <cmath>
0023
0024 namespace Acts::detail {
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035 MaterialUpdateMode determineMaterialUpdateMode(
0036 const Surface& surface, const Surface* startSurface,
0037 const Surface* targetSurface, MaterialUpdateMode requestedMode);
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050 template <typename propagator_state_t, typename navigator_t>
0051 MaterialUpdateMode determineMaterialUpdateMode(
0052 const propagator_state_t& state, const navigator_t& navigator,
0053 MaterialUpdateMode requestedMode) {
0054 const Surface* surface = navigator.currentSurface(state.navigation);
0055 const Surface* startSurface = navigator.startSurface(state.navigation);
0056 const Surface* targetSurface = navigator.targetSurface(state.navigation);
0057
0058 if (surface == nullptr) {
0059 return MaterialUpdateMode::NoUpdate;
0060 }
0061
0062 return determineMaterialUpdateMode(*surface, startSurface, targetSurface,
0063 requestedMode);
0064 }
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074 MaterialSlab evaluateMaterialSlab(const GeometryContext& geoContext,
0075 const Surface& surface,
0076 Direction propagationDirection,
0077 const Vector3& position,
0078 const Vector3& direction,
0079 MaterialUpdateMode updateMode);
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089 template <typename propagator_state_t, typename stepper_t>
0090 MaterialSlab evaluateMaterialSlab(const propagator_state_t& state,
0091 const stepper_t& stepper,
0092 const Surface& surface,
0093 MaterialUpdateMode updateMode) {
0094 const GeometryContext& geoContext = state.options.geoContext;
0095 const Direction propagationDirection = state.options.direction;
0096 const Vector3 position = stepper.position(state.stepping);
0097 const Vector3 direction = stepper.direction(state.stepping);
0098
0099 return evaluateMaterialSlab(geoContext, surface, propagationDirection,
0100 position, direction, updateMode);
0101 }
0102
0103
0104 struct PointwiseMaterialEffects {
0105 double eLoss = 0;
0106 double variancePhi = 0;
0107 double varianceTheta = 0;
0108 double varianceQoverP = 0;
0109 };
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120 PointwiseMaterialEffects computeMaterialEffects(
0121 const MaterialSlab& slab, const ParticleHypothesis& particleHypothesis,
0122 const Vector3& direction, float qOverP, bool multipleScattering,
0123 bool energyLoss, bool covTransport);
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134 template <typename propagator_state_t, typename stepper_t>
0135 PointwiseMaterialEffects computeMaterialEffects(const propagator_state_t& state,
0136 const stepper_t& stepper,
0137 const MaterialSlab& slab,
0138 bool multipleScattering,
0139 bool energyLoss) {
0140 const bool covTransport = state.stepping.covTransport;
0141 const Vector3 direction = stepper.direction(state.stepping);
0142 const float qOverP = stepper.qOverP(state.stepping);
0143 const ParticleHypothesis& particleHypothesis =
0144 stepper.particleHypothesis(state.stepping);
0145
0146 return computeMaterialEffects(slab, particleHypothesis, direction, qOverP,
0147 multipleScattering, energyLoss, covTransport);
0148 }
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161 template <typename propagator_state_t, typename stepper_t>
0162 PointwiseMaterialEffects performMaterialInteraction(
0163 propagator_state_t& state, const stepper_t& stepper,
0164 const MaterialSlab& slab, NoiseUpdateMode noiseUpdateMode,
0165 bool multipleScattering, bool energyLoss) {
0166 if (slab.isVacuum()) {
0167 return {};
0168 }
0169
0170 const PointwiseMaterialEffects effects = computeMaterialEffects(
0171 state, stepper, slab, multipleScattering, energyLoss);
0172
0173 const Direction propDir = state.options.direction;
0174 const ParticleHypothesis& particleHypothesis =
0175 stepper.particleHypothesis(state.stepping);
0176 const double mass = particleHypothesis.mass();
0177 const double absQ = particleHypothesis.absoluteCharge();
0178 const Vector3 position = stepper.position(state.stepping);
0179 const double time = stepper.time(state.stepping);
0180 const Vector3 direction = stepper.direction(state.stepping);
0181 const float qOverP = stepper.qOverP(state.stepping);
0182 const double momentum = stepper.absoluteMomentum(state.stepping);
0183
0184
0185
0186 const double nextE = fastHypot(mass, momentum) - effects.eLoss * propDir;
0187
0188 double nextP = (mass < nextE) ? std::sqrt(nextE * nextE - mass * mass) : 0;
0189
0190
0191
0192
0193 static constexpr double minP = 10 * Acts::UnitConstants::MeV;
0194 nextP = std::max(minP, nextP);
0195 const double nextQOverP =
0196 particleHypothesis.qOverP(nextP, std::copysign(absQ, qOverP));
0197
0198
0199 stepper.update(state.stepping, position, direction, nextQOverP, time);
0200
0201
0202
0203 const auto updateVariance = [](double variance, double change,
0204 NoiseUpdateMode updateMode) {
0205
0206
0207 return std::max(0.,
0208 variance + std::copysign(change, toUnderlying(updateMode)));
0209 };
0210
0211
0212 state.stepping.cov(eBoundPhi, eBoundPhi) =
0213 updateVariance(state.stepping.cov(eBoundPhi, eBoundPhi),
0214 effects.variancePhi, noiseUpdateMode);
0215 state.stepping.cov(eBoundTheta, eBoundTheta) =
0216 updateVariance(state.stepping.cov(eBoundTheta, eBoundTheta),
0217 effects.varianceTheta, noiseUpdateMode);
0218 state.stepping.cov(eBoundQOverP, eBoundQOverP) =
0219 updateVariance(state.stepping.cov(eBoundQOverP, eBoundQOverP),
0220 effects.varianceQoverP, noiseUpdateMode);
0221
0222 return effects;
0223 }
0224
0225
0226
0227
0228
0229
0230
0231
0232
0233
0234
0235
0236
0237
0238 template <typename propagator_state_t, typename stepper_t>
0239 PointwiseMaterialEffects performMaterialInteraction(
0240 propagator_state_t& state, const stepper_t& stepper, const Surface& surface,
0241 MaterialUpdateMode updateMode, NoiseUpdateMode noiseUpdateMode,
0242 bool multipleScattering, bool energyLoss, const Logger& logger) {
0243 const MaterialSlab slab =
0244 evaluateMaterialSlab(state, stepper, surface, updateMode);
0245 if (slab.isVacuum()) {
0246 ACTS_VERBOSE("No material effects on surface: " << surface.geometryId()
0247 << " with update mode: "
0248 << updateMode);
0249 }
0250
0251 const PointwiseMaterialEffects effects = performMaterialInteraction(
0252 state, stepper, slab, noiseUpdateMode, multipleScattering, energyLoss);
0253
0254 const Direction propDir = state.options.direction;
0255
0256 ACTS_VERBOSE("Material effects on surface: "
0257 << surface.geometryId() << " with update mode: " << updateMode
0258 << " are :");
0259 ACTS_VERBOSE("eLoss = " << effects.eLoss * propDir << ", "
0260 << "variancePhi = " << effects.variancePhi << ", "
0261 << "varianceTheta = " << effects.varianceTheta << ", "
0262 << "varianceQoverP = " << effects.varianceQoverP);
0263
0264 return effects;
0265 }
0266
0267 }