File indexing completed on 2026-06-28 07:34:46
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011 #include "Acts/Definitions/Common.hpp"
0012 #include "Acts/Definitions/PdgParticle.hpp"
0013 #include "Acts/Geometry/TrackingVolume.hpp"
0014 #include "Acts/Material/MaterialInteraction.hpp"
0015 #include "Acts/Material/MaterialSlab.hpp"
0016 #include "Acts/Propagator/PropagatorState.hpp"
0017 #include "Acts/Propagator/detail/PointwiseMaterialInteraction.hpp"
0018 #include "Acts/Propagator/detail/VolumeMaterialInteraction.hpp"
0019 #include "Acts/Surfaces/Surface.hpp"
0020
0021 namespace Acts {
0022
0023
0024
0025
0026 struct MaterialInteractor {
0027
0028 bool multipleScattering = true;
0029
0030 bool energyLoss = true;
0031
0032 bool recordInteractions = false;
0033
0034 NoiseUpdateMode noiseUpdateMode = NoiseUpdateMode::addNoise;
0035
0036
0037 using result_type = RecordedMaterial;
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057 template <typename propagator_state_t, typename stepper_t,
0058 typename navigator_t>
0059 Result<void> act(propagator_state_t& state, const stepper_t& stepper,
0060 const navigator_t& navigator, result_type& result,
0061 const Logger& logger) const {
0062 if (state.stage == PropagatorStage::postPropagation) {
0063 return Result<void>::success();
0064 }
0065
0066
0067 if (!(multipleScattering || energyLoss || recordInteractions)) {
0068 return Result<void>::success();
0069 }
0070
0071
0072
0073
0074
0075 const Surface* surface = navigator.currentSurface(state.navigation);
0076
0077
0078 if (surface != nullptr && surface->surfaceMaterial()) {
0079 ACTS_VERBOSE("MaterialInteractor | " << "Found material on surface "
0080 << surface->geometryId());
0081
0082 const Result<MaterialSlab> slabResult = detail::evaluateMaterialSlab(
0083 state, stepper, *surface,
0084 detail::determineMaterialUpdateMode(state, navigator,
0085 MaterialUpdateMode::FullUpdate));
0086 if (!slabResult.ok()) {
0087 ACTS_DEBUG("MaterialInteractor | "
0088 << "Failed to evaluate material slab: "
0089 << slabResult.error());
0090 return Result<void>::failure(slabResult.error());
0091 }
0092 const MaterialSlab& slab = *slabResult;
0093
0094
0095
0096 if (!slab.isVacuum()) {
0097
0098
0099 if (state.stepping.covTransport) {
0100 stepper.transportCovarianceToCurvilinear(state.stepping);
0101 }
0102
0103 const double initialMomentum = stepper.absoluteMomentum(state.stepping);
0104
0105
0106 const detail::PointwiseMaterialEffects effects =
0107 detail::performMaterialInteraction(state, stepper, slab,
0108 noiseUpdateMode,
0109 multipleScattering, energyLoss);
0110
0111 if (energyLoss) {
0112 using namespace UnitLiterals;
0113
0114 const ParticleHypothesis& particleHypothesis =
0115 stepper.particleHypothesis(state.stepping);
0116 const PdgParticle absPdg = particleHypothesis.absolutePdg();
0117 const double mass = particleHypothesis.mass();
0118 const double momentum = stepper.absoluteMomentum(state.stepping);
0119
0120 ACTS_VERBOSE("MaterialInteractor | "
0121 << slab << " absPdg=" << absPdg
0122 << " mass=" << mass / 1_MeV << "MeV"
0123 << " momentum=" << momentum / 1_GeV << "GeV"
0124 << " energyloss=" << effects.eLoss / 1_MeV << "MeV");
0125 }
0126
0127
0128 recordResult(state, stepper, navigator, slab, initialMomentum, effects,
0129 result);
0130 }
0131 }
0132
0133
0134
0135
0136 if (!result.materialInteractions.empty() &&
0137 !result.materialInteractions.back().volume.empty() &&
0138 result.materialInteractions.back().updatedVolumeStep == false) {
0139 updateResult(state, stepper, result);
0140 }
0141
0142 const TrackingVolume* volume = navigator.currentVolume(state.navigation);
0143
0144
0145 if (volume && volume->hasMaterial()) {
0146 ACTS_VERBOSE("MaterialInteractor | " << "Found material in volume "
0147 << volume->geometryId());
0148
0149
0150 detail::VolumeMaterialInteraction interaction(volume, state, stepper);
0151
0152
0153 if (interaction.evaluateMaterialSlab(state, navigator)) {
0154
0155 recordResult(interaction, result);
0156 }
0157 }
0158
0159 return Result<void>::success();
0160 }
0161
0162 private:
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176 template <typename propagator_state_t, typename stepper_t,
0177 typename navigator_t>
0178 void recordResult(const propagator_state_t& state, const stepper_t& stepper,
0179 const navigator_t& navigator, const MaterialSlab& slab,
0180 double initialMomentum,
0181 const detail::PointwiseMaterialEffects& effects,
0182 result_type& result) const {
0183 result.materialInX0 += slab.thicknessInX0();
0184 result.materialInL0 += slab.thicknessInL0();
0185
0186
0187 if (!recordInteractions) {
0188 return;
0189 }
0190
0191 const Vector3 position = stepper.position(state.stepping);
0192 const double time = stepper.time(state.stepping);
0193 const Vector3 direction = stepper.direction(state.stepping);
0194 const double finalMomentum = stepper.absoluteMomentum(state.stepping);
0195
0196 const Surface* surface = navigator.currentSurface(state.navigation);
0197 const double pathCorrection =
0198 surface->pathCorrection(state.options.geoContext, position, direction);
0199
0200 MaterialInteraction mi;
0201 mi.position = position;
0202 mi.time = time;
0203 mi.direction = direction;
0204 mi.deltaP = initialMomentum - finalMomentum;
0205 mi.sigmaPhi2 = effects.variancePhi;
0206 mi.sigmaTheta2 = effects.varianceTheta;
0207 mi.sigmaQoP2 = effects.varianceQoverP;
0208 mi.surface = surface;
0209 mi.volume = InteractionVolume();
0210 mi.pathCorrection = pathCorrection;
0211 mi.materialSlab = slab;
0212 result.materialInteractions.push_back(std::move(mi));
0213 }
0214
0215
0216
0217
0218
0219 void recordResult(const detail::VolumeMaterialInteraction& interaction,
0220 result_type& result) const {
0221
0222 if (!recordInteractions) {
0223 return;
0224 }
0225
0226 MaterialInteraction mi;
0227 mi.position = interaction.pos;
0228 mi.time = interaction.time;
0229 mi.direction = interaction.dir;
0230 mi.surface = nullptr;
0231 mi.volume = interaction.volume;
0232 mi.pathCorrection = interaction.pathCorrection;
0233 mi.materialSlab = interaction.slab;
0234 result.materialInteractions.push_back(std::move(mi));
0235 }
0236
0237
0238
0239
0240
0241
0242 template <typename propagator_state_t, typename stepper_t>
0243 void updateResult(propagator_state_t& state, const stepper_t& stepper,
0244 result_type& result) const {
0245
0246 if (!recordInteractions) {
0247 return;
0248 }
0249
0250 Vector3 shift = stepper.position(state.stepping) -
0251 result.materialInteractions.back().position;
0252 double momentum = stepper.direction(state.stepping).norm();
0253 result.materialInteractions.back().deltaP =
0254 momentum - result.materialInteractions.back().direction.norm();
0255 result.materialInteractions.back().materialSlab.scaleThickness(
0256 shift.norm());
0257 result.materialInteractions.back().updatedVolumeStep = true;
0258 result.materialInX0 +=
0259 result.materialInteractions.back().materialSlab.thicknessInX0();
0260 result.materialInL0 +=
0261 result.materialInteractions.back().materialSlab.thicknessInL0();
0262 }
0263 };
0264
0265 }