Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:13:05

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
0008 
0009 #include <boost/test/unit_test.hpp>
0010 
0011 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/Definitions/PdgParticle.hpp"
0013 #include "Acts/Definitions/Units.hpp"
0014 #include "Acts/Geometry/GeometryContext.hpp"
0015 #include "Acts/Geometry/TrackingVolume.hpp"
0016 #include "Acts/Material/HomogeneousSurfaceMaterial.hpp"
0017 #include "Acts/Material/MaterialSlab.hpp"
0018 #include "Acts/Propagator/ConstrainedStep.hpp"
0019 #include "Acts/Surfaces/CurvilinearSurface.hpp"
0020 #include "Acts/Surfaces/PlaneSurface.hpp"
0021 #include "Acts/Surfaces/Surface.hpp"
0022 #include "Acts/Tests/CommonHelpers/FloatComparisons.hpp"
0023 #include "Acts/Tests/CommonHelpers/PredefinedMaterials.hpp"
0024 #include "Acts/Utilities/Logger.hpp"
0025 #include "ActsFatras/EventData/Barcode.hpp"
0026 #include "ActsFatras/EventData/Particle.hpp"
0027 #include "ActsFatras/EventData/ProcessType.hpp"
0028 #include "ActsFatras/Kernel/detail/SimulationActor.hpp"
0029 #include "ActsFatras/Selectors/SurfaceSelectors.hpp"
0030 
0031 #include <array>
0032 #include <cmath>
0033 #include <cstddef>
0034 #include <cstdint>
0035 #include <limits>
0036 #include <memory>
0037 #include <random>
0038 #include <utility>
0039 #include <vector>
0040 
0041 using namespace Acts::UnitLiterals;
0042 using namespace ActsFatras;
0043 
0044 namespace {
0045 
0046 constexpr auto tol = 4 * std::numeric_limits<double>::epsilon();
0047 constexpr auto inf = std::numeric_limits<double>::infinity();
0048 
0049 struct MockDecay {
0050   double properTimeLimit = inf;
0051 
0052   template <typename generator_t>
0053   constexpr double generateProperTimeLimit(generator_t & /*generator*/,
0054                                            const Particle &particle) const {
0055     return particle.properTime() + properTimeLimit;
0056   }
0057   template <typename generator_t>
0058   constexpr std::array<Particle, 0> run(generator_t & /*generator*/,
0059                                         const Particle & /*particle*/) const {
0060     return {};
0061   }
0062 };
0063 
0064 struct MockInteractionList {
0065   struct Selection {
0066     double x0Limit = std::numeric_limits<double>::infinity();
0067     double l0Limit = std::numeric_limits<double>::infinity();
0068     std::size_t x0Process = std::numeric_limits<std::size_t>::max();
0069     std::size_t l0Process = std::numeric_limits<std::size_t>::max();
0070   };
0071 
0072   double energyLoss = 0;
0073 
0074   template <typename generator_t>
0075   bool runContinuous(generator_t & /*generator*/,
0076                      const Acts::MaterialSlab & /*slab*/, Particle &particle,
0077                      std::vector<Particle> &generated) const {
0078     generated.push_back(particle);
0079     particle.correctEnergy(-energyLoss);
0080     // break if particle is not alive anymore
0081     return !particle.isAlive();
0082   }
0083 
0084   template <typename generator_t>
0085   Selection armPointLike(generator_t & /*generator*/,
0086                          const Particle & /*particle*/) const {
0087     return {};
0088   }
0089 
0090   template <typename generator_t>
0091   bool runPointLike(generator_t & /*generator*/, std::size_t /*processIndex*/,
0092                     Particle & /*particle*/,
0093                     std::vector<Particle> & /*generated*/) const {
0094     return false;
0095   }
0096 };
0097 
0098 struct MockStepperState {
0099   Acts::Vector3 pos = Acts::Vector3::Zero();
0100   double time = 0;
0101   Acts::Vector3 dir = Acts::Vector3::Zero();
0102   double p = 0;
0103 };
0104 
0105 struct MockStepper {
0106   using State = MockStepperState;
0107 
0108   auto position(const State &state) const { return state.pos; }
0109   auto time(const State &state) const { return state.time; }
0110   auto direction(const State &state) const { return state.dir; }
0111   auto absoluteMomentum(const State &state) const { return state.p; }
0112   void update(State &state, const Acts::Vector3 &pos, const Acts::Vector3 &dir,
0113               double qop, double time) {
0114     state.pos = pos;
0115     state.time = time;
0116     state.dir = dir;
0117     state.p = 1 / qop;
0118   }
0119   void updateStepSize(State & /*state*/, double /*stepSize*/,
0120                       Acts::ConstrainedStep::Type /*stype*/) const {}
0121   void releaseStepSize(State & /*state*/,
0122                        Acts::ConstrainedStep::Type /*stype*/) const {}
0123 };
0124 
0125 struct MockNavigatorState {
0126   Acts::Surface *startSurface = nullptr;
0127   Acts::Surface *currentSurface = nullptr;
0128 };
0129 
0130 struct MockNavigator {
0131   const Acts::Surface *startSurface(const MockNavigatorState &state) const {
0132     return state.startSurface;
0133   }
0134 
0135   const Acts::Surface *currentSurface(const MockNavigatorState &state) const {
0136     return state.currentSurface;
0137   }
0138 
0139   const Acts::TrackingVolume *currentVolume(
0140       const MockNavigatorState & /*state*/) const {
0141     return nullptr;
0142   }
0143 
0144   bool endOfWorldReached(const MockNavigatorState & /*state*/) const {
0145     return false;
0146   }
0147 };
0148 
0149 struct MockPropagatorState {
0150   MockNavigatorState navigation;
0151   MockStepperState stepping;
0152   Acts::GeometryContext geoContext;
0153   Acts::PropagatorStage stage = Acts::PropagatorStage::invalid;
0154 
0155   struct {
0156     std::vector<std::uint32_t> constrainToVolumeIds;
0157   } options;
0158 };
0159 
0160 template <typename SurfaceSelector>
0161 struct Fixture {
0162   using Generator = std::ranlux48;
0163   using Actor = typename ActsFatras::detail::SimulationActor<
0164       Generator, MockDecay, MockInteractionList, SurfaceSelector>;
0165   using Result = typename Actor::result_type;
0166 
0167   // reference information for initial particle
0168   Barcode pid = Barcode().setVertexPrimary(12u).setParticle(3u);
0169   ProcessType proc = ProcessType::eUndefined;
0170   Acts::PdgParticle pdg = Acts::PdgParticle::eProton;
0171   double q = 1_e;
0172   double m = 1_GeV;
0173   double p = 1_GeV;
0174   double e;
0175   Generator generator;
0176   std::shared_ptr<Acts::Surface> surface;
0177   Actor actor;
0178   Result result;
0179   MockPropagatorState state;
0180   MockStepper stepper;
0181   MockNavigator navigator;
0182 
0183   Fixture(double energyLoss, std::shared_ptr<Acts::Surface> surface_)
0184       : e(std::hypot(m, p)), generator(42), surface(std::move(surface_)) {
0185     const auto particle = Particle(pid, pdg, q, m)
0186                               .setProcess(proc)
0187                               .setPosition4(1_mm, 2_mm, 3_mm, 4_ns)
0188                               .setDirection(1, 0, 0)
0189                               .setAbsoluteMomentum(p);
0190     actor.generator = &generator;
0191     actor.interactions.energyLoss = energyLoss;
0192     actor.initialParticle = particle;
0193     state.stage = Acts::PropagatorStage::postStep;
0194     state.navigation.currentSurface = surface.get();
0195     state.stepping.pos = particle.position();
0196     state.stepping.time = particle.time();
0197     state.stepping.dir = particle.direction();
0198     state.stepping.p = particle.absoluteMomentum();
0199   }
0200 };
0201 
0202 // make a surface without material.
0203 std::shared_ptr<Acts::Surface> makeEmptySurface() {
0204   auto surface =
0205       Acts::CurvilinearSurface(Acts::Vector3(1, 2, 3), Acts::Vector3(1, 0, 0))
0206           .planeSurface();
0207   return surface;
0208 }
0209 
0210 // make a surface with 1% X0/L0 material.
0211 std::shared_ptr<Acts::Surface> makeMaterialSurface() {
0212   auto surface = makeEmptySurface();
0213   auto slab = Acts::Test::makeUnitSlab();
0214   surface->assignSurfaceMaterial(
0215       std::make_shared<Acts::HomogeneousSurfaceMaterial>(slab));
0216   return surface;
0217 }
0218 
0219 }  // namespace
0220 
0221 BOOST_AUTO_TEST_SUITE(FatrasSimulationActor)
0222 
0223 BOOST_AUTO_TEST_CASE(HitsOnEmptySurface) {
0224   Fixture<EverySurface> f(125_MeV, makeEmptySurface());
0225 
0226   // input reference check
0227   BOOST_CHECK_EQUAL(f.actor.initialParticle.particleId(), f.pid);
0228   BOOST_CHECK_EQUAL(f.actor.initialParticle.process(), f.proc);
0229   BOOST_CHECK_EQUAL(f.actor.initialParticle.pdg(), f.pdg);
0230   BOOST_CHECK_EQUAL(f.actor.initialParticle.mass(), f.m);
0231   BOOST_CHECK_EQUAL(f.actor.initialParticle.absoluteMomentum(), f.p);
0232   BOOST_CHECK_EQUAL(f.actor.initialParticle.energy(), f.e);
0233 
0234   // call.actor: pre propagation
0235   f.state.stage = Acts::PropagatorStage::prePropagation;
0236   f.actor.act(f.state, f.stepper, f.navigator, f.result,
0237               Acts::getDummyLogger());
0238 
0239   // call.actor: surface selection -> one hit, no material -> no secondary
0240   f.state.stage = Acts::PropagatorStage::postStep;
0241   f.actor.act(f.state, f.stepper, f.navigator, f.result,
0242               Acts::getDummyLogger());
0243   BOOST_CHECK(f.result.isAlive);
0244   CHECK_CLOSE_REL(f.result.particle.energy(), f.e, tol);
0245   BOOST_CHECK_EQUAL(f.result.generatedParticles.size(), 0u);
0246   BOOST_CHECK_EQUAL(f.result.hits.size(), 1u);
0247   BOOST_CHECK_EQUAL(f.result.hits[0].index(), 0u);
0248   // proper time must be non-NaN, but is zero since no time has passed
0249   BOOST_CHECK_EQUAL(f.result.particle.properTime(), 0);
0250   // empty surfaces adds no material
0251   BOOST_CHECK_EQUAL(f.result.particle.pathInX0(), 0);
0252   BOOST_CHECK_EQUAL(f.result.particle.pathInL0(), 0);
0253   // no processes are configured, so none can be selected
0254   BOOST_CHECK_EQUAL(f.result.x0Limit, inf);
0255   BOOST_CHECK_EQUAL(f.result.x0Process,
0256                     std::numeric_limits<std::size_t>::max());
0257   BOOST_CHECK_EQUAL(f.result.l0Limit, inf);
0258   BOOST_CHECK_EQUAL(f.result.l0Process,
0259                     std::numeric_limits<std::size_t>::max());
0260   // check consistency between particle and stepper state
0261   BOOST_CHECK_EQUAL(f.state.stepping.pos, f.result.particle.position());
0262   BOOST_CHECK_EQUAL(f.state.stepping.time, f.result.particle.time());
0263   BOOST_CHECK_EQUAL(f.state.stepping.dir, f.result.particle.direction());
0264   BOOST_CHECK_EQUAL(f.state.stepping.p, f.result.particle.absoluteMomentum());
0265 
0266   // call.actor again: one more hit, still no secondary
0267   f.state.stage = Acts::PropagatorStage::postStep;
0268   f.actor.act(f.state, f.stepper, f.navigator, f.result,
0269               Acts::getDummyLogger());
0270   BOOST_CHECK(f.result.isAlive);
0271   CHECK_CLOSE_REL(f.result.particle.energy(), f.e, tol);
0272   BOOST_CHECK_EQUAL(f.result.generatedParticles.size(), 0u);
0273   BOOST_CHECK_EQUAL(f.result.hits.size(), 2u);
0274   BOOST_CHECK_EQUAL(f.result.hits[0].index(), 0u);
0275   BOOST_CHECK_EQUAL(f.result.hits[1].index(), 1u);
0276   // proper time must be non-NaN, but is zero since no time
0277   // has passed
0278   BOOST_CHECK_EQUAL(f.result.particle.properTime(), 0);
0279   // empty surfaces adds no material
0280   BOOST_CHECK_EQUAL(f.result.particle.pathInX0(), 0);
0281   BOOST_CHECK_EQUAL(f.result.particle.pathInL0(), 0);
0282   // no processes are configured, so none can be selected
0283   BOOST_CHECK_EQUAL(f.result.x0Limit, inf);
0284   BOOST_CHECK_EQUAL(f.result.x0Process,
0285                     std::numeric_limits<std::size_t>::max());
0286   BOOST_CHECK_EQUAL(f.result.l0Limit, inf);
0287   BOOST_CHECK_EQUAL(f.result.l0Process,
0288                     std::numeric_limits<std::size_t>::max());
0289   // check consistency between particle and stepper state
0290   BOOST_CHECK_EQUAL(f.state.stepping.pos, f.result.particle.position());
0291   BOOST_CHECK_EQUAL(f.state.stepping.time, f.result.particle.time());
0292   BOOST_CHECK_EQUAL(f.state.stepping.dir, f.result.particle.direction());
0293   BOOST_CHECK_EQUAL(f.state.stepping.p, f.result.particle.absoluteMomentum());
0294 
0295   // particle identity should be the same as the initial input
0296   BOOST_CHECK_EQUAL(f.result.particle.particleId(), f.pid);
0297   BOOST_CHECK_EQUAL(f.result.particle.process(), f.proc);
0298   BOOST_CHECK_EQUAL(f.result.particle.pdg(), f.pdg);
0299   BOOST_CHECK_EQUAL(f.result.particle.charge(), f.q);
0300   BOOST_CHECK_EQUAL(f.result.particle.mass(), f.m);
0301 }
0302 
0303 BOOST_AUTO_TEST_CASE(HitsOnMaterialSurface) {
0304   Fixture<EverySurface> f(125_MeV, makeMaterialSurface());
0305 
0306   // input reference check
0307   BOOST_CHECK_EQUAL(f.actor.initialParticle.particleId(), f.pid);
0308   BOOST_CHECK_EQUAL(f.actor.initialParticle.process(), f.proc);
0309   BOOST_CHECK_EQUAL(f.actor.initialParticle.pdg(), f.pdg);
0310   BOOST_CHECK_EQUAL(f.actor.initialParticle.mass(), f.m);
0311   BOOST_CHECK_EQUAL(f.actor.initialParticle.absoluteMomentum(), f.p);
0312   BOOST_CHECK_EQUAL(f.actor.initialParticle.energy(), f.e);
0313 
0314   // call.actor: pre propagation
0315   f.state.stage = Acts::PropagatorStage::prePropagation;
0316   f.actor.act(f.state, f.stepper, f.navigator, f.result,
0317               Acts::getDummyLogger());
0318 
0319   // call.actor: surface selection -> one hit, material -> one secondary
0320   f.state.stage = Acts::PropagatorStage::postStep;
0321   f.actor.act(f.state, f.stepper, f.navigator, f.result,
0322               Acts::getDummyLogger());
0323   BOOST_CHECK(f.result.isAlive);
0324   CHECK_CLOSE_REL(f.result.particle.energy(), f.e - 125_MeV, tol);
0325   BOOST_CHECK_EQUAL(f.result.generatedParticles.size(), 1u);
0326   BOOST_CHECK_EQUAL(f.result.hits.size(), 1u);
0327   BOOST_CHECK_EQUAL(f.result.hits[0].index(), 0u);
0328   // proper time must be non-NaN, but is zero since no time
0329   // has passed
0330   BOOST_CHECK_EQUAL(f.result.particle.properTime(), 0);
0331   // test material is a unit slab
0332   BOOST_CHECK_EQUAL(f.result.particle.pathInX0(), 1);
0333   BOOST_CHECK_EQUAL(f.result.particle.pathInL0(), 1);
0334   // no processes are configured, so none can be selected
0335   BOOST_CHECK_EQUAL(f.result.x0Limit, inf);
0336   BOOST_CHECK_EQUAL(f.result.x0Process,
0337                     std::numeric_limits<std::size_t>::max());
0338   BOOST_CHECK_EQUAL(f.result.l0Limit, inf);
0339   BOOST_CHECK_EQUAL(f.result.l0Process,
0340                     std::numeric_limits<std::size_t>::max());
0341   // check consistency between particle and stepper state
0342   BOOST_CHECK_EQUAL(f.state.stepping.pos, f.result.particle.position());
0343   BOOST_CHECK_EQUAL(f.state.stepping.time, f.result.particle.time());
0344   BOOST_CHECK_EQUAL(f.state.stepping.dir, f.result.particle.direction());
0345   CHECK_CLOSE_REL(f.state.stepping.p, f.result.particle.absoluteMomentum(),
0346                   tol);
0347 
0348   // call.actor again: one more hit, one more secondary
0349   f.state.stage = Acts::PropagatorStage::postStep;
0350   f.actor.act(f.state, f.stepper, f.navigator, f.result,
0351               Acts::getDummyLogger());
0352   BOOST_CHECK(f.result.isAlive);
0353   CHECK_CLOSE_REL(f.result.particle.energy(), f.e - 250_MeV, tol);
0354   BOOST_CHECK_EQUAL(f.result.generatedParticles.size(), 2u);
0355   BOOST_CHECK_EQUAL(f.result.hits.size(), 2u);
0356   BOOST_CHECK_EQUAL(f.result.hits[0].index(), 0u);
0357   BOOST_CHECK_EQUAL(f.result.hits[1].index(), 1u);
0358   // proper time must be non-NaN, but is zero since no time
0359   // has passed
0360   BOOST_CHECK_EQUAL(f.result.particle.properTime(), 0);
0361   // test material is a unit slab that was passed twice
0362   BOOST_CHECK_EQUAL(f.result.particle.pathInX0(), 2);
0363   BOOST_CHECK_EQUAL(f.result.particle.pathInL0(), 2);
0364   // no processes are configured, so none can be selected
0365   BOOST_CHECK_EQUAL(f.result.x0Limit, inf);
0366   BOOST_CHECK_EQUAL(f.result.x0Process,
0367                     std::numeric_limits<std::size_t>::max());
0368   BOOST_CHECK_EQUAL(f.result.l0Limit, inf);
0369   BOOST_CHECK_EQUAL(f.result.l0Process,
0370                     std::numeric_limits<std::size_t>::max());
0371   // check consistency between particle and stepper state
0372   BOOST_CHECK_EQUAL(f.state.stepping.pos, f.result.particle.position());
0373   BOOST_CHECK_EQUAL(f.state.stepping.time, f.result.particle.time());
0374   BOOST_CHECK_EQUAL(f.state.stepping.dir, f.result.particle.direction());
0375   BOOST_CHECK_EQUAL(f.state.stepping.p, f.result.particle.absoluteMomentum());
0376 
0377   // particle identity should be the same as the initial input
0378   BOOST_CHECK_EQUAL(f.result.particle.particleId(), f.pid);
0379   BOOST_CHECK_EQUAL(f.result.particle.process(), f.proc);
0380   BOOST_CHECK_EQUAL(f.result.particle.pdg(), f.pdg);
0381   BOOST_CHECK_EQUAL(f.result.particle.charge(), f.q);
0382   BOOST_CHECK_EQUAL(f.result.particle.mass(), f.m);
0383 }
0384 
0385 BOOST_AUTO_TEST_CASE(NoHitsEmptySurface) {
0386   Fixture<NoSurface> f(125_MeV, makeEmptySurface());
0387 
0388   // input reference check
0389   BOOST_CHECK_EQUAL(f.actor.initialParticle.particleId(), f.pid);
0390   BOOST_CHECK_EQUAL(f.actor.initialParticle.process(), f.proc);
0391   BOOST_CHECK_EQUAL(f.actor.initialParticle.pdg(), f.pdg);
0392   BOOST_CHECK_EQUAL(f.actor.initialParticle.mass(), f.m);
0393   BOOST_CHECK_EQUAL(f.actor.initialParticle.absoluteMomentum(), f.p);
0394   BOOST_CHECK_EQUAL(f.actor.initialParticle.energy(), f.e);
0395 
0396   // call.actor: pre propagation
0397   f.state.stage = Acts::PropagatorStage::prePropagation;
0398   f.actor.act(f.state, f.stepper, f.navigator, f.result,
0399               Acts::getDummyLogger());
0400 
0401   // call.actor: no surface sel. -> no hit, no material -> no secondary
0402   f.state.stage = Acts::PropagatorStage::postStep;
0403   f.actor.act(f.state, f.stepper, f.navigator, f.result,
0404               Acts::getDummyLogger());
0405   BOOST_CHECK(f.result.isAlive);
0406   CHECK_CLOSE_REL(f.result.particle.energy(), f.e, tol);
0407   BOOST_CHECK_EQUAL(f.result.generatedParticles.size(), 0u);
0408   BOOST_CHECK_EQUAL(f.result.hits.size(), 0u);
0409   // proper time must be non-NaN, but is zero since no time
0410   // has passed
0411   BOOST_CHECK_EQUAL(f.result.particle.properTime(), 0);
0412   // empty surfaces adds no material
0413   BOOST_CHECK_EQUAL(f.result.particle.pathInX0(), 0);
0414   BOOST_CHECK_EQUAL(f.result.particle.pathInL0(), 0);
0415   // no processes are configured, so none can be selected
0416   BOOST_CHECK_EQUAL(f.result.x0Limit, inf);
0417   BOOST_CHECK_EQUAL(f.result.x0Process,
0418                     std::numeric_limits<std::size_t>::max());
0419   BOOST_CHECK_EQUAL(f.result.l0Limit, inf);
0420   BOOST_CHECK_EQUAL(f.result.l0Process,
0421                     std::numeric_limits<std::size_t>::max());
0422   // check consistency between particle and stepper state
0423   BOOST_CHECK_EQUAL(f.state.stepping.pos, f.result.particle.position());
0424   BOOST_CHECK_EQUAL(f.state.stepping.time, f.result.particle.time());
0425   BOOST_CHECK_EQUAL(f.state.stepping.dir, f.result.particle.direction());
0426   BOOST_CHECK_EQUAL(f.state.stepping.p, f.result.particle.absoluteMomentum());
0427 
0428   // call.actor again: no hit, still no secondary
0429   f.state.stage = Acts::PropagatorStage::postStep;
0430   f.actor.act(f.state, f.stepper, f.navigator, f.result,
0431               Acts::getDummyLogger());
0432   BOOST_CHECK(f.result.isAlive);
0433   CHECK_CLOSE_REL(f.result.particle.energy(), f.e, tol);
0434   BOOST_CHECK_EQUAL(f.result.generatedParticles.size(), 0u);
0435   BOOST_CHECK_EQUAL(f.result.hits.size(), 0u);
0436   // proper time must be non-NaN, but is zero since no time
0437   // has passed
0438   BOOST_CHECK_EQUAL(f.result.particle.properTime(), 0);
0439   // empty surfaces adds no material
0440   BOOST_CHECK_EQUAL(f.result.particle.pathInX0(), 0);
0441   BOOST_CHECK_EQUAL(f.result.particle.pathInL0(), 0);
0442   // no processes are configured, so none can be selected
0443   BOOST_CHECK_EQUAL(f.result.x0Limit, inf);
0444   BOOST_CHECK_EQUAL(f.result.x0Process,
0445                     std::numeric_limits<std::size_t>::max());
0446   BOOST_CHECK_EQUAL(f.result.l0Limit, inf);
0447   BOOST_CHECK_EQUAL(f.result.l0Process,
0448                     std::numeric_limits<std::size_t>::max());
0449   // check consistency between particle and stepper state
0450   BOOST_CHECK_EQUAL(f.state.stepping.pos, f.result.particle.position());
0451   BOOST_CHECK_EQUAL(f.state.stepping.time, f.result.particle.time());
0452   BOOST_CHECK_EQUAL(f.state.stepping.dir, f.result.particle.direction());
0453   BOOST_CHECK_EQUAL(f.state.stepping.p, f.result.particle.absoluteMomentum());
0454 
0455   // particle identity should be the same as the initial input
0456   BOOST_CHECK_EQUAL(f.result.particle.particleId(), f.pid);
0457   BOOST_CHECK_EQUAL(f.result.particle.process(), f.proc);
0458   BOOST_CHECK_EQUAL(f.result.particle.pdg(), f.pdg);
0459   BOOST_CHECK_EQUAL(f.result.particle.charge(), f.q);
0460   BOOST_CHECK_EQUAL(f.result.particle.mass(), f.m);
0461 }
0462 
0463 BOOST_AUTO_TEST_CASE(NoHitsMaterialSurface) {
0464   Fixture<NoSurface> f(125_MeV, makeMaterialSurface());
0465 
0466   // call.actor: pre propagation
0467   f.state.stage = Acts::PropagatorStage::prePropagation;
0468   f.actor.act(f.state, f.stepper, f.navigator, f.result,
0469               Acts::getDummyLogger());
0470 
0471   // call.actor: no surface sel. -> no hit, material -> one secondary
0472   f.state.stage = Acts::PropagatorStage::postStep;
0473   f.actor.act(f.state, f.stepper, f.navigator, f.result,
0474               Acts::getDummyLogger());
0475   BOOST_CHECK(f.result.isAlive);
0476   CHECK_CLOSE_REL(f.result.particle.energy(), f.e - 125_MeV, tol);
0477   BOOST_CHECK_EQUAL(f.result.generatedParticles.size(), 1u);
0478   BOOST_CHECK_EQUAL(f.result.hits.size(), 0u);
0479   // proper time must be non-NaN, but is zero since no time
0480   // has passed
0481   BOOST_CHECK_EQUAL(f.result.particle.properTime(), 0);
0482   // test material is a unit slab
0483   BOOST_CHECK_EQUAL(f.result.particle.pathInX0(), 1);
0484   BOOST_CHECK_EQUAL(f.result.particle.pathInL0(), 1);
0485   // no processes are configured, so none can be selected
0486   BOOST_CHECK_EQUAL(f.result.x0Limit, inf);
0487   BOOST_CHECK_EQUAL(f.result.x0Process,
0488                     std::numeric_limits<std::size_t>::max());
0489   BOOST_CHECK_EQUAL(f.result.l0Limit, inf);
0490   BOOST_CHECK_EQUAL(f.result.l0Process,
0491                     std::numeric_limits<std::size_t>::max());
0492   // check consistency between particle and stepper state
0493   BOOST_CHECK_EQUAL(f.state.stepping.pos, f.result.particle.position());
0494   BOOST_CHECK_EQUAL(f.state.stepping.time, f.result.particle.time());
0495   BOOST_CHECK_EQUAL(f.state.stepping.dir, f.result.particle.direction());
0496   CHECK_CLOSE_REL(f.state.stepping.p, f.result.particle.absoluteMomentum(),
0497                   tol);
0498 
0499   // call.actor again: still no hit, one more secondary
0500   f.state.stage = Acts::PropagatorStage::postStep;
0501   f.actor.act(f.state, f.stepper, f.navigator, f.result,
0502               Acts::getDummyLogger());
0503   BOOST_CHECK(f.result.isAlive);
0504   CHECK_CLOSE_REL(f.result.particle.energy(), f.e - 250_MeV, tol);
0505   BOOST_CHECK_EQUAL(f.result.generatedParticles.size(), 2u);
0506   BOOST_CHECK_EQUAL(f.result.hits.size(), 0u);
0507   // proper time must be non-NaN, but is zero since no time
0508   // has passed
0509   BOOST_CHECK_EQUAL(f.result.particle.properTime(), 0);
0510   // test material is a unit slab that was passed twice
0511   BOOST_CHECK_EQUAL(f.result.particle.pathInX0(), 2);
0512   BOOST_CHECK_EQUAL(f.result.particle.pathInL0(), 2);
0513   // no processes are configured, so none can be selected
0514   BOOST_CHECK_EQUAL(f.result.x0Limit, inf);
0515   BOOST_CHECK_EQUAL(f.result.x0Process,
0516                     std::numeric_limits<std::size_t>::max());
0517   BOOST_CHECK_EQUAL(f.result.l0Limit, inf);
0518   BOOST_CHECK_EQUAL(f.result.l0Process,
0519                     std::numeric_limits<std::size_t>::max());
0520   // check consistency between particle and stepper state
0521   BOOST_CHECK_EQUAL(f.state.stepping.pos, f.result.particle.position());
0522   BOOST_CHECK_EQUAL(f.state.stepping.time, f.result.particle.time());
0523   BOOST_CHECK_EQUAL(f.state.stepping.dir, f.result.particle.direction());
0524   BOOST_CHECK_EQUAL(f.state.stepping.p, f.result.particle.absoluteMomentum());
0525 
0526   // particle identity should be the same as the initial input
0527   BOOST_CHECK_EQUAL(f.result.particle.particleId(), f.pid);
0528   BOOST_CHECK_EQUAL(f.result.particle.process(), f.proc);
0529   BOOST_CHECK_EQUAL(f.result.particle.pdg(), f.pdg);
0530   BOOST_CHECK_EQUAL(f.result.particle.charge(), f.q);
0531   BOOST_CHECK_EQUAL(f.result.particle.mass(), f.m);
0532 }
0533 
0534 BOOST_AUTO_TEST_CASE(Decay) {
0535   // configure no energy loss for the decay tests
0536   Fixture<NoSurface> f(0_GeV, makeEmptySurface());
0537 
0538   // inverse Lorentz factor for proper time dilation: 1/gamma = m/E
0539   const auto gammaInv = f.m / f.e;
0540 
0541   // call.actor: pre propagation
0542   f.state.stage = Acts::PropagatorStage::prePropagation;
0543   f.actor.act(f.state, f.stepper, f.navigator, f.result,
0544               Acts::getDummyLogger());
0545 
0546   // first step w/ defaults leaves particle alive
0547   f.state.stage = Acts::PropagatorStage::postStep;
0548   f.actor.act(f.state, f.stepper, f.navigator, f.result,
0549               Acts::getDummyLogger());
0550   BOOST_CHECK(f.result.isAlive);
0551   BOOST_CHECK_EQUAL(f.result.particle.particleId(), f.pid);
0552   BOOST_CHECK_EQUAL(f.result.particle.process(), f.proc);
0553   BOOST_CHECK_EQUAL(f.result.particle.pdg(), f.pdg);
0554   BOOST_CHECK_EQUAL(f.result.particle.charge(), f.q);
0555   BOOST_CHECK_EQUAL(f.result.particle.mass(), f.m);
0556   CHECK_CLOSE_REL(f.result.particle.energy(), f.e, tol);
0557   BOOST_CHECK_EQUAL(f.result.particle.properTime(), 0_ns);
0558 
0559   // second step w/ defaults increases proper time
0560   f.state.stage = Acts::PropagatorStage::postStep;
0561   f.state.stepping.time += 1_ns;
0562   f.actor.act(f.state, f.stepper, f.navigator, f.result,
0563               Acts::getDummyLogger());
0564   BOOST_CHECK(f.result.isAlive);
0565   BOOST_CHECK_EQUAL(f.result.particle.particleId(), f.pid);
0566   BOOST_CHECK_EQUAL(f.result.particle.process(), f.proc);
0567   BOOST_CHECK_EQUAL(f.result.particle.pdg(), f.pdg);
0568   BOOST_CHECK_EQUAL(f.result.particle.charge(), f.q);
0569   BOOST_CHECK_EQUAL(f.result.particle.mass(), f.m);
0570   CHECK_CLOSE_REL(f.result.particle.energy(), f.e, tol);
0571   CHECK_CLOSE_REL(f.result.particle.properTime(), gammaInv * 1_ns, tol);
0572 
0573   // third step w/ proper time limit decays the particle
0574   f.state.stage = Acts::PropagatorStage::postStep;
0575   f.state.stepping.time += 1_ns;
0576   f.result.properTimeLimit = f.result.particle.properTime() + gammaInv * 0.5_ns;
0577   f.actor.act(f.state, f.stepper, f.navigator, f.result,
0578               Acts::getDummyLogger());
0579   BOOST_CHECK(!f.result.isAlive);
0580   BOOST_CHECK_EQUAL(f.result.particle.particleId(), f.pid);
0581   BOOST_CHECK_EQUAL(f.result.particle.process(), f.proc);
0582   BOOST_CHECK_EQUAL(f.result.particle.pdg(), f.pdg);
0583   BOOST_CHECK_EQUAL(f.result.particle.charge(), f.q);
0584   BOOST_CHECK_EQUAL(f.result.particle.mass(), f.m);
0585   CHECK_CLOSE_REL(f.result.particle.energy(), f.e, tol);
0586   CHECK_CLOSE_REL(f.result.particle.properTime(), gammaInv * 2_ns, tol);
0587 }
0588 
0589 BOOST_AUTO_TEST_SUITE_END()