Warning, file /acts/Fatras/include/ActsFatras/Kernel/Simulation.hpp was not indexed
or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011 #include "Acts/Geometry/GeometryContext.hpp"
0012 #include "Acts/MagneticField/MagneticFieldContext.hpp"
0013 #include "Acts/Propagator/ActorList.hpp"
0014 #include "Acts/Utilities/Logger.hpp"
0015 #include "Acts/Utilities/Result.hpp"
0016 #include "ActsFatras/EventData/Particle.hpp"
0017 #include "ActsFatras/Kernel/SimulationResult.hpp"
0018 #include "ActsFatras/Kernel/detail/SimulationActor.hpp"
0019 #include "ActsFatras/Kernel/detail/SimulationError.hpp"
0020
0021 #include <algorithm>
0022 #include <cassert>
0023 #include <iterator>
0024 #include <memory>
0025 #include <vector>
0026
0027 namespace ActsFatras {
0028
0029
0030
0031
0032
0033
0034
0035 template <typename propagator_t, typename interactions_t,
0036 typename hit_surface_selector_t, typename decay_t>
0037 struct SingleParticleSimulation {
0038
0039 propagator_t propagator;
0040
0041 double maxStepSize = std::numeric_limits<double>::max();
0042
0043 double pathLimit = std::numeric_limits<double>::max();
0044
0045 decay_t decay;
0046
0047 interactions_t interactions;
0048
0049 hit_surface_selector_t selectHitSurface;
0050
0051 std::unique_ptr<const Acts::Logger> logger;
0052
0053
0054 SingleParticleSimulation(propagator_t &&propagator_,
0055 std::unique_ptr<const Acts::Logger> _logger)
0056 : propagator(propagator_), logger(std::move(_logger)) {}
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067 template <typename generator_t>
0068 Acts::Result<SimulationResult> simulate(
0069 const Acts::GeometryContext &geoCtx,
0070 const Acts::MagneticFieldContext &magCtx, generator_t &generator,
0071 const Particle &particle) const {
0072
0073 using Actor = detail::SimulationActor<generator_t, decay_t, interactions_t,
0074 hit_surface_selector_t>;
0075 using Result = typename Actor::result_type;
0076 using ActorList = Acts::ActorList<Actor>;
0077 using PropagatorOptions =
0078 typename propagator_t::template Options<ActorList>;
0079
0080
0081 PropagatorOptions options(geoCtx, magCtx);
0082 options.stepping.maxStepSize = maxStepSize;
0083 options.pathLimit = pathLimit;
0084
0085 auto &actor = options.actorList.template get<Actor>();
0086 actor.generator = &generator;
0087 actor.decay = decay;
0088 actor.interactions = interactions;
0089 actor.selectHitSurface = selectHitSurface;
0090 actor.initialParticle = particle;
0091
0092 if (particle.hasReferenceSurface()) {
0093 auto result = propagator.propagate(
0094 particle.boundParameters(geoCtx).value(), options);
0095 if (!result.ok()) {
0096 return result.error();
0097 }
0098 auto &value = result.value().template get<Result>();
0099 return std::move(value);
0100 }
0101
0102 auto result =
0103 propagator.propagate(particle.curvilinearParameters(), options);
0104 if (!result.ok()) {
0105 return result.error();
0106 }
0107 auto &value = result.value().template get<Result>();
0108 return std::move(value);
0109 }
0110 };
0111
0112
0113 struct FailedParticle {
0114
0115
0116
0117
0118
0119 Particle particle;
0120
0121 std::error_code error;
0122 };
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134 template <typename charged_selector_t, typename charged_simulator_t,
0135 typename neutral_selector_t, typename neutral_simulator_t>
0136 struct Simulation {
0137 charged_selector_t selectCharged;
0138 neutral_selector_t selectNeutral;
0139 charged_simulator_t charged;
0140 neutral_simulator_t neutral;
0141
0142
0143 Simulation(charged_simulator_t &&charged_, neutral_simulator_t &&neutral_)
0144 : charged(std::move(charged_)), neutral(std::move(neutral_)) {}
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182 template <typename generator_t, typename input_particles_t,
0183 typename output_particles_t, typename hits_t>
0184 Acts::Result<std::vector<FailedParticle>> simulate(
0185 const Acts::GeometryContext &geoCtx,
0186 const Acts::MagneticFieldContext &magCtx, generator_t &generator,
0187 const input_particles_t &inputParticles,
0188 output_particles_t &simulatedParticlesInitial,
0189 output_particles_t &simulatedParticlesFinal, hits_t &hits) const {
0190 assert(
0191 (simulatedParticlesInitial.size() == simulatedParticlesFinal.size()) &&
0192 "Inconsistent initial sizes of the simulated particle containers");
0193
0194 using SingleParticleSimulationResult = Acts::Result<SimulationResult>;
0195
0196 std::vector<FailedParticle> failedParticles;
0197
0198 for (const Particle &inputParticle : inputParticles) {
0199
0200 if (!selectParticle(inputParticle)) {
0201 continue;
0202 }
0203
0204 if ((inputParticle.particleId().generation() != 0u) ||
0205 (inputParticle.particleId().subParticle() != 0u)) {
0206 return detail::SimulationError::eInvalidInputParticleId;
0207 }
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218 auto iinitial = simulatedParticlesInitial.size();
0219 simulatedParticlesInitial.push_back(inputParticle);
0220 for (; iinitial < simulatedParticlesInitial.size(); ++iinitial) {
0221 const auto &initialParticle = simulatedParticlesInitial[iinitial];
0222
0223
0224
0225 SingleParticleSimulationResult result =
0226 SingleParticleSimulationResult::success({});
0227 if (initialParticle.charge() != 0.) {
0228 result = charged.simulate(geoCtx, magCtx, generator, initialParticle);
0229 } else {
0230 result = neutral.simulate(geoCtx, magCtx, generator, initialParticle);
0231 }
0232
0233 if (!result.ok()) {
0234
0235 simulatedParticlesInitial.erase(
0236 std::next(simulatedParticlesInitial.begin(), iinitial));
0237
0238 failedParticles.push_back({initialParticle, result.error()});
0239 continue;
0240 }
0241
0242 assert(result->particle.particleId() == initialParticle.particleId() &&
0243 "Particle id must not change during simulation");
0244
0245 copyOutputs(result.value(), simulatedParticlesInitial,
0246 simulatedParticlesFinal, hits);
0247
0248
0249
0250
0251
0252 renumberTailParticleIds(simulatedParticlesInitial, iinitial);
0253 }
0254 }
0255
0256 assert(
0257 (simulatedParticlesInitial.size() == simulatedParticlesFinal.size()) &&
0258 "Inconsistent final sizes of the simulated particle containers");
0259
0260
0261
0262
0263
0264 return failedParticles;
0265 }
0266
0267 private:
0268
0269 bool selectParticle(const Particle &particle) const {
0270 if (particle.charge() != 0.) {
0271 return selectCharged(particle);
0272 } else {
0273 return selectNeutral(particle);
0274 }
0275 }
0276
0277
0278
0279
0280
0281 template <typename particles_t, typename hits_t>
0282 void copyOutputs(const SimulationResult &result,
0283 particles_t &particlesInitial, particles_t &particlesFinal,
0284 hits_t &hits) const {
0285
0286
0287 particlesFinal.push_back(result.particle);
0288 std::copy(result.hits.begin(), result.hits.end(), std::back_inserter(hits));
0289
0290
0291 std::copy_if(
0292 result.generatedParticles.begin(), result.generatedParticles.end(),
0293 std::back_inserter(particlesInitial),
0294 [this](const Particle &particle) { return selectParticle(particle); });
0295 }
0296
0297
0298
0299
0300
0301
0302
0303
0304
0305
0306
0307
0308
0309
0310
0311 template <typename particles_t>
0312 static void renumberTailParticleIds(particles_t &particles,
0313 std::size_t lastValid) {
0314
0315
0316
0317
0318
0319
0320
0321
0322
0323
0324
0325
0326
0327
0328
0329
0330
0331
0332
0333 for (auto j = lastValid; (j + 1u) < particles.size(); ++j) {
0334 const auto prevId = particles[j].particleId();
0335 auto currId = particles[j + 1u].particleId();
0336
0337
0338 if (prevId.generation() != currId.generation()) {
0339 continue;
0340 }
0341
0342 if (prevId.subParticle() < currId.subParticle()) {
0343 continue;
0344 }
0345
0346 currId.setSubParticle(prevId.subParticle() + 1u);
0347 particles[j + 1u] = particles[j + 1u].withParticleId(currId);
0348 }
0349 }
0350 };
0351
0352 }