Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
NuclearInteraction.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file NuclearInteraction.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 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 
10 
11 #include <algorithm>
12 #include <cstddef>
13 #include <cstdint>
14 #include <iterator>
15 #include <memory>
16 #include <type_traits>
17 
18 namespace ActsFatras {
19 
21  double rnd,
22  const detail::NuclearInteractionParametrisation& parametrisation,
23  float particleMomentum) const {
24  // Return lowest/highest if momentum outside the boundary
25  if (particleMomentum <= parametrisation.front().first) {
26  return parametrisation.front().second;
27  }
28  if (particleMomentum >= parametrisation.back().first) {
29  return parametrisation.back().second;
30  }
31 
32  // Find the two neighbouring parametrisations
33  const auto lowerBound = std::lower_bound(
34  parametrisation.begin(), parametrisation.end(), particleMomentum,
35  [](const std::pair<const float,
37  params,
38  const float mom) { return params.first < mom; });
39  const float momentumUpperNeighbour = lowerBound->first;
40  const float momentumLowerNeighbour = std::prev(lowerBound, 1)->first;
41 
42  // Pick one randomly
43  const float weight = (momentumUpperNeighbour - particleMomentum) /
44  (momentumUpperNeighbour - momentumLowerNeighbour);
45  return (rnd < weight) ? std::prev(lowerBound, 1)->second : lowerBound->second;
46 } // namespace ActsFatras
47 
49  double rnd,
51  distribution) const {
52  // Fast exit
53  if (distribution.second.empty()) {
54  return 0;
55  }
56 
57  // Find the bin
58  const uint32_t int_rnd = static_cast<uint32_t>(UINT32_MAX * rnd);
59  const auto it = std::upper_bound(distribution.second.begin(),
60  distribution.second.end(), int_rnd);
61  size_t iBin = std::min((size_t)std::distance(distribution.second.begin(), it),
62  distribution.second.size() - 1);
63 
64  // Return the corresponding bin
65  return static_cast<unsigned int>(distribution.first[iBin]);
66 }
67 
69  double rnd,
71  distribution,
72  bool interpolate) const {
73  // Fast exit
74  if (distribution.second.empty()) {
75  return std::numeric_limits<Scalar>::infinity();
76  }
77 
78  // Find the bin
79  const uint32_t int_rnd = static_cast<uint32_t>(UINT32_MAX * rnd);
80  // Fast exit for non-normalised CDFs like interaction probabiltiy
81  if (int_rnd > distribution.second.back()) {
82  return std::numeric_limits<Scalar>::infinity();
83  }
84  const auto it = std::upper_bound(distribution.second.begin(),
85  distribution.second.end(), int_rnd);
86  size_t iBin = std::min((size_t)std::distance(distribution.second.begin(), it),
87  distribution.second.size() - 1);
88 
89  if (interpolate) {
90  // Interpolate between neighbouring bins and return a diced intermediate
91  // value
92  const uint32_t basecont = (iBin > 0 ? distribution.second[iBin - 1] : 0);
93  const uint32_t dcont = distribution.second[iBin] - basecont;
94  return distribution.first[iBin] +
95  (distribution.first[iBin + 1] - distribution.first[iBin]) *
96  (dcont > 0 ? (int_rnd - basecont) / dcont : 0.5);
97  } else {
98  return distribution.first[iBin];
99  }
100 }
101 
103  double rnd,
105  distribution) const {
106  return sampleDiscreteValues(rnd, distribution);
107 }
108 
109 std::pair<ActsFatras::Particle::Scalar, ActsFatras::Particle::Scalar>
111  ActsFatras::Particle::Scalar theta1, float phi2,
112  float theta2) const {
113  // Rotation around the global y-axis
114  Acts::SquareMatrix3 rotY = Acts::SquareMatrix3::Zero();
115  rotY(0, 0) = std::cos(theta1);
116  rotY(0, 2) = std::sin(theta1);
117  rotY(1, 1) = 1.;
118  rotY(2, 0) = -std::sin(theta1);
119  rotY(2, 2) = std::cos(theta1);
120 
121  // Rotation around the global z-axis
122  Acts::SquareMatrix3 rotZ = Acts::SquareMatrix3::Zero();
123  rotZ(0, 0) = std::cos(phi1);
124  rotZ(0, 1) = -std::sin(phi1);
125  rotZ(1, 0) = std::sin(phi1);
126  rotZ(1, 1) = std::cos(phi1);
127  rotZ(2, 2) = 1.;
128 
129  // Rotate the direction vector of the second particle
130  const Acts::Vector3 vector2(std::sin(theta2) * std::cos(phi2),
131  std::sin(theta2) * std::sin(phi2),
132  std::cos(theta2));
133  const Acts::Vector3 vectorSum = rotZ * rotY * vector2;
134 
135  // Calculate the global angles
136  const float theta = std::acos(vectorSum.z() / vectorSum.norm());
137  const float phi = std::atan2(vectorSum.y(), vectorSum.x());
138 
139  return std::make_pair(phi, theta);
140 }
141 
143  const Acts::ActsDynamicVector& invariantMasses,
144  float parametrizedMomentum) const {
145  const unsigned int size = momenta.size();
146  for (unsigned int i = 0; i < size; i++) {
147  // Calculate the invariant masses
148  const float momentum = momenta[i];
149  const float invariantMass = invariantMasses[i];
150  const float p1p2 = 2. * momentum * parametrizedMomentum;
151  const float costheta = 1. - invariantMass * invariantMass / p1p2;
152 
153  // Abort if an angle cannot be calculated
154  if (std::abs(costheta) > 1) {
155  return false;
156  }
157  }
158  return true;
159 }
160 } // namespace ActsFatras