LDMX Software
SeedToTrackParamMaker.h
1#pragma once
2
3#include "Acts/Definitions/Algebra.hpp"
4#include "Acts/Definitions/TrackParametrization.hpp"
5#include "Acts/Seeding/Seed.hpp"
6//#include "Acts/Utilities/VectorHelpers.hpp"
7#include <optional>
8
9#include "Acts/Definitions/Units.hpp"
10#include "Acts/Utilities/Helpers.hpp"
11
12namespace tracking {
13namespace sim {
14
16 public:
18
19 template <typename external_spacepoint_t>
20 bool KarimakiFit(const std::vector<external_spacepoint_t*>& sp,
21 std::array<double, 9>& data, const Acts::Vector2 refPoint);
22
23 // We assume that a track propagates from point r1 to point r2
24 // If the test function returns negative means that we need to transform
25 // rho -> -rho
26 // phi -> phi+pi,
27 // d->-d
28
29 bool transformRhoPhid(const Acts::Vector2& r1, const Acts::Vector2& r2,
30 double& phi, double& rho, double& d) {
31 float trackDir = cos(phi) * (r1[0] - r2[0]) + sin(phi) * (r1[1] - r2[1]);
32
33 if (trackDir < 0) {
34 phi = M_PI + phi;
35 rho = -rho;
36 d = -d;
37 return true;
38 }
39
40 else
41 return false;
42 }
43
47 template <typename external_spacepoint_t>
48 bool FitSeedAtlas(const Acts::Seed<external_spacepoint_t>& seed,
49 std::array<double, 9>& data, const Acts::Transform3& Tp,
50 const double& bFieldZ);
51
52 template <typename external_spacepoint_t>
53 bool FitSeedAtlas(const std::vector<external_spacepoint_t>& sp,
54 std::array<double, 9>& data, const Acts::Transform3& Tp,
55 const double& bFieldZ);
56
59 template <typename external_spacepoint_t>
60 bool FitSeedLinPar(const Acts::Seed<external_spacepoint_t>& seed,
61 std::vector<double>& data);
62
90
91 template <typename spacepoint_iterator_t>
92 std::optional<Acts::BoundVector> estimateTrackParamsFromSeed(
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) {
97 // Check the number of provided space points
98 size_t numSP = std::distance(spBegin, spEnd);
99 if (numSP != 3) {
100 std::cout << "ERROR::less than 3 point provided" << std::endl;
101 return std::nullopt;
102 }
103
104 // Convert bField to Tesla
105 Acts::ActsScalar bFieldInTesla = bField.norm() / Acts::UnitConstants::T;
106 Acts::ActsScalar bFieldMinInTesla = bFieldMin / Acts::UnitConstants::T;
107 // Check if magnetic field is too small
108 if (bFieldInTesla < bFieldMinInTesla) {
109 // @todo shall we use straight-line estimation and use default q/pt in
110 // such case?
111 std::cout << "The magnetic field at the bottom space point: B = "
112 << bFieldInTesla
113 << " T is smaller than |B|_min = " << bFieldMinInTesla
114 << " T. Estimation is not performed." << std::endl;
115 return std::nullopt;
116 }
117
118 // The global positions of the bottom, middle and space points
119 std::array<Acts::Vector3, 3> spGlobalPositions = {
120 Acts::Vector3::Zero(), Acts::Vector3::Zero(), Acts::Vector3::Zero()};
121 // The first, second and third space point are assumed to be bottom, middle
122 // and top space point, respectively
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."
127 << std::endl;
128 return std::nullopt;
129 }
130 const auto& sp = *it;
131 spGlobalPositions[isp] = Acts::Vector3(sp->x(), sp->y(), sp->z());
132 }
133
134 // Define a new coordinate frame with its origin at the bottom space point,
135 // z axis along the magnetic field direction and y axis perpendicular to
136 // vector from the bottom to middle space point. Hence, the projection of
137 // the middle space point on the tranverse plane will be located at the x
138 // axis of the new frame.
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;
147 // The center of the new frame is at the bottom space point
148 Acts::Translation3 trans(spGlobalPositions[0]);
149 // The transform which constructs the new frame
150 Acts::Transform3 transform(trans * rotation);
151
152 // The coordinate of the middle and top space point in the new frame
153 Acts::Vector3 local1 = transform.inverse() * spGlobalPositions[1];
154 Acts::Vector3 local2 = transform.inverse() * spGlobalPositions[2];
155
156 // Lambda to transform the coordinates to the (u, v) space
157 auto uvTransform = [](const Acts::Vector3& local) -> Acts::Vector2 {
158 Acts::Vector2 uv;
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;
163 return uv;
164 };
165 // The uv1.y() should be zero
166 Acts::Vector2 uv1 = uvTransform(local1);
167 Acts::Vector2 uv2 = uvTransform(local2);
168
169 // A,B are slope and intercept of the straight line in the u,v plane
170 // connecting the three points
171 Acts::ActsScalar A = (uv2.y() - uv1.y()) / (uv2.x() - uv1.x());
172 Acts::ActsScalar B = uv2.y() - A * uv2.x();
173 // Curvature (with a sign) estimate
174 Acts::ActsScalar rho = -2.0 * B / std::hypot(1., A);
175 // The projection of the top space point on the transverse plane of the new
176 // frame
177 Acts::ActsScalar rn = local2.x() * local2.x() + local2.y() * local2.y();
178 // The (1/tanTheta) of momentum in the new frame,
179 Acts::ActsScalar invTanTheta =
180 local2.z() * std::sqrt(1. / rn) / (1. + rho * rho * rn);
181 // The momentum direction in the new frame (the center of the circle has the
182 // coordinate (-1.*A/(2*B), 1./(2*B)))
183 Acts::Vector3 transDirection(1., A, std::hypot(1, A) * invTanTheta);
184 // Transform it back to the original frame
185 [[maybe_unused]] Acts::Vector3 direction =
186 rotation * transDirection.normalized();
187
188 // Initialize the bound parameters vector
189 Acts::BoundVector params = Acts::BoundVector::Zero();
190
191 // The estimated phi and theta
192 // params[Acts::eBoundPhi] = Acts::VectorHelpers::phi(direction);
193 // params[Acts::eBoundTheta] = Acts::VectorHelpers::theta(direction);
194
195 Acts::Vector3 bottomLocalPos = Tp.inverse() * spGlobalPositions[0];
196
197 // The estimated loc0 and loc1
198 params[Acts::eBoundLoc0] = bottomLocalPos.x();
199 params[Acts::eBoundLoc1] = bottomLocalPos.y();
200
201 // The estimated q/pt in [GeV/c]^-1 (note that the pt is the projection of
202 // momentum on the transverse plane of the new frame)
203 Acts::ActsScalar qOverPt =
204 rho * (Acts::UnitConstants::m) / (0.3 * bFieldInTesla);
205 // The estimated q/p in [GeV/c]^-1
206 params[Acts::eBoundQOverP] = qOverPt / std::hypot(1., invTanTheta);
207
208 // The estimated momentum, and its projection along the magnetic field
209 // diretion
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;
213 // The estimated velocity, and its projection along the magnetic field
214 // diretion
215 Acts::ActsScalar v = pInGeV / std::hypot(pInGeV, massInGeV);
216 Acts::ActsScalar vz = pzInGeV / std::hypot(pInGeV, massInGeV);
217 // The z coordinate of the bottom space point along the magnetic field
218 // direction
219 Acts::ActsScalar pathz = spGlobalPositions[0].dot(bField) / bField.norm();
220 // The estimated time (use path length along magnetic field only if it's not
221 // zero)
222 if (pathz != 0) {
223 params[Acts::eBoundTime] = pathz / vz;
224 } else {
225 params[Acts::eBoundTime] = spGlobalPositions[0].norm() / v;
226 }
227
228 return params;
229 }
230};
231} // namespace sim
232} // namespace tracking
233
234#include "SeedToTrackParamMaker.ipp"
std::optional< Acts::BoundVector > estimateTrackParamsFromSeed(const Acts::Transform3 &Tp, spacepoint_iterator_t spBegin, spacepoint_iterator_t spEnd, Acts::Vector3 bField, Acts::ActsScalar bFieldMin, Acts::ActsScalar mass=139.57018 *Acts::UnitConstants::MeV)
Estimate the full track parameters from three space points.
bool FitSeedLinPar(const Acts::Seed< external_spacepoint_t > &seed, std::vector< double > &data)
This is a simple Line and Parabola fit (from HPS reconstruction by Robert Johnson)
bool FitSeedAtlas(const Acts::Seed< external_spacepoint_t > &seed, std::array< double, 9 > &data, const Acts::Transform3 &Tp, const double &bFieldZ)
This resembles the method used in ATLAS for the seed fitting L811 https://acode-browser....
The measurement calibrator can be a function or a class/struct able to retrieve the sim hits containe...