EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
InteractorTests.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file InteractorTests.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2020 CERN for the benefit of the Acts project
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 
9 #include <boost/test/unit_test.hpp>
10 
18 
19 #include <limits>
20 #include <random>
21 
22 using namespace ActsFatras;
23 
24 namespace {
25 
27 
28 struct MockPhysicsList {
29  double energyLoss = 0;
30 
31  template <typename generator_t>
32  bool operator()(generator_t &, const Acts::MaterialSlab &, Particle &particle,
33  std::vector<Particle> &generated) const {
34  generated.push_back(particle);
35  particle.correctEnergy(-energyLoss);
36  // break if particle is not alive anymore
37  return !particle;
38  }
39 };
40 
41 struct MockStepperState {
42  using Scalar = double;
44 
46  Scalar time;
47  Vector3 direction;
49 };
50 
51 struct MockStepper {
54 
55  auto position(MockStepperState &state) const { return state.position; }
56  auto time(MockStepperState &state) const { return state.time; }
57  auto direction(MockStepperState &state) const { return state.direction; }
58  auto momentum(MockStepperState &state) const { return state.momentum; }
59  void update(MockStepperState &state, const Vector3 &position,
60  const Vector3 &direction, Scalar momentum, Scalar time) {
61  state.position = position;
62  state.time = time;
63  state.direction = direction;
64  state.momentum = momentum;
65  }
66 };
67 
68 struct MockPropagatorState {
69  struct {
70  bool targetReached = false;
71  Acts::Surface *currentSurface = nullptr;
72  } navigation;
73  MockStepperState stepping;
75 };
76 
77 template <typename SurfaceSelector>
78 struct Fixture {
79  using Generator = std::ranlux48;
80  using Interactor =
81  typename ActsFatras::detail::Interactor<Generator, MockPhysicsList,
82  SurfaceSelector>;
83  using InteractorResult = typename Interactor::result_type;
84 
86  std::shared_ptr<Acts::Surface> surface;
87  Interactor interactor;
88  InteractorResult result;
89  MockPropagatorState state;
90  MockStepper stepper;
91 
92  Fixture(double energyLoss, std::shared_ptr<Acts::Surface> surface_)
93  : generator(42), surface(std::move(surface_)) {
94  // use zero-mass to simplify the math
95  const auto particle =
96  Particle(Barcode().setVertexPrimary(12u).setParticle(3u),
98  .setPosition4(1, 2, 3, 4)
99  .setDirection(1, 0, 0)
100  .setAbsMomentum(100);
101  interactor.generator = &generator;
102  interactor.physics.energyLoss = energyLoss;
103  interactor.particle = particle;
104  state.navigation.currentSurface = surface.get();
105  state.stepping.position = particle.position();
106  state.stepping.time = particle.time();
107  state.stepping.direction = particle.unitDirection();
108  state.stepping.momentum = particle.absMomentum();
109  }
110 };
111 
112 // make a surface without material.
113 std::shared_ptr<Acts::Surface> makeEmptySurface() {
114  auto surface = Acts::Surface::makeShared<Acts::PlaneSurface>(
115  Acts::Vector3D(1, 2, 3), Acts::Vector3D(1, 0, 0));
116  return surface;
117 }
118 
119 // make a surface with material.
120 std::shared_ptr<Acts::Surface> makeMaterialSurface() {
121  auto surface = makeEmptySurface();
122  auto slab = Acts::Test::makePercentSlab();
123  surface->assignSurfaceMaterial(
124  std::make_shared<Acts::HomogeneousSurfaceMaterial>(std::move(slab)));
125  return surface;
126 }
127 
128 } // namespace
129 
130 BOOST_AUTO_TEST_SUITE(FatrasInteractor)
131 
132 BOOST_AUTO_TEST_CASE(HitsOnEmptySurface) {
133  Fixture<EverySurface> f(0.5, makeEmptySurface());
134 
135  // call interactor: surface selection -> one hit, no material -> no secondary
136  f.interactor(f.state, f.stepper, f.result);
137  BOOST_CHECK_EQUAL(f.result.generatedParticles.size(), 0u);
138  BOOST_CHECK_EQUAL(f.result.hits.size(), 1u);
139  BOOST_CHECK_EQUAL(f.result.hits[0].index(), 0u);
140 
141  // call interactor again: one more hit, still no secondary
142  f.interactor(f.state, f.stepper, f.result);
143  BOOST_CHECK_EQUAL(f.result.generatedParticles.size(), 0u);
144  BOOST_CHECK_EQUAL(f.result.hits.size(), 2u);
145  BOOST_CHECK_EQUAL(f.result.hits[0].index(), 0u);
146  BOOST_CHECK_EQUAL(f.result.hits[1].index(), 1u);
147 
148  // particle identity should be the same as the initial input
149  BOOST_CHECK_EQUAL(f.result.particle.particleId(),
150  f.interactor.particle.particleId());
151  BOOST_CHECK_EQUAL(f.result.particle.process(),
152  f.interactor.particle.process());
153  BOOST_CHECK_EQUAL(f.result.particle.pdg(), f.interactor.particle.pdg());
154  BOOST_CHECK_EQUAL(f.result.particle.charge(), f.interactor.particle.charge());
155  BOOST_CHECK_EQUAL(f.result.particle.mass(), f.interactor.particle.mass());
156  // particle energy has not changed since there were no interactions
157  CHECK_CLOSE_REL(f.result.particle.energy(), f.interactor.particle.energy(),
158  eps);
159 }
160 
161 BOOST_AUTO_TEST_CASE(HitsOnMaterialSurface) {
162  Fixture<EverySurface> f(0.5, makeMaterialSurface());
163 
164  // call interactor: surface selection -> one hit, material -> one secondary
165  f.interactor(f.state, f.stepper, f.result);
166  BOOST_CHECK_EQUAL(f.result.generatedParticles.size(), 1u);
167  BOOST_CHECK_EQUAL(f.result.hits.size(), 1u);
168  BOOST_CHECK_EQUAL(f.result.hits[0].index(), 0u);
169 
170  // call interactor again: one more hit, one more secondary
171  f.interactor(f.state, f.stepper, f.result);
172  BOOST_CHECK_EQUAL(f.result.generatedParticles.size(), 2u);
173  BOOST_CHECK_EQUAL(f.result.hits.size(), 2u);
174  BOOST_CHECK_EQUAL(f.result.hits[0].index(), 0u);
175  BOOST_CHECK_EQUAL(f.result.hits[1].index(), 1u);
176 
177  // particle identity should be the same as the initial input
178  BOOST_CHECK_EQUAL(f.result.particle.particleId(),
179  f.interactor.particle.particleId());
180  BOOST_CHECK_EQUAL(f.result.particle.process(),
181  f.interactor.particle.process());
182  BOOST_CHECK_EQUAL(f.result.particle.pdg(), f.interactor.particle.pdg());
183  BOOST_CHECK_EQUAL(f.result.particle.charge(), f.interactor.particle.charge());
184  BOOST_CHECK_EQUAL(f.result.particle.mass(), f.interactor.particle.mass());
185  // particle energy has changed due to interactions
186  CHECK_CLOSE_REL((f.result.particle.energy() + 1),
187  f.interactor.particle.energy(), eps);
188 }
189 
190 BOOST_AUTO_TEST_CASE(NoHitsEmptySurface) {
191  Fixture<NoSurface> f(0.5, makeEmptySurface());
192 
193  // call interactor: no surface sel. -> no hit, no material -> no secondary
194  f.interactor(f.state, f.stepper, f.result);
195  BOOST_CHECK_EQUAL(f.result.generatedParticles.size(), 0u);
196  BOOST_CHECK_EQUAL(f.result.hits.size(), 0u);
197 
198  // call interactor again: no hit, still no secondary
199  f.interactor(f.state, f.stepper, f.result);
200  BOOST_CHECK_EQUAL(f.result.generatedParticles.size(), 0u);
201  BOOST_CHECK_EQUAL(f.result.hits.size(), 0u);
202 
203  // particle identity should be the same as the initial input
204  BOOST_CHECK_EQUAL(f.result.particle.particleId(),
205  f.interactor.particle.particleId());
206  BOOST_CHECK_EQUAL(f.result.particle.process(),
207  f.interactor.particle.process());
208  BOOST_CHECK_EQUAL(f.result.particle.pdg(), f.interactor.particle.pdg());
209  BOOST_CHECK_EQUAL(f.result.particle.charge(), f.interactor.particle.charge());
210  BOOST_CHECK_EQUAL(f.result.particle.mass(), f.interactor.particle.mass());
211  // particle energy has not changed since there were no interactions
212  CHECK_CLOSE_REL(f.result.particle.energy(), f.interactor.particle.energy(),
213  eps);
214 }
215 
216 BOOST_AUTO_TEST_CASE(NoHitsMaterialSurface) {
217  Fixture<NoSurface> f(0.5, makeMaterialSurface());
218 
219  // call interactor: no surface sel. -> no hit, material -> one secondary
220  f.interactor(f.state, f.stepper, f.result);
221  BOOST_CHECK_EQUAL(f.result.generatedParticles.size(), 1u);
222  BOOST_CHECK_EQUAL(f.result.hits.size(), 0u);
223 
224  // call interactor again: still no hit, one more secondary
225  f.interactor(f.state, f.stepper, f.result);
226  BOOST_CHECK_EQUAL(f.result.generatedParticles.size(), 2u);
227  BOOST_CHECK_EQUAL(f.result.hits.size(), 0u);
228 
229  // particle identity should be the same as the initial input
230  BOOST_CHECK_EQUAL(f.result.particle.particleId(),
231  f.interactor.particle.particleId());
232  BOOST_CHECK_EQUAL(f.result.particle.process(),
233  f.interactor.particle.process());
234  BOOST_CHECK_EQUAL(f.result.particle.pdg(), f.interactor.particle.pdg());
235  BOOST_CHECK_EQUAL(f.result.particle.charge(), f.interactor.particle.charge());
236  BOOST_CHECK_EQUAL(f.result.particle.mass(), f.interactor.particle.mass());
237  // particle energy has changed due to interactions
238  CHECK_CLOSE_REL((f.result.particle.energy() + 1),
239  f.interactor.particle.energy(), eps);
240 }
241 
242 BOOST_AUTO_TEST_SUITE_END()