File indexing completed on 2025-01-18 09:12:13
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011 #include "Acts/Material/ISurfaceMaterial.hpp"
0012 #include "Acts/Propagator/ConstrainedStep.hpp"
0013 #include "Acts/Propagator/PropagatorState.hpp"
0014 #include "Acts/Propagator/StandardAborters.hpp"
0015 #include "Acts/Surfaces/Surface.hpp"
0016 #include "ActsFatras/EventData/Particle.hpp"
0017 #include "ActsFatras/Kernel/SimulationResult.hpp"
0018
0019 #include <algorithm>
0020 #include <cassert>
0021 #include <cmath>
0022
0023 namespace ActsFatras::detail {
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037 template <typename generator_t, typename decay_t, typename interactions_t,
0038 typename hit_surface_selector_t>
0039 struct SimulationActor {
0040 using result_type = SimulationResult;
0041
0042
0043 generator_t *generator = nullptr;
0044
0045 decay_t decay;
0046
0047 interactions_t interactions;
0048
0049 hit_surface_selector_t selectHitSurface;
0050
0051 Particle initialParticle;
0052
0053
0054 double properTimeRelativeTolerance = 1e-3;
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065 template <typename propagator_state_t, typename stepper_t,
0066 typename navigator_t>
0067 void act(propagator_state_t &state, stepper_t &stepper,
0068 navigator_t &navigator, result_type &result,
0069 const Acts::Logger &logger) const {
0070 assert(generator != nullptr && "The generator pointer must be valid");
0071
0072 if (state.stage == Acts::PropagatorStage::prePropagation) {
0073
0074
0075 result.particle =
0076 makeParticle(initialParticle, state, stepper, navigator);
0077 result.properTimeLimit =
0078 decay.generateProperTimeLimit(*generator, initialParticle);
0079 return;
0080 }
0081
0082
0083 if (!result.isAlive) {
0084 return;
0085 }
0086
0087 if (Acts::EndOfWorldReached{}.checkAbort(state, stepper, navigator,
0088 logger)) {
0089 result.isAlive = false;
0090 return;
0091 }
0092
0093
0094
0095
0096
0097 result.particle = makeParticle(result.particle, state, stepper, navigator);
0098
0099
0100 if (std::isfinite(result.properTimeLimit) &&
0101 (result.properTimeLimit - result.particle.properTime() <
0102 result.properTimeLimit * properTimeRelativeTolerance)) {
0103 auto descendants = decay.run(generator, result.particle);
0104 for (const auto &descendant : descendants) {
0105 result.generatedParticles.emplace_back(descendant);
0106 }
0107 result.isAlive = false;
0108 return;
0109 }
0110
0111
0112 if (std::isfinite(result.properTimeLimit)) {
0113 assert(result.particle.mass() > 0.0 && "Particle must have mass");
0114
0115
0116
0117
0118 const auto properTimeDiff =
0119 result.properTimeLimit - result.particle.properTime();
0120
0121
0122 const auto stepSize = properTimeDiff *
0123 result.particle.absoluteMomentum() /
0124 result.particle.mass();
0125 stepper.releaseStepSize(state.stepping,
0126 Acts::ConstrainedStep::Type::User);
0127 stepper.updateStepSize(state.stepping, stepSize,
0128 Acts::ConstrainedStep::Type::User);
0129 }
0130
0131
0132 if (std::isnan(result.x0Limit) || std::isnan(result.l0Limit)) {
0133 armPointLikeInteractions(initialParticle, result);
0134 }
0135
0136
0137 if (state.stage == Acts::PropagatorStage::postPropagation) {
0138 return;
0139 }
0140
0141 if (!navigator.currentSurface(state.navigation)) {
0142 return;
0143 }
0144 const Acts::Surface &surface = *navigator.currentSurface(state.navigation);
0145
0146
0147
0148 const Particle before = result.particle;
0149
0150
0151 if (surface.surfaceMaterial()) {
0152
0153
0154
0155 auto lpResult = surface.globalToLocal(state.geoContext, before.position(),
0156 before.direction());
0157 if (lpResult.ok()) {
0158 Acts::Vector2 local = lpResult.value();
0159 Acts::MaterialSlab slab =
0160 surface.surfaceMaterial()->materialSlab(local);
0161
0162 if (slab.isValid()) {
0163
0164 auto normal = surface.normal(state.geoContext, before.position(),
0165 before.direction());
0166
0167
0168 auto cosIncidenceInv = normal.norm() / normal.dot(before.direction());
0169
0170 slab.scaleThickness(std::abs(cosIncidenceInv));
0171
0172 interact(slab, result);
0173 }
0174 }
0175 }
0176 Particle &after = result.particle;
0177
0178
0179 if (selectHitSurface(surface)) {
0180 result.hits.emplace_back(
0181 surface.geometryId(), before.particleId(),
0182
0183 0.5 * (before.fourPosition() + after.fourPosition()),
0184 before.fourMomentum(), after.fourMomentum(), result.hits.size());
0185
0186 after.setNumberOfHits(result.hits.size());
0187 }
0188
0189 if (after.absoluteMomentum() == 0.0) {
0190 result.isAlive = false;
0191 return;
0192 }
0193
0194
0195 stepper.update(state.stepping, after.position(), after.direction(),
0196 after.qOverP(), after.time());
0197 }
0198
0199 template <typename propagator_state_t, typename stepper_t,
0200 typename navigator_t>
0201 bool checkAbort(propagator_state_t & , const stepper_t & ,
0202 const navigator_t & , const result_type &result,
0203 const Acts::Logger & ) const {
0204
0205 return !result.isAlive;
0206 }
0207
0208
0209 template <typename propagator_state_t, typename stepper_t,
0210 typename navigator_t>
0211 Particle makeParticle(const Particle &previous, propagator_state_t &state,
0212 stepper_t &stepper, navigator_t &navigator) const {
0213
0214
0215
0216
0217 const auto deltaLabTime = stepper.time(state.stepping) - previous.time();
0218
0219
0220
0221
0222 const auto gammaInv = previous.mass() / previous.energy();
0223 const auto properTime = previous.properTime() + gammaInv * deltaLabTime;
0224 const Acts::Surface *currentSurface = nullptr;
0225 if (navigator.currentSurface(state.navigation) != nullptr) {
0226 currentSurface = navigator.currentSurface(state.navigation);
0227 }
0228
0229 return Particle(previous)
0230 .setPosition4(stepper.position(state.stepping),
0231 stepper.time(state.stepping))
0232 .setDirection(stepper.direction(state.stepping))
0233 .setAbsoluteMomentum(stepper.absoluteMomentum(state.stepping))
0234 .setProperTime(properTime)
0235 .setReferenceSurface(currentSurface);
0236 }
0237
0238
0239 void armPointLikeInteractions(const Particle &particle,
0240 result_type &result) const {
0241 auto selection = interactions.armPointLike(*generator, particle);
0242 result.x0Limit = selection.x0Limit;
0243 result.l0Limit = selection.l0Limit;
0244 result.x0Process = selection.x0Process;
0245 result.l0Process = selection.l0Process;
0246 }
0247
0248
0249
0250
0251
0252 void interact(const Acts::MaterialSlab &slab, result_type &result) const {
0253
0254
0255 auto runContinuousPartial = [&, this](float fraction) {
0256 Acts::MaterialSlab partialSlab = slab;
0257 partialSlab.scaleThickness(fraction);
0258
0259 const auto x0 = result.particle.pathInX0() + partialSlab.thicknessInX0();
0260 const auto l0 = result.particle.pathInX0() + partialSlab.thicknessInL0();
0261 bool retval = false;
0262 if (interactions.runContinuous(*(this->generator), partialSlab,
0263 result.particle,
0264 result.generatedParticles)) {
0265 result.isAlive = false;
0266 retval = true;
0267 }
0268
0269
0270
0271
0272
0273 result.particle.setMaterialPassed(x0, l0);
0274 return retval;
0275 };
0276
0277
0278 const auto slabX0 = slab.thicknessInX0();
0279 const auto slabL0 = slab.thicknessInL0();
0280
0281
0282 const auto x0Dist = result.x0Limit - result.particle.pathInX0();
0283 const auto l0Dist = result.l0Limit - result.particle.pathInL0();
0284
0285
0286
0287
0288
0289
0290
0291
0292
0293
0294
0295
0296
0297
0298
0299
0300
0301 const float fracX0 =
0302 std::clamp(static_cast<float>(x0Dist / slabX0), 0.0f, 1.0f);
0303 const float fracL0 =
0304 std::clamp(static_cast<float>(l0Dist / slabL0), 0.0f, 1.0f);
0305
0306 const float frac = std::min(fracX0, fracL0);
0307
0308
0309 if (0.0f < frac) {
0310
0311 if (runContinuousPartial(frac)) {
0312 return;
0313 }
0314 }
0315
0316 if (frac < 1.0f) {
0317
0318 const std::size_t process =
0319 (fracX0 < fracL0) ? result.x0Process : result.l0Process;
0320
0321 if (interactions.runPointLike(*generator, process, result.particle,
0322 result.generatedParticles)) {
0323 result.isAlive = false;
0324 return;
0325 }
0326
0327 if (runContinuousPartial(1.0 - frac)) {
0328 return;
0329 }
0330
0331
0332
0333
0334
0335
0336
0337 armPointLikeInteractions(result.particle, result);
0338 }
0339 }
0340 };
0341
0342 }