File indexing completed on 2025-12-16 09:20:34
0001 #include "TrackFitUtils.h"
0002
0003 #include "ActsGeometry.h"
0004 #include "ActsSurfaceMaps.h"
0005 #include "MvtxDefs.h"
0006 #include "TrkrClusterContainerv4.h"
0007 #include "TrkrDefs.h" // for cluskey, getTrkrId, tpcId
0008
0009 #include <Acts/Definitions/Algebra.hpp>
0010 #include <Acts/Definitions/Units.hpp>
0011
0012 #include <algorithm>
0013 #include <cmath>
0014 #include <cstdint>
0015 #include <iostream>
0016 #include <iterator>
0017 #include <limits>
0018 #include <ostream>
0019 #include <set>
0020 #include <tuple>
0021 #include <utility>
0022 #include <vector>
0023
0024 namespace
0025 {
0026
0027
0028 template <class T>
0029 inline constexpr T square(const T& x)
0030 {
0031 return x * x;
0032 }
0033 template <class T>
0034 inline constexpr T r(const T& x, const T& y)
0035 {
0036 return std::sqrt(square(x) + square(y));
0037 }
0038 }
0039
0040 std::pair<Acts::Vector3, Acts::Vector3> TrackFitUtils::get_helix_tangent(const std::vector<float>& fitpars, Acts::Vector3& global)
0041 {
0042
0043
0044
0045 float const radius = fitpars[0];
0046 float const x0 = fitpars[1];
0047 float const y0 = fitpars[2];
0048 float const zslope = fitpars[3];
0049 float const z0 = fitpars[4];
0050
0051 Acts::Vector2 pca_circle = TrackFitUtils::get_circle_point_pca(radius, x0, y0, global);
0052
0053
0054 float const pca_circle_radius = pca_circle.norm();
0055 float const pca_z = pca_circle_radius * zslope + z0;
0056 Acts::Vector3 const pca(pca_circle(0), pca_circle(1), pca_z);
0057
0058
0059
0060 float const angle_pca = atan2(pca_circle(1) - y0, pca_circle(0) - x0);
0061
0062 float const d_angle = 0.005;
0063 float const newx = radius * std::cos(angle_pca + d_angle) + x0;
0064 float const newy = radius * std::sin(angle_pca + d_angle) + y0;
0065 float const newz = std::sqrt(newx * newx + newy * newy) * zslope + z0;
0066 Acts::Vector3 const second_point_pca(newx, newy, newz);
0067
0068
0069 Acts::Vector3 tangent = (second_point_pca - pca) / (second_point_pca - pca).norm();
0070
0071
0072 float const phi = atan2(global(1), global(0));
0073 float const tangent_phi = atan2(tangent(1), tangent(0));
0074 if (std::fabs(tangent_phi - phi) > M_PI / 2)
0075 {
0076 tangent = -1.0 * tangent;
0077 }
0078
0079
0080
0081
0082
0083
0084 Acts::Vector3 const final_pca = pca + ((global - pca).dot(tangent)) * tangent;
0085
0086 auto line = std::make_pair(final_pca, tangent);
0087
0088 return line;
0089 }
0090 Acts::Vector3 TrackFitUtils::surface_3Dline_intersection(const TrkrDefs::cluskey& key,
0091 TrkrCluster* cluster, ActsGeometry* geometry, float& xyslope, float& xyint, float& yzslope, float& yzint)
0092 {
0093 Acts::Vector3 intersection(std::numeric_limits<float>::quiet_NaN(),
0094 std::numeric_limits<float>::quiet_NaN(),
0095 std::numeric_limits<float>::quiet_NaN());
0096
0097 auto surf = geometry->maps().getSurface(key, cluster);
0098
0099
0100
0101 float const x1 = -1;
0102 float const x2 = 5;
0103 float const y1 = xyslope * x1 + xyint;
0104 float const y2 = xyslope * x2 + xyint;
0105
0106 float const z1 = (y1 - yzint) / yzslope;
0107 float const z2 = (y2 - yzint) / yzslope;
0108
0109 Acts::Vector3 v1(x1, y1, z1), v2(x2, y2, z2);
0110
0111 Acts::Vector3 surfcenter = surf->center(geometry->geometry().getGeoContext()) / Acts::UnitConstants::cm;
0112 Acts::Vector3 surfnorm = surf->normal(geometry->geometry().getGeoContext(), Acts::Vector3(1,1,1), Acts::Vector3(1,1,1)) / Acts::UnitConstants::cm;
0113
0114 Acts::Vector3 u = v2 - v1;
0115 float const dot = surfnorm.dot(u);
0116
0117
0118 if (abs(dot) > 1e-6)
0119 {
0120 Acts::Vector3 const w = v1 - surfcenter;
0121 float const fac = -surfnorm.dot(w) / dot;
0122 u *= fac;
0123 intersection = v1 + u;
0124 }
0125
0126 return intersection;
0127 }
0128
0129 TrackFitUtils::circle_fit_output_t TrackFitUtils::circle_fit_by_taubin(const TrackFitUtils::position_vector_t& positions)
0130 {
0131
0132 double meanX = 0;
0133 double meanY = 0;
0134 double weight = 0;
0135
0136 for (const auto& [x, y] : positions)
0137 {
0138 meanX += x;
0139 meanY += y;
0140 ++weight;
0141 }
0142 meanX /= weight;
0143 meanY /= weight;
0144
0145
0146
0147 double Mxx = 0;
0148 double Myy = 0;
0149 double Mxy = 0;
0150 double Mxz = 0;
0151 double Myz = 0;
0152 double Mzz = 0;
0153
0154 for (auto& [x, y] : positions)
0155 {
0156 double const Xi = x - meanX;
0157 double const Yi = y - meanY;
0158 double const Zi = square(Xi) + square(Yi);
0159
0160 Mxy += Xi * Yi;
0161 Mxx += Xi * Xi;
0162 Myy += Yi * Yi;
0163 Mxz += Xi * Zi;
0164 Myz += Yi * Zi;
0165 Mzz += Zi * Zi;
0166 }
0167 Mxx /= weight;
0168 Myy /= weight;
0169 Mxy /= weight;
0170 Mxz /= weight;
0171 Myz /= weight;
0172 Mzz /= weight;
0173
0174
0175
0176 const double Mz = Mxx + Myy;
0177 const double Cov_xy = Mxx * Myy - Mxy * Mxy;
0178 const double Var_z = Mzz - Mz * Mz;
0179 const double A3 = 4 * Mz;
0180 const double A2 = -3 * Mz * Mz - Mzz;
0181 const double A1 = Var_z * Mz + 4 * Cov_xy * Mz - Mxz * Mxz - Myz * Myz;
0182 const double A0 = Mxz * (Mxz * Myy - Myz * Mxy) + Myz * (Myz * Mxx - Mxz * Mxy) - Var_z * Cov_xy;
0183 const double A22 = A2 + A2;
0184 const double A33 = A3 + A3 + A3;
0185
0186
0187
0188
0189 static constexpr int iter_max = 99;
0190 double x = 0;
0191 double y = A0;
0192
0193
0194 for (int iter = 0; iter < iter_max; ++iter)
0195 {
0196 const double Dy = A1 + x * (A22 + A33 * x);
0197 const double xnew = x - y / Dy;
0198 if ((xnew == x) || (!std::isfinite(xnew)))
0199 {
0200 break;
0201 }
0202
0203 const double ynew = A0 + xnew * (A1 + xnew * (A2 + xnew * A3));
0204 if (std::abs(ynew) >= std::abs(y))
0205 {
0206 break;
0207 }
0208
0209 x = xnew;
0210 y = ynew;
0211 }
0212
0213
0214 const double DET = square(x) - x * Mz + Cov_xy;
0215 const double Xcenter = (Mxz * (Myy - x) - Myz * Mxy) / DET / 2;
0216 const double Ycenter = (Myz * (Mxx - x) - Mxz * Mxy) / DET / 2;
0217
0218
0219 double const X0 = Xcenter + meanX;
0220 double const Y0 = Ycenter + meanY;
0221 double const R = std::sqrt(square(Xcenter) + square(Ycenter) + Mz);
0222 return std::make_tuple(R, X0, Y0);
0223 }
0224
0225
0226 TrackFitUtils::circle_fit_output_t TrackFitUtils::circle_fit_by_taubin(const std::vector<Acts::Vector3>& positions)
0227 {
0228 position_vector_t positions_2d;
0229 for (const auto& position : positions)
0230 {
0231 positions_2d.emplace_back(position.x(), position.y());
0232 }
0233
0234 return circle_fit_by_taubin(positions_2d);
0235 }
0236
0237
0238 TrackFitUtils::line_fit_output_t TrackFitUtils::line_fit(const TrackFitUtils::position_vector_t& positions)
0239 {
0240
0241
0242
0243
0244
0245 double xmean = 0.;
0246 double ymean = 0.;
0247 for (const auto& [x, y] : positions)
0248 {
0249 xmean = xmean + x;
0250 ymean = ymean + y;
0251 }
0252 double const n = positions.size();
0253 xmean /= n;
0254 ymean /= n;
0255
0256
0257 double ssd_x = 0.;
0258 double ssd_y = 0.;
0259 double ssd_xy = 0.;
0260 for (const auto& [x, y] : positions)
0261 {
0262 ssd_x += square(x - xmean);
0263 ssd_y += square(y - ymean);
0264 ssd_xy += (x - xmean) * (y - ymean);
0265 }
0266 const double slope = (ssd_y - ssd_x + sqrt(square(ssd_y - ssd_x) + 4 * square(ssd_xy))) / 2. / ssd_xy;
0267 const double intercept = ymean - slope * xmean;
0268 return std::make_tuple(slope, intercept);
0269 }
0270
0271
0272 TrackFitUtils::line_fit_output_t TrackFitUtils::line_fit(const std::vector<Acts::Vector3>& positions)
0273 {
0274 position_vector_t positions_2d;
0275 for (const auto& position : positions)
0276 {
0277 positions_2d.emplace_back(std::sqrt(square(position.x()) + square(position.y())), position.z());
0278 }
0279
0280 return line_fit(positions_2d);
0281 }
0282
0283
0284 TrackFitUtils::line_fit_output_t TrackFitUtils::line_fit_xz(const std::vector<Acts::Vector3>& positions)
0285 {
0286 position_vector_t positions_2d;
0287 for (const auto& position : positions)
0288 {
0289 positions_2d.emplace_back(position.x(), position.z());
0290 }
0291
0292 return line_fit(positions_2d);
0293 }
0294
0295
0296 TrackFitUtils::line_fit_output_t TrackFitUtils::line_fit_xy(const std::vector<Acts::Vector3>& positions)
0297 {
0298 position_vector_t positions_2d;
0299 for (const auto& position : positions)
0300 {
0301 positions_2d.emplace_back(position.x(), position.y());
0302 }
0303
0304 return line_fit(positions_2d);
0305 }
0306
0307
0308 TrackFitUtils::line_circle_intersection_output_t TrackFitUtils::line_circle_intersection(double r, double m, double b)
0309 {
0310 const double a_coef = 1 + square(m);
0311 const double b_coef = 2 * m * b;
0312 const double c_coef = square(b) - square(r);
0313 const double delta = square(b_coef) - 4 * a_coef * c_coef;
0314
0315 const double sqdelta = std::sqrt(delta);
0316
0317 const double xplus = (-b_coef + sqdelta) / (2. * a_coef);
0318 const double xminus = (-b_coef - sqdelta) / (2. * a_coef);
0319
0320 const double yplus = m * xplus + b;
0321 const double yminus = m * xminus + b;
0322
0323 return std::make_tuple(xplus, yplus, xminus, yminus);
0324 }
0325
0326
0327 TrackFitUtils::circle_circle_intersection_output_t TrackFitUtils::circle_circle_intersection(double r1, double r2, double x2, double y2)
0328 {
0329 const double D = square(r1) - square(r2) + square(x2) + square(y2);
0330 const double a = 1.0 + square(x2 / y2);
0331 const double b = -D * x2 / square(y2);
0332 const double c = square(D / (2. * y2)) - square(r1);
0333 const double delta = square(b) - 4. * a * c;
0334
0335 const double sqdelta = std::sqrt(delta);
0336
0337 const double xplus = (-b + sqdelta) / (2. * a);
0338 const double xminus = (-b - sqdelta) / (2. * a);
0339
0340 const double yplus = -(2 * x2 * xplus - D) / (2. * y2);
0341 const double yminus = -(2 * x2 * xminus - D) / (2. * y2);
0342
0343 return std::make_tuple(xplus, yplus, xminus, yminus);
0344 }
0345
0346 unsigned int TrackFitUtils::addClustersOnLine(TrackFitUtils::line_fit_output_t& fitpars,
0347 const bool& isXY,
0348 const double& dca_cut,
0349 ActsGeometry* tGeometry,
0350 TrkrClusterContainer* clusterContainer,
0351 std::vector<Acts::Vector3>& global_vec,
0352 std::vector<TrkrDefs::cluskey>& cluskey_vec,
0353 const unsigned int& startLayer,
0354 const unsigned int& endLayer)
0355 {
0356 float const slope = std::get<0>(fitpars);
0357 float const intercept = std::get<1>(fitpars);
0358
0359 int nclusters = 0;
0360 std::set<TrkrDefs::cluskey> keys_to_add;
0361 std::set<TrkrDefs::TrkrId> detectors = {TrkrDefs::TrkrId::mvtxId,
0362 TrkrDefs::TrkrId::inttId,
0363 TrkrDefs::TrkrId::tpcId,
0364 TrkrDefs::TrkrId::micromegasId};
0365
0366 if (startLayer > 2)
0367 {
0368 detectors.erase(TrkrDefs::TrkrId::mvtxId);
0369 if (startLayer > 6)
0370 {
0371 detectors.erase(TrkrDefs::TrkrId::inttId);
0372 if (startLayer > 54)
0373 {
0374 detectors.erase(TrkrDefs::TrkrId::tpcId);
0375 }
0376 }
0377 }
0378 if (endLayer < 56)
0379 {
0380 detectors.erase(TrkrDefs::TrkrId::micromegasId);
0381 if (endLayer < 7)
0382 {
0383 detectors.erase(TrkrDefs::TrkrId::tpcId);
0384 if (endLayer < 3)
0385 {
0386 detectors.erase(TrkrDefs::TrkrId::inttId);
0387 }
0388 }
0389 }
0390 for (const auto& det : detectors)
0391 {
0392 for (const auto& hitsetkey : clusterContainer->getHitSetKeys(det))
0393 {
0394 if (TrkrDefs::getLayer(hitsetkey) < startLayer ||
0395 TrkrDefs::getLayer(hitsetkey) > endLayer)
0396 {
0397 continue;
0398 }
0399
0400 auto range = clusterContainer->getClusters(hitsetkey);
0401 for (auto clusIter = range.first; clusIter != range.second; ++clusIter)
0402 {
0403 TrkrDefs::cluskey const cluskey = clusIter->first;
0404
0405 TrkrCluster* cluster = clusIter->second;
0406
0407 auto global = tGeometry->getGlobalPosition(cluskey, cluster);
0408 float x, y;
0409 if (isXY)
0410 {
0411 x = global.x();
0412 y = global.y();
0413 }
0414 else
0415 {
0416
0417 x = global.z();
0418 y = std::sqrt(square(global.x()) + square(global.y()));
0419 if (global.y() < 0)
0420 {
0421 y *= -1;
0422 }
0423 }
0424
0425
0426
0427
0428
0429 float const perpSlope = -1 / slope;
0430 float const perpIntercept = y - perpSlope * x;
0431
0432
0433 float const pcax = (perpIntercept - intercept) / (slope - perpSlope);
0434 float const pcay = slope * pcax + intercept;
0435
0436
0437 float const dcax = pcax - x;
0438 float const dcay = pcay - y;
0439 float dca = std::sqrt(square(dcax) + square(dcay));
0440 if (!isXY && TrkrDefs::getTrkrId(cluskey) == TrkrDefs::TrkrId::inttId)
0441 {
0442
0443 dca = dcay;
0444 }
0445 if (dca < dca_cut)
0446 {
0447 keys_to_add.insert(cluskey);
0448 }
0449 }
0450 }
0451 }
0452
0453 for (auto& key : keys_to_add)
0454 {
0455 cluskey_vec.push_back(key);
0456 auto clus = clusterContainer->findCluster(key);
0457 auto global = tGeometry->getGlobalPosition(key, clus);
0458 global_vec.push_back(global);
0459 nclusters++;
0460 }
0461
0462 return nclusters;
0463 }
0464
0465
0466 unsigned int TrackFitUtils::addClusters(std::vector<float>& fitpars,
0467 double dca_cut,
0468 ActsGeometry* _tGeometry,
0469 TrkrClusterContainer* _cluster_map,
0470 std::vector<Acts::Vector3>& global_vec,
0471 std::vector<TrkrDefs::cluskey>& cluskey_vec,
0472 unsigned int startLayer,
0473 unsigned int endLayer)
0474 {
0475
0476
0477
0478 unsigned int nclusters = 0;
0479
0480
0481 std::set<TrkrDefs::cluskey> keysToAdd;
0482 std::set<TrkrDefs::TrkrId> detectors = {TrkrDefs::TrkrId::mvtxId,
0483 TrkrDefs::TrkrId::inttId,
0484 TrkrDefs::TrkrId::tpcId,
0485 TrkrDefs::TrkrId::micromegasId};
0486
0487 if (startLayer > 2)
0488 {
0489 detectors.erase(TrkrDefs::TrkrId::mvtxId);
0490 if (startLayer > 6)
0491 {
0492 detectors.erase(TrkrDefs::TrkrId::inttId);
0493 if (startLayer > 54)
0494 {
0495 detectors.erase(TrkrDefs::TrkrId::tpcId);
0496 }
0497 }
0498 }
0499 if (endLayer < 56)
0500 {
0501 detectors.erase(TrkrDefs::TrkrId::micromegasId);
0502 if (endLayer < 7)
0503 {
0504 detectors.erase(TrkrDefs::TrkrId::tpcId);
0505 if (endLayer < 3)
0506 {
0507 detectors.erase(TrkrDefs::TrkrId::inttId);
0508 }
0509 }
0510 }
0511
0512 for (const auto& det : detectors)
0513 {
0514 for (const auto& hitsetkey : _cluster_map->getHitSetKeys(det))
0515 {
0516 if (TrkrDefs::getLayer(hitsetkey) < startLayer ||
0517 TrkrDefs::getLayer(hitsetkey) > endLayer)
0518 {
0519 continue;
0520 }
0521
0522 auto range = _cluster_map->getClusters(hitsetkey);
0523 for (auto clusIter = range.first; clusIter != range.second; ++clusIter)
0524 {
0525 TrkrDefs::cluskey const cluskey = clusIter->first;
0526
0527 TrkrCluster* cluster = clusIter->second;
0528
0529 auto global = _tGeometry->getGlobalPosition(cluskey, cluster);
0530
0531 Acts::Vector3 pca = get_helix_pca(fitpars, global);
0532 float dca = (pca - global).norm();
0533
0534 Acts::Vector2 const global_xy(global(0), global(1));
0535 Acts::Vector2 const pca_xy(pca(0), pca(1));
0536 Acts::Vector2 const pca_xy_residual = pca_xy - global_xy;
0537 dca = pca_xy_residual.norm();
0538 if (dca < dca_cut)
0539 {
0540 keysToAdd.insert(cluskey);
0541 }
0542 }
0543 }
0544 }
0545
0546 for (auto& key : keysToAdd)
0547 {
0548 cluskey_vec.push_back(key);
0549 auto clus = _cluster_map->findCluster(key);
0550 auto global = _tGeometry->getGlobalPosition(key, clus);
0551 global_vec.push_back(global);
0552 nclusters++;
0553 }
0554
0555 return nclusters;
0556 }
0557
0558
0559 Acts::Vector3 TrackFitUtils::get_helix_pca(std::vector<float>& fitpars,
0560 const Acts::Vector3& global)
0561 {
0562
0563
0564
0565 float const radius = fitpars[0];
0566 float const x0 = fitpars[1];
0567 float const y0 = fitpars[2];
0568 float const zslope = fitpars[3];
0569 float const z0 = fitpars[4];
0570
0571 Acts::Vector2 pca_circle = get_circle_point_pca(radius, x0, y0, global);
0572
0573
0574 float const pca_circle_radius = pca_circle.norm();
0575 float const pca_z = pca_circle_radius * zslope + z0;
0576 Acts::Vector3 const pca(pca_circle(0), pca_circle(1), pca_z);
0577
0578
0579
0580 float const projection = 0.25;
0581 Acts::Vector3 const second_point = pca + projection * pca / pca.norm();
0582 Acts::Vector2 second_point_pca_circle = get_circle_point_pca(radius, x0, y0, second_point);
0583 float const second_point_pca_z = second_point_pca_circle.norm() * zslope + z0;
0584 Acts::Vector3 const second_point_pca(second_point_pca_circle(0), second_point_pca_circle(1), second_point_pca_z);
0585
0586
0587 Acts::Vector3 const tangent = (second_point_pca - pca) / (second_point_pca - pca).norm();
0588
0589
0590 Acts::Vector3 final_pca = getPCALinePoint(global, tangent, pca);
0591
0592 return final_pca;
0593 }
0594
0595
0596 Acts::Vector2 TrackFitUtils::get_circle_point_pca(float radius, float x0, float y0, Acts::Vector3 global)
0597 {
0598
0599
0600
0601
0602 Acts::Vector2 const origin(x0, y0);
0603 Acts::Vector2 const point(global(0), global(1));
0604
0605 Acts::Vector2 pca = origin + radius * (point - origin) / (point - origin).norm();
0606
0607 return pca;
0608 }
0609
0610
0611 std::vector<float> TrackFitUtils::fitClusters(std::vector<Acts::Vector3>& global_vec,
0612 const std::vector<TrkrDefs::cluskey> &cluskey_vec,
0613 bool use_intt)
0614 {
0615 std::vector<float> fitpars;
0616
0617
0618 if (global_vec.size() < 3)
0619 {
0620 return fitpars;
0621 }
0622 std::tuple<double, double, double> circle_fit_pars = TrackFitUtils::circle_fit_by_taubin(global_vec);
0623
0624
0625 std::vector<Acts::Vector3> global_vec_noINTT;
0626 for (unsigned int ivec = 0; ivec < global_vec.size(); ++ivec)
0627 {
0628 unsigned int const trkrid = TrkrDefs::getTrkrId(cluskey_vec[ivec]);
0629
0630 if (trkrid != TrkrDefs::inttId && cluskey_vec[ivec] != 0)
0631 {
0632 global_vec_noINTT.push_back(global_vec[ivec]);
0633 }
0634 }
0635
0636 if (use_intt)
0637 {
0638 global_vec_noINTT = global_vec;
0639 }
0640 if (global_vec_noINTT.size() < 3)
0641 {
0642 return fitpars;
0643 }
0644 std::tuple<double, double> line_fit_pars = TrackFitUtils::line_fit(global_vec_noINTT);
0645
0646 fitpars.push_back(std::get<0>(circle_fit_pars));
0647 fitpars.push_back(std::get<1>(circle_fit_pars));
0648 fitpars.push_back(std::get<2>(circle_fit_pars));
0649 fitpars.push_back(std::get<0>(line_fit_pars));
0650 fitpars.push_back(std::get<1>(line_fit_pars));
0651
0652 return fitpars;
0653 }
0654
0655
0656 std::vector<float> TrackFitUtils::fitClustersZeroField(const std::vector<Acts::Vector3>& global_vec,
0657 const std::vector<TrkrDefs::cluskey>& cluskey_vec, bool use_intt, bool mvtx_east, bool mvtx_west)
0658
0659 {
0660 std::vector<float> fitpars;
0661 std::tuple<double, double> xy_fit_pars;
0662
0663
0664 if (global_vec.size() < 3)
0665 {
0666 std::cout << " TrackFitUtils::fitClustersZeroField failed for <3 cluskeys " << ((int) global_vec.size()) << std::endl;
0667 return fitpars;
0668 }
0669
0670
0671
0672
0673 std::vector<Acts::Vector3> global_vec_noINTT;
0674 bool cross_mvtx_half = false;
0675 if ((mvtx_east || mvtx_west))
0676 {
0677 cross_mvtx_half = TrackFitUtils::isTrackCrossMvtxHalf(cluskey_vec);
0678 }
0679 else
0680 {
0681 xy_fit_pars = TrackFitUtils::line_fit_xy(global_vec);
0682 }
0683 for (unsigned int ivec = 0; ivec < global_vec.size(); ++ivec)
0684 {
0685 unsigned int const trkrid = TrkrDefs::getTrkrId(cluskey_vec[ivec]);
0686 if ((mvtx_east || mvtx_west) && trkrid == TrkrDefs::mvtxId)
0687 {
0688 if (cross_mvtx_half && TrackFitUtils::includeMvtxHit(cluskey_vec[ivec], mvtx_east, mvtx_west))
0689 {
0690 global_vec_noINTT.push_back(global_vec[ivec]);
0691 }
0692 }
0693 else if (trkrid != TrkrDefs::inttId && cluskey_vec[ivec] != 0)
0694 {
0695 global_vec_noINTT.push_back(global_vec[ivec]);
0696 }
0697 }
0698
0699 if (use_intt)
0700 {
0701 global_vec_noINTT = global_vec;
0702 }
0703 if (global_vec_noINTT.size() < 3)
0704 {
0705
0706 return fitpars;
0707 }
0708 std::tuple<double, double> xz_fit_pars = TrackFitUtils::line_fit_xz(global_vec_noINTT);
0709 if ((mvtx_east || mvtx_west))
0710 {
0711 xy_fit_pars = TrackFitUtils::line_fit_xy(global_vec_noINTT);
0712 }
0713
0714 fitpars.push_back(std::get<0>(xy_fit_pars));
0715 fitpars.push_back(std::get<1>(xy_fit_pars));
0716 fitpars.push_back(std::get<0>(xz_fit_pars));
0717 fitpars.push_back(std::get<1>(xz_fit_pars));
0718
0719
0720
0721
0722
0723
0724
0725
0726
0727
0728
0729 return fitpars;
0730 }
0731
0732
0733 void TrackFitUtils::getTrackletClusters(ActsGeometry* _tGeometry,
0734 TrkrClusterContainer* _cluster_map,
0735 std::vector<Acts::Vector3>& global_vec,
0736 const std::vector<TrkrDefs::cluskey>& cluskey_vec)
0737 {
0738 for (unsigned long const key : cluskey_vec)
0739 {
0740 auto cluster = _cluster_map->findCluster(key);
0741 if (!cluster)
0742 {
0743 std::cout << "Failed to get cluster with key " << key << std::endl;
0744 continue;
0745 }
0746
0747 Acts::Vector3 const global = _tGeometry->getGlobalPosition(key, cluster);
0748
0749
0750
0751
0752
0753
0754
0755
0756
0757
0758
0759
0760
0761 global_vec.push_back(global);
0762 }
0763 }
0764
0765
0766 Acts::Vector2 TrackFitUtils::get_line_point_pca(double slope, double intercept, Acts::Vector3 global)
0767 {
0768
0769
0770
0771
0772
0773
0774
0775
0776 const double& m = slope;
0777 const double& b = intercept;
0778 const double& x0 = global(0);
0779 const double& y0 = global(1);
0780 const double xp = (x0 + m * (y0 - b)) / (1 + m * m);
0781 const double yp = m * xp + b;
0782
0783 return {xp, yp};
0784
0785
0786 }
0787
0788 double TrackFitUtils::z_fit_to_pca(const double xy_slope, const double xy_intercept,
0789 const std::vector<Acts::Vector3>& glob_pts)
0790 {
0791
0792
0793
0794
0795 auto pca = get_line_point_pca(xy_slope, xy_intercept, Acts::Vector3(0, 0, 0));
0796 std::vector<std::pair<double, double>> zd_vec;
0797 for (auto& glob : glob_pts)
0798 {
0799 auto point = get_line_point_pca(xy_slope, xy_intercept, glob);
0800 double const dist = sqrt(square(pca.x() - point.x()) + square(pca.y() + point.y()));
0801 zd_vec.emplace_back(dist, glob.z());
0802 }
0803 auto slope_and_b = line_fit(zd_vec);
0804
0805
0806
0807 return std::get<1>(slope_and_b);
0808 }
0809
0810 double TrackFitUtils::line_dist_to_pca(const double slope, const double intercept,
0811 const Acts::Vector2& pca, const Acts::Vector3& global)
0812 {
0813 auto point_on_line = get_line_point_pca(slope, intercept, global);
0814 return sqrt(square(pca.x() - point_on_line.x()) + square(pca.y() - point_on_line.y()));
0815 }
0816
0817
0818 Acts::Vector3 TrackFitUtils::getPCALinePoint(const Acts::Vector3& global, const Acts::Vector3& tangent, const Acts::Vector3& posref)
0819 {
0820
0821
0822
0823
0824 Acts::Vector3 pca = posref + ((global - posref).dot(tangent)) * tangent;
0825
0826
0827
0828
0829
0830
0831
0832
0833
0834 return pca;
0835 }
0836
0837 Acts::Vector3 TrackFitUtils::get_helix_surface_intersection(const Surface& surf,
0838 std::vector<float>& fitpars, Acts::Vector3& global, ActsGeometry* _tGeometry)
0839 {
0840
0841
0842 Acts::Vector3 sensorCenter = surf->center(_tGeometry->geometry().getGeoContext()) * 0.1;
0843 Acts::Vector3 sensorNormal = -surf->normal(_tGeometry->geometry().getGeoContext(), Acts::Vector3(1, 1, 1), Acts::Vector3(1, 1, 1));
0844
0845 sensorNormal /= sensorNormal.norm();
0846
0847
0848
0849 std::pair<Acts::Vector3, Acts::Vector3> const line = get_helix_tangent(fitpars, global);
0850 Acts::Vector3 const pca = line.first;
0851 Acts::Vector3 const tangent = line.second;
0852
0853 Acts::Vector3 intersection = get_line_plane_intersection(pca, tangent, sensorCenter, sensorNormal);
0854
0855 return intersection;
0856 }
0857 Acts::Vector3 TrackFitUtils::get_line_plane_intersection(const Acts::Vector3& pca, const Acts::Vector3& tangent,
0858 const Acts::Vector3& sensorCenter, const Acts::Vector3& sensorNormal)
0859 {
0860
0861
0862
0863
0864
0865
0866
0867
0868 float const d = (sensorCenter - pca).dot(sensorNormal) / tangent.dot(sensorNormal);
0869 return pca + d * tangent;
0870 }
0871 std::vector<double> TrackFitUtils::getLineClusterResiduals(TrackFitUtils::position_vector_t& rz_pts, float slope, float intercept)
0872 {
0873 std::vector<double> residuals;
0874
0875 std::transform(rz_pts.begin(), rz_pts.end(),
0876 std::back_inserter(residuals), [slope, intercept](const std::pair<double, double>& point)
0877 {
0878 double const r = point.first;
0879 double const z = point.second;
0880
0881
0882
0883 double const a = -slope;
0884 double const b = 1.0;
0885 double const c = -intercept;
0886 return std::abs(a*r+b*z+c)/sqrt(square(a)+square(b)); });
0887 return residuals;
0888 }
0889
0890 std::vector<double> TrackFitUtils::getCircleClusterResiduals(TrackFitUtils::position_vector_t& xy_pts, float R, float X0, float Y0)
0891 {
0892 std::vector<double> residuals;
0893 std::transform(xy_pts.begin(), xy_pts.end(),
0894 std::back_inserter(residuals), [R, X0, Y0](const std::pair<double, double>& point)
0895 {
0896 double const x = point.first;
0897 double const y = point.second;
0898
0899
0900 return std::sqrt( square(x-X0) + square(y-Y0) ) - R; });
0901
0902 return residuals;
0903 }
0904
0905 float TrackFitUtils::get_helix_pathlength(std::vector<float>& fitpars, const Acts::Vector3& start_point, const Acts::Vector3& end_point)
0906 {
0907
0908
0909
0910
0911 if (fitpars.size() != 5)
0912 {
0913 return -1e9;
0914 }
0915 float const R = fitpars[0];
0916 float const x0 = fitpars[1];
0917 float const y0 = fitpars[2];
0918 float const zslope = fitpars[3];
0919
0920
0921
0922
0923
0924 float const half_turn_z_pathlength = zslope * 2 * R;
0925
0926
0927 float const z_dist = end_point.z() - start_point.z();
0928 int const n_turns = std::floor(std::fabs(z_dist / half_turn_z_pathlength));
0929
0930
0931 float const phic_start = atan2(start_point.y() - y0, start_point.x() - x0);
0932 float const phic_end = atan2(end_point.y() - y0, end_point.x() - x0);
0933 float const phic_dist = std::fabs(phic_end - phic_start) + n_turns * 2 * M_PI;
0934 float const xy_dist = R * phic_dist;
0935
0936 float const pathlength = std::sqrt(xy_dist * xy_dist + z_dist * z_dist);
0937 return pathlength;
0938 }
0939
0940 float TrackFitUtils::get_helix_surface_pathlength(const Surface& surf, std::vector<float>& fitpars, const Acts::Vector3& start_point, ActsGeometry* tGeometry)
0941 {
0942 Acts::Vector3 surface_center = surf->center(tGeometry->geometry().getGeoContext()) * 0.1;
0943 Acts::Vector3 const intersection = get_helix_surface_intersection(surf, fitpars, surface_center, tGeometry);
0944 return get_helix_pathlength(fitpars, start_point, intersection);
0945 }
0946
0947
0948
0949
0950
0951
0952
0953
0954
0955
0956 std::tuple<bool, double, double, double, Acts::Vector3, Acts::Vector3>
0957 TrackFitUtils::zero_field_track_params(
0958 ActsGeometry* _tGeometry,
0959 TrkrClusterContainer* _cluster_map,
0960 const std::vector<TrkrDefs::cluskey>& cluskey_vec)
0961 {
0962 std::vector<Acts::Vector3> global_vec;
0963
0964
0965 getTrackletClusters(_tGeometry, _cluster_map, global_vec, cluskey_vec);
0966 if (global_vec.size() < 2)
0967 {
0968 return std::make_tuple(false, 0., 0., 0., Acts::Vector3(0., 0., 0), Acts::Vector3(0., 0., 0.));
0969 }
0970
0971
0972 auto params = fitClustersZeroField(global_vec, cluskey_vec, true);
0973 if (params.size() < 4)
0974 {
0975 std::cout << " fit params failed at size : " << ((int) params.size()) << std::endl;
0976 return std::make_tuple(false, 0., 0., 0., Acts::Vector3(0., 0., 0), Acts::Vector3(0., 0., 0.));
0977 }
0978 const double xy_m = params[0];
0979 const double xy_b = params[1];
0980 const double xz_m = params[2];
0981 const double xz_b = params[3];
0982
0983
0984 double x, y, z;
0985
0986
0987 Acts::Vector2 dca_xy = get_line_point_pca(xy_m, xy_b, {0., 0., 0});
0988 x = dca_xy.x();
0989 y = dca_xy.y();
0990
0991 z = xz_m * x + xz_b;
0992
0993
0994 Acts::Vector3 cluster = global_vec.back();
0995 auto clus_dca_xy = get_line_point_pca(xy_m, xy_b, {cluster.x(), cluster.y(), 0});
0996 double px = clus_dca_xy.x();
0997 double py = clus_dca_xy.y();
0998 double pz = xz_m * px + xz_b;
0999
1000
1001 double const alt_z = z_fit_to_pca(xy_m, xy_b, global_vec);
1002 bool const PRINT_DEBUG = false;
1003 if (PRINT_DEBUG)
1004 {
1005 std::cout << " zthis " << z << " and alt "
1006 << alt_z << " DELTA: " << (alt_z - z) << " xy-slope " << xy_m << std::endl;
1007 }
1008 z = alt_z;
1009
1010
1011 px -= x;
1012 py -= y;
1013 pz -= z;
1014
1015
1016 const double scale = sqrt(px * px + py * py) / 5.;
1017 px /= scale;
1018 py /= scale;
1019 pz /= scale;
1020 auto p = Acts::Vector3(px, py, pz);
1021 const double phi = std::atan2(py, px);
1022 const double eta = atanh(pz / p.norm());
1023 if (PRINT_DEBUG)
1024 {
1025 std::cout << "phi: " << phi << " eta: " << eta << " pT: 1" << " x,y,z: " << x << "<" << y << "," << z << " P: " << px << "," << py << "," << pz << std::endl;
1026 }
1027 return std::make_tuple(true, phi, eta, 1, Acts::Vector3(x, y, z), p);
1028 }
1029
1030 bool TrackFitUtils::isTrackCrossMvtxHalf(const std::vector<TrkrDefs::cluskey> &cluskey_vec)
1031 {
1032 bool isWest = false;
1033 bool isEast = false;
1034 for (unsigned long ivec : cluskey_vec)
1035 {
1036 uint32_t const hitsetkey = TrkrDefs::getHitSetKeyFromClusKey(ivec);
1037 unsigned int const layer = TrkrDefs::getLayer(hitsetkey);
1038 unsigned int const stave = MvtxDefs::getStaveId(hitsetkey);
1039 if (stave > (2 + layer) && stave < (9 + layer * 3))
1040 {
1041 isEast = true;
1042 }
1043 else
1044 {
1045 isWest = true;
1046 }
1047 }
1048 if (isEast && isWest)
1049 {
1050 return true;
1051 }
1052 return false;
1053 }
1054
1055 bool TrackFitUtils::includeMvtxHit(TrkrDefs::cluskey clus_key, bool mvtx_east, bool mvtx_west)
1056 {
1057 uint32_t const hitsetkey = TrkrDefs::getHitSetKeyFromClusKey(clus_key);
1058 bool const is_east = isMvtxEast(hitsetkey);
1059 if ((is_east && mvtx_east) || (!is_east && mvtx_west))
1060 {
1061 return true;
1062 }
1063
1064 return false;
1065 }
1066
1067 bool TrackFitUtils::isMvtxEast(uint32_t hitsetkey)
1068 {
1069 unsigned int const layer = TrkrDefs::getLayer(hitsetkey);
1070 unsigned int const stave = MvtxDefs::getStaveId(hitsetkey);
1071 bool is_east = false;
1072 if (stave > (2 + layer) && stave < (9 + layer * 3))
1073 {
1074 is_east = true;
1075 }
1076 return is_east;
1077 }