93 const Acts::Transform3& Tp, spacepoint_iterator_t spBegin,
94 spacepoint_iterator_t spEnd, Acts::Vector3 bField,
95 Acts::ActsScalar bFieldMin,
96 Acts::ActsScalar mass = 139.57018 * Acts::UnitConstants::MeV) {
98 size_t numSP = std::distance(spBegin, spEnd);
100 std::cout <<
"ERROR::less than 3 point provided" << std::endl;
105 Acts::ActsScalar bFieldInTesla = bField.norm() / Acts::UnitConstants::T;
106 Acts::ActsScalar bFieldMinInTesla = bFieldMin / Acts::UnitConstants::T;
108 if (bFieldInTesla < bFieldMinInTesla) {
111 std::cout <<
"The magnetic field at the bottom space point: B = "
113 <<
" T is smaller than |B|_min = " << bFieldMinInTesla
114 <<
" T. Estimation is not performed." << std::endl;
119 std::array<Acts::Vector3, 3> spGlobalPositions = {
120 Acts::Vector3::Zero(), Acts::Vector3::Zero(), Acts::Vector3::Zero()};
123 for (
size_t isp = 0; isp < 3; ++isp) {
124 spacepoint_iterator_t it = std::next(spBegin, isp);
125 if (*it ==
nullptr) {
126 std::cout <<
"Empty space point found. This should not happen."
130 const auto& sp = *it;
131 spGlobalPositions[isp] = Acts::Vector3(sp->x(), sp->y(), sp->z());
139 Acts::Vector3 relVec = spGlobalPositions[1] - spGlobalPositions[0];
140 Acts::Vector3 newZAxis = bField.normalized();
141 Acts::Vector3 newYAxis = newZAxis.cross(relVec).normalized();
142 Acts::Vector3 newXAxis = newYAxis.cross(newZAxis);
143 Acts::RotationMatrix3 rotation;
144 rotation.col(0) = newXAxis;
145 rotation.col(1) = newYAxis;
146 rotation.col(2) = newZAxis;
148 Acts::Translation3 trans(spGlobalPositions[0]);
150 Acts::Transform3 transform(trans * rotation);
153 Acts::Vector3 local1 = transform.inverse() * spGlobalPositions[1];
154 Acts::Vector3 local2 = transform.inverse() * spGlobalPositions[2];
157 auto uvTransform = [](
const Acts::Vector3& local) -> Acts::Vector2 {
159 Acts::ActsScalar denominator =
160 local.x() * local.x() + local.y() * local.y();
161 uv.x() = local.x() / denominator;
162 uv.y() = local.y() / denominator;
166 Acts::Vector2 uv1 = uvTransform(local1);
167 Acts::Vector2 uv2 = uvTransform(local2);
171 Acts::ActsScalar A = (uv2.y() - uv1.y()) / (uv2.x() - uv1.x());
172 Acts::ActsScalar B = uv2.y() - A * uv2.x();
174 Acts::ActsScalar rho = -2.0 * B / std::hypot(1., A);
177 Acts::ActsScalar rn = local2.x() * local2.x() + local2.y() * local2.y();
179 Acts::ActsScalar invTanTheta =
180 local2.z() * std::sqrt(1. / rn) / (1. + rho * rho * rn);
183 Acts::Vector3 transDirection(1., A, std::hypot(1, A) * invTanTheta);
185 [[maybe_unused]] Acts::Vector3 direction =
186 rotation * transDirection.normalized();
189 Acts::BoundVector params = Acts::BoundVector::Zero();
195 Acts::Vector3 bottomLocalPos = Tp.inverse() * spGlobalPositions[0];
198 params[Acts::eBoundLoc0] = bottomLocalPos.x();
199 params[Acts::eBoundLoc1] = bottomLocalPos.y();
203 Acts::ActsScalar qOverPt =
204 rho * (Acts::UnitConstants::m) / (0.3 * bFieldInTesla);
206 params[Acts::eBoundQOverP] = qOverPt / std::hypot(1., invTanTheta);
210 Acts::ActsScalar pInGeV = std::abs(1.0 / params[Acts::eBoundQOverP]);
211 Acts::ActsScalar pzInGeV = 1.0 / std::abs(qOverPt) * invTanTheta;
212 Acts::ActsScalar massInGeV = mass / Acts::UnitConstants::GeV;
215 Acts::ActsScalar v = pInGeV / std::hypot(pInGeV, massInGeV);
216 Acts::ActsScalar vz = pzInGeV / std::hypot(pInGeV, massInGeV);
219 Acts::ActsScalar pathz = spGlobalPositions[0].dot(bField) / bField.norm();
223 params[Acts::eBoundTime] = pathz / vz;
225 params[Acts::eBoundTime] = spGlobalPositions[0].norm() / v;