Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
InteractionList.hpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file InteractionList.hpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2018-2021 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 
14 
15 #include <bitset>
16 #include <tuple>
17 #include <type_traits>
18 #include <utility>
19 
20 namespace ActsFatras {
21 namespace detail {
22 
26 template <class T, class Tuple>
27 struct TupleIndexOf;
28 template <class T, class... Types>
29 struct TupleIndexOf<T, std::tuple<T, Types...>> {
30  static constexpr std::size_t value = 0u;
31 };
32 template <class T, class U, class... Types>
33 struct TupleIndexOf<T, std::tuple<U, Types...>> {
34  static constexpr std::size_t value =
35  1u + TupleIndexOf<T, std::tuple<Types...>>::value;
36 };
37 
38 // Construct an index sequence for a subset of the tuple elements.
39 //
40 // Whether an element is part of the subset is defined by the predicate
41 // template type. It must take the element type as its only template parameter
42 // and must provide a static `value` member value. If the value evaluates to
43 // `true`, then the corresponding index will be part of the index sequence.
44 //
45 // Example: The tuple contains four elements, where all but the third one (i=2)
46 // should be selected. This leads to the following recursive expansion
47 // where the index sequence of the subset is filled from the front.
48 //
49 // TupleFilterImpl<..., kCounter=4> // select index=3
50 // -> TupleFilterImpl<..., kCounter=3, 3> // skip index=2
51 // -> TupleFilterImpl<..., kCounter=2, 3> // select index=1
52 // -> TupleFilterImpl<..., kCounter=1, 1, 3> // select index=0
53 // -> TupleFilterImpl<..., kCounter=0, 0, 1, 3> // terminate
54 //
55 template <template <typename> typename predicate_t, typename tuple_t,
56  size_t kCounter, size_t... kIndices>
58  static constexpr auto kIndex = kCounter - 1u;
59  static constexpr bool kElementSelection =
60  predicate_t<std::tuple_element_t<kIndex, tuple_t>>::value;
61  // recursive type if the element would be selected
62  using SelectElement = typename TupleFilterImpl<predicate_t, tuple_t, kIndex,
63  kIndex, kIndices...>::Type;
64  // recursive type if the element would be skipped
65  using SkipElement =
66  typename TupleFilterImpl<predicate_t, tuple_t, kIndex, kIndices...>::Type;
67  // select recursive type based on the selector decision
68  using Type =
69  std::conditional_t<kElementSelection, SelectElement, SkipElement>;
70 };
71 template <template <typename> typename predicate_t, typename tuple_t,
72  size_t... kIndices>
73 struct TupleFilterImpl<predicate_t, tuple_t, 0u, kIndices...> {
74  using Type = std::index_sequence<kIndices...>;
75 };
76 template <template <typename> typename predicate_t, typename tuple_t>
77 using TupleFilter = typename TupleFilterImpl<predicate_t, tuple_t,
78  std::tuple_size_v<tuple_t>>::Type;
79 
83 template <typename process_t>
86  using result_type = unsigned int;
87 
88  static constexpr result_type min() { return 0u; }
89  static constexpr result_type max() { return 1u << 15u; }
90  constexpr result_type operator()() { return 0u; }
91  };
92 
93  METHOD_TRAIT(generatePathLimits_method_t, generatePathLimits);
94 
95  using scalar_pair_t = std::pair<Particle::Scalar, Particle::Scalar>;
96 
97  public:
98  static constexpr bool value = Acts::Concepts::has_method<
99  const process_t, scalar_pair_t, generatePathLimits_method_t,
101 };
102 
103 template <typename process_t>
105  static constexpr bool value = not IsPointLikeProcess<process_t>::value;
106 };
107 
108 template <typename processes_t>
110 template <typename processes_t>
112 
113 } // namespace detail
114 
174 template <typename... processes_t>
176  using Mask = std::bitset<sizeof...(processes_t)>;
177  using Processes = std::tuple<processes_t...>;
180 
181  public:
183  struct Selection {
185  std::numeric_limits<Particle::Scalar>::infinity();
187  std::numeric_limits<Particle::Scalar>::infinity();
188  size_t x0Process = SIZE_MAX;
189  size_t l0Process = SIZE_MAX;
190  };
191 
193  void disable(size_t process) { m_mask.set(process); }
198  template <typename process_t>
199  void disable() {
201  }
202 
204  template <size_t kProcess>
205  std::tuple_element_t<kProcess, Processes>& get() {
206  return std::get<kProcess>(m_processes);
207  }
212  template <typename process_t>
213  process_t& get() {
214  return std::get<process_t>(m_processes);
215  }
216 
225  template <typename generator_t>
226  bool runContinuous(generator_t& rng, const Acts::MaterialSlab& slab,
228  std::vector<Particle>& generated) const {
229  return runContinuousImpl(rng, slab, particle, generated,
231  }
232 
240  template <typename generator_t>
241  Selection armPointLike(generator_t& rng, const Particle& particle) const {
242  Selection selection;
243  armPointLikeImpl(rng, particle, selection, PointLikeIndices());
244  return selection;
245  }
246 
259  template <typename generator_t>
260  bool runPointLike(generator_t& rng, size_t processIndex, Particle& particle,
261  std::vector<Particle>& generated) const {
262  return runPointLikeImpl(rng, processIndex, particle, generated,
263  PointLikeIndices());
264  }
265 
266  private:
267  // allow processes to be masked. defaults to zeros -> no masked processes
270 
271  // for the `runContinuous` call, we need to iterate over all available
272  // processes and apply the ones that implement the continuous process
273  // interface. this is done using an index-based compile-time recursive call.
274  template <typename generator_t, std::size_t kI0, std::size_t... kIs>
275  bool runContinuousImpl(generator_t& rng, const Acts::MaterialSlab& slab,
276  Particle& particle, std::vector<Particle>& generated,
277  std::index_sequence<kI0, kIs...> /*indices*/) const {
278  const auto& process = std::get<kI0>(m_processes);
279  // only call process if it is not masked
280  if (not m_mask[kI0] and process(rng, slab, particle, generated)) {
281  // exit early in case the process signals an abort
282  return true;
283  }
284  return runContinuousImpl(rng, slab, particle, generated,
285  std::index_sequence<kIs...>());
286  }
287  template <typename generator_t>
288  bool runContinuousImpl(generator_t& /*rng*/,
289  const Acts::MaterialSlab& /*slab*/,
290  Particle& /*particle*/,
291  std::vector<Particle>& /*generated*/,
292  std::index_sequence<> /*indices*/) const {
293  return false;
294  }
295 
296  // for the `armPointLike` call, we need to iterate over all available
297  // processes and select the ones that generate the smallest limits. this is
298  // done using an index-based compile-time recursive call.
299  template <typename generator_t, std::size_t kI0, std::size_t... kIs>
300  void armPointLikeImpl(generator_t& rng, const Particle& particle,
301  Selection& selection,
302  std::index_sequence<kI0, kIs...> /*indices*/) const {
303  // only arm the process if it is not masked
304  if (not m_mask[kI0]) {
305  auto [x0Limit, l0Limit] =
306  std::get<kI0>(m_processes).generatePathLimits(rng, particle);
307  if (x0Limit < selection.x0Limit) {
308  selection.x0Limit = x0Limit;
309  selection.x0Process = kI0;
310  }
311  if (l0Limit < selection.l0Limit) {
312  selection.l0Limit = l0Limit;
313  selection.l0Process = kI0;
314  }
315  }
316  // continue with the remaining processes
317  armPointLikeImpl(rng, particle, selection, std::index_sequence<kIs...>());
318  }
319  template <typename generator_t>
320  void armPointLikeImpl(generator_t& /*rng*/, const Particle& /*particle*/,
321  Selection& /*selection*/,
322  std::index_sequence<> /*indices*/) const {}
323 
324  // for the `runPointLike` call we need to call just one process. since we can
325  // not select a tuple element with a runtime index, we need to iterate over
326  // all processes with a compile-time recursive function until we reach the
327  // requested one.
328  template <typename generator_t, size_t kI0, size_t... kIs>
329  bool runPointLikeImpl(generator_t& rng, size_t processIndex,
330  Particle& particle, std::vector<Particle>& generated,
331  std::index_sequence<kI0, kIs...> /*indices*/) const {
332  if (kI0 == processIndex) {
333  if (m_mask[kI0]) {
334  // the selected process is masked. since nothing is executed the
335  // particle continues to be alive; not a break condition.
336  return false;
337  }
338  return std::get<kI0>(m_processes).run(rng, particle, generated);
339  }
340  // continue the iteration with the remaining processes
341  return runPointLikeImpl(rng, processIndex, particle, generated,
342  std::index_sequence<kIs...>());
343  }
344  template <typename generator_t>
345  bool runPointLikeImpl(generator_t& /*rng*/, size_t /*processIndex*/,
346  Particle& /*particle*/,
347  std::vector<Particle>& /*generated*/,
348  std::index_sequence<> /*indices*/) const {
349  // the requested process index is outside the possible range. **do not**
350  // treat this as an error to simplify the case of an empty physics lists or
351  // a default process index.
352  return false;
353  }
354 };
355 
356 } // namespace ActsFatras