LDMX Software
SeedToTrackParamMaker.h
1#pragma once
2
3#include "Acts/Definitions/Algebra.hpp"
4#include "Acts/Definitions/TrackParametrization.hpp"
5// #include "Acts/Utilities/VectorHelpers.hpp"
6#include <optional>
7
8#include "Acts/Definitions/Units.hpp"
9#include "Acts/Utilities/Helpers.hpp"
10
11namespace tracking {
12namespace sim {
13
15 public:
17
18 template <typename external_spacepoint_t>
19 bool karimakiFit(const std::vector<external_spacepoint_t*>& sp,
20 std::array<double, 9>& data, const Acts::Vector2 refPoint);
21
22 // We assume that a track propagates from point r1 to point r2
23 // If the test function returns negative means that we need to transform
24 // rho -> -rho
25 // phi -> phi+pi,
26 // d->-d
27
28 bool transformRhoPhid(const Acts::Vector2& r1, const Acts::Vector2& r2,
29 double& phi, double& rho, double& d) {
30 float track_dir = cos(phi) * (r1[0] - r2[0]) + sin(phi) * (r1[1] - r2[1]);
31
32 if (track_dir < 0) {
33 phi = M_PI + phi;
34 rho = -rho;
35 d = -d;
36 return true;
37 }
38
39 else
40 return false;
41 }
42
46 // Acts::Seed<T> removed in v47 — fitSeedAtlas(Seed) unused, commented out
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 // Acts::Seed<T> removed in v47 — fitSeedLinPar(Seed) unused, commented out
60 // template <typename external_spacepoint_t>
61 // bool fitSeedLinPar(const Acts::Seed<external_spacepoint_t>& seed,
62 // std::vector<double>& data);
63
91
92 template <typename spacepoint_iterator_t>
93 std::optional<Acts::BoundVector> estimateTrackParamsFromSeed(
94 const Acts::Transform3& Tp, spacepoint_iterator_t spBegin,
95 spacepoint_iterator_t spEnd, Acts::Vector3 bField, double bFieldMin,
96 double mass = 139.57018 * Acts::UnitConstants::MeV) {
97 // Check the number of provided space points
98 size_t num_sp = std::distance(spBegin, spEnd);
99 if (num_sp != 3) {
100 std::cout << "ERROR::less than 3 point provided" << std::endl;
101 return std::nullopt;
102 }
103
104 // Convert bField to Tesla
105 double b_field_in_tesla = bField.norm() / Acts::UnitConstants::T;
106 double b_field_min_in_tesla = bFieldMin / Acts::UnitConstants::T;
107 // Check if magnetic field is too small
108 if (b_field_in_tesla < b_field_min_in_tesla) {
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 << b_field_in_tesla
113 << " T is smaller than |B|_min = " << b_field_min_in_tesla
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> sp_global_positions = {
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 sp_global_positions[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 rel_vec = sp_global_positions[1] - sp_global_positions[0];
140 Acts::Vector3 new_z_axis = bField.normalized();
141 Acts::Vector3 new_y_axis = new_z_axis.cross(rel_vec).normalized();
142 Acts::Vector3 new_x_axis = new_y_axis.cross(new_z_axis);
143 Acts::RotationMatrix3 rotation;
144 rotation.col(0) = new_x_axis;
145 rotation.col(1) = new_y_axis;
146 rotation.col(2) = new_z_axis;
147 // The center of the new frame is at the bottom space point
148 Acts::Translation3 trans(sp_global_positions[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() * sp_global_positions[1];
154 Acts::Vector3 local2 = transform.inverse() * sp_global_positions[2];
155
156 // Lambda to transform the coordinates to the (u, v) space
157 auto uv_transform = [](const Acts::Vector3& local) -> Acts::Vector2 {
158 Acts::Vector2 uv;
159 double denominator = local.x() * local.x() + local.y() * local.y();
160 uv.x() = local.x() / denominator;
161 uv.y() = local.y() / denominator;
162 return uv;
163 };
164 // The uv1.y() should be zero
165 Acts::Vector2 uv1 = uv_transform(local1);
166 Acts::Vector2 uv2 = uv_transform(local2);
167
168 // A,B are slope and intercept of the straight line in the u,v plane
169 // connecting the three points
170 double a = (uv2.y() - uv1.y()) / (uv2.x() - uv1.x());
171 double b = uv2.y() - a * uv2.x();
172 // Curvature (with a sign) estimate
173 double rho = -2.0 * b / std::hypot(1., a);
174 // The projection of the top space point on the transverse plane of the new
175 // frame
176 double rn = local2.x() * local2.x() + local2.y() * local2.y();
177 // The (1/tanTheta) of momentum in the new frame,
178 double inv_tan_theta =
179 local2.z() * std::sqrt(1. / rn) / (1. + rho * rho * rn);
180 // The momentum direction in the new frame (the center of the circle has the
181 // coordinate (-1.*A/(2*B), 1./(2*B)))
182 Acts::Vector3 trans_direction(1., a, std::hypot(1, a) * inv_tan_theta);
183 // Transform it back to the original frame
184 [[maybe_unused]] Acts::Vector3 direction =
185 rotation * trans_direction.normalized();
186
187 // Initialize the bound parameters vector
188 Acts::BoundVector params = Acts::BoundVector::Zero();
189
190 // The estimated phi and theta
191 // params[Acts::eBoundPhi] = Acts::VectorHelpers::phi(direction);
192 // params[Acts::eBoundTheta] = Acts::VectorHelpers::theta(direction);
193
194 Acts::Vector3 bottom_local_pos = Tp.inverse() * sp_global_positions[0];
195
196 // The estimated loc0 and loc1
197 params[Acts::eBoundLoc0] = bottom_local_pos.x();
198 params[Acts::eBoundLoc1] = bottom_local_pos.y();
199
200 // The estimated q/pt in [GeV/c]^-1 (note that the pt is the projection of
201 // momentum on the transverse plane of the new frame)
202 double q_over_pt =
203 rho * (Acts::UnitConstants::m) / (0.3 * b_field_in_tesla);
204 // The estimated q/p in [GeV/c]^-1
205 params[Acts::eBoundQOverP] = q_over_pt / std::hypot(1., inv_tan_theta);
206
207 // The estimated momentum, and its projection along the magnetic field
208 // diretion
209 double p_in_ge_v = std::abs(1.0 / params[Acts::eBoundQOverP]);
210 double pz_in_ge_v = 1.0 / std::abs(q_over_pt) * inv_tan_theta;
211 double mass_in_ge_v = mass / Acts::UnitConstants::GeV;
212 // The estimated velocity, and its projection along the magnetic field
213 // diretion
214 double v = p_in_ge_v / std::hypot(p_in_ge_v, mass_in_ge_v);
215 double vz = pz_in_ge_v / std::hypot(p_in_ge_v, mass_in_ge_v);
216 // The z_ coordinate of the bottom space point along the magnetic field
217 // direction
218 double pathz = sp_global_positions[0].dot(bField) / bField.norm();
219 // The estimated time (use path length along magnetic field only if it's not
220 // zero)
221 if (pathz != 0) {
222 params[Acts::eBoundTime] = pathz / vz;
223 } else {
224 params[Acts::eBoundTime] = sp_global_positions[0].norm() / v;
225 }
226
227 return params;
228 }
229};
230} // namespace sim
231} // namespace tracking
232
233#include "SeedToTrackParamMaker.ipp"
std::optional< Acts::BoundVector > estimateTrackParamsFromSeed(const Acts::Transform3 &Tp, spacepoint_iterator_t spBegin, spacepoint_iterator_t spEnd, Acts::Vector3 bField, double bFieldMin, double mass=139.57018 *Acts::UnitConstants::MeV)
This is a simple Line and Parabola fit (from HPS reconstruction by Robert Johnson)
bool fitSeedAtlas(const std::vector< external_spacepoint_t > &sp, 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...