EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Interactor.hpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file Interactor.hpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2018-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 #pragma once
10 
16 
17 #include <cassert>
18 
19 namespace ActsFatras {
20 namespace detail {
21 
33 template <typename generator_t, typename physics_list_t,
34  typename hit_surface_selector_t>
35 struct Interactor {
37 
40  // This references the Interactor to automatically access its result type.
42 
43  template <typename propagator_state_t, typename stepper_t>
44  constexpr bool operator()(propagator_state_t &, const stepper_t &,
45  const result_type &result) const {
46  return not result.isAlive;
47  }
48  };
49 
51  generator_t *generator = nullptr;
53  physics_list_t physics;
55  hit_surface_selector_t selectHitSurface;
58 
67  template <typename propagator_state_t, typename stepper_t>
68  void operator()(propagator_state_t &state, stepper_t &stepper,
69  result_type &result) const {
70  assert(generator and "The generator pointer must be valid");
71 
72  // If we are on target, everything should have been done
73  if (state.navigation.targetReached) {
74  return;
75  }
76  // If we are not on a surface, there is nothing for us to do
77  if (not state.navigation.currentSurface) {
78  return;
79  }
80  const Acts::Surface &surface = *state.navigation.currentSurface;
81 
82  // avoid having a clumsy `initialized` flag by reconstructing the particle
83  // state directly from the propagation state; using only the identity
84  // parameters from the initial particle state.
85  const auto before =
87  // include passed material from the initial particle state
88  .setMaterialPassed(particle.pathInX0() + result.pathInX0,
89  particle.pathInL0() + result.pathInL0)
90  .setPosition4(stepper.position(state.stepping),
91  stepper.time(state.stepping))
92  .setDirection(stepper.direction(state.stepping))
93  .setAbsMomentum(stepper.momentum(state.stepping));
94  // we want to keep the particle state before and after the interaction.
95  // since the particle is modified in-place we need a copy.
96  auto after = before;
97 
98  // interactions only make sense if there is material to interact with.
99  if (surface.surfaceMaterial()) {
100  // TODO - is this the right thing to do when globalToLocal fails
101  // it should in principle never happen, so probably it would be best
102  // to change to a model using transform() directly
103  auto lpResult = surface.globalToLocal(state.geoContext, before.position(),
104  before.unitDirection());
105  if (lpResult.ok()) {
106  Acts::Vector2D local(0., 0.);
107 
108  Acts::MaterialSlab slab =
109  surface.surfaceMaterial()->materialSlab(local);
110 
111  // again: no valid material -> no interaction
112  if (slab) {
113  // adapt material for non-zero incidence
114  auto normal = surface.normal(state.geoContext, local);
115  // dot-product(unit normal, direction) = cos(incidence angle)
116  // particle direction is normalized, not sure about surface normal
117  auto cosIncidenceInv =
118  normal.norm() / normal.dot(before.unitDirection());
119  slab.scaleThickness(cosIncidenceInv);
120  // physics list returns if the particle was killed.
121  result.isAlive =
122  not physics(*generator, slab, after, result.generatedParticles);
123  // add the accumulated material; assumes the full material was passsed
124  // event if the particle was killed.
125  result.pathInX0 += slab.thicknessInX0();
126  result.pathInL0 += slab.thicknessInL0();
127  // WARNING this overwrites changes that the physics interactions
128  // might have performed with regard to the passed material.
129  // ensures consistent material counting by making the one
130  // component that by construction will see all material
131  // contributions (this Interactor) responsible.
132  // TODO review this for supporting multiple interactions within the
133  // same material slab
134  after.setMaterialPassed(before.pathInX0() + slab.thicknessInX0(),
135  before.pathInL0() + slab.thicknessInL0());
136  }
137  }
138  }
139 
140  // store results of this interaction step, including potential hits
141  result.particle = after;
142  if (selectHitSurface(surface)) {
143  result.hits.emplace_back(
144  surface.geometryId(), before.particleId(),
145  // the interaction could potentially modify the particle position
146  Hit::Scalar(0.5) * (before.position4() + after.position4()),
147  before.momentum4(), after.momentum4(), result.hits.size());
148  }
149 
150  // continue the propagation with the modified parameters
151  stepper.update(state.stepping, after.position(), after.unitDirection(),
152  after.absMomentum(), after.time());
153  }
154 
156  template <typename propagator_state_t, typename stepper_t>
157  void operator()(propagator_state_t &, stepper_t &) const {}
158 };
159 
160 } // namespace detail
161 } // namespace ActsFatras