File indexing completed on 2025-08-06 08:21:59
0001 #include "MvtxStandaloneTracking.h"
0002
0003 #include <trackbase/TrkrClusterContainer.h>
0004 #include <trackbase/TrkrClusterv1.h>
0005 #include <trackbase/TrkrDefUtil.h>
0006
0007 #include <phool/PHCompositeNode.h>
0008 #include <phool/PHIODataNode.h>
0009 #include <phool/PHNodeIterator.h>
0010 #include <phool/getClass.h>
0011
0012 #include <TDecompSVD.h>
0013 #include <TMath.h>
0014
0015 #include <iostream>
0016 #include <utility>
0017 #include <stdio.h>
0018 #include <map>
0019
0020 MvtxStandaloneTracking::MvtxStandaloneTracking()
0021 : window_x_(10)
0022 , window_z_(10)
0023 , ghostrejection_(false)
0024 , verbosity_(0)
0025 {
0026
0027 }
0028
0029 MvtxStandaloneTracking::~MvtxStandaloneTracking()
0030 {
0031 }
0032
0033 void
0034 MvtxStandaloneTracking::RunTracking(PHCompositeNode* topNode, MvtxTrackList &trklst, std::vector<int> &lyrs)
0035 {
0036
0037 if ( lyrs.size() < 3 || lyrs.size() > 4 )
0038 {
0039 std::cout << PHWHERE << "ERROR: Inappropriate number of input layers - " << lyrs.size() << std::endl;
0040 return;
0041 }
0042
0043 trklst.clear();
0044
0045
0046
0047
0048 clusters_ = findNode::getClass<TrkrClusterContainer>(topNode, "TrkrClusterContainer");
0049 if (!clusters_)
0050 {
0051 std::cout << PHWHERE << "ERROR: Can't find node TrkrClusterContainer" << std::endl;
0052 return;
0053 }
0054
0055
0056
0057
0058
0059 AssociateClusters(trklst, lyrs);
0060
0061 if ( verbosity_ > 0 )
0062 std::cout << PHWHERE << " Finished associating clusters. N candidates:" << trklst.size() << std::endl;
0063
0064
0065
0066 for ( unsigned int itrk = 0; itrk < trklst.size(); itrk++)
0067 {
0068 TrackFitXY(trklst.at(itrk));
0069 TrackFitZY(trklst.at(itrk));
0070 }
0071
0072 if ( verbosity_ > 1 )
0073 PrintTrackCandidates(trklst);
0074
0075
0076
0077
0078
0079 if ( ghostrejection_ && trklst.size() > 1 )
0080 RunGhostRejection(trklst);
0081
0082
0083 return;
0084 }
0085
0086 void
0087 MvtxStandaloneTracking::AssociateClusters(MvtxTrackList &trklst, std::vector<int> &lyrs)
0088 {
0089
0090
0091 TrkrDefUtil util;
0092
0093
0094
0095 TrkrClusterContainer::ConstRange clusrange0 =
0096 clusters_->GetClusters(TrkrDefs::TRKRID::mvtx_id, lyrs.at(0));
0097 for ( TrkrClusterContainer::ConstIterator iter0 = clusrange0.first;
0098 iter0 != clusrange0.second;
0099 ++iter0)
0100 {
0101
0102
0103 TrkrClusterContainer::ConstRange clusrange1 =
0104 clusters_->GetClusters(TrkrDefs::TRKRID::mvtx_id, lyrs.at(1));
0105 for ( TrkrClusterContainer::ConstIterator iter1 = clusrange1.first;
0106 iter1 != clusrange1.second;
0107 ++iter1)
0108 {
0109
0110
0111 TrkrCluster* clus0 = iter0->second;
0112 TrkrCluster* clus1 = iter1->second;
0113
0114
0115 double mxy = CalcSlope(clus0->GetY(), clus0->GetX(), clus1->GetY(), clus1->GetX());
0116 double bxy = CalcIntecept(clus0->GetY(), clus0->GetX(), mxy);
0117
0118
0119 double mzy = CalcSlope(clus0->GetY(), clus0->GetZ(), clus1->GetY(), clus1->GetZ());
0120 double bzy = CalcIntecept(clus0->GetY(), clus0->GetZ(), mxy);
0121
0122
0123 TrkrClusterContainer::ConstRange clusrange2 =
0124 clusters_->GetClusters(TrkrDefs::TRKRID::mvtx_id, lyrs.at(2));
0125 for ( TrkrClusterContainer::ConstIterator iter2 = clusrange2.first;
0126 iter2 != clusrange2.second;
0127 ++iter2)
0128 {
0129
0130
0131 if ( fabs((iter2->second)->GetX() - CalcProjection((iter2->second)->GetY(), mxy, bxy)) < window_x_ &&
0132 fabs((iter2->second)->GetZ() - CalcProjection((iter2->second)->GetY(), mzy, bzy)) < window_z_ )
0133 {
0134
0135
0136 MvtxTrack trk;
0137 (trk.ClusterList).push_back(iter0->second);
0138 (trk.ClusterList).push_back(iter1->second);
0139 (trk.ClusterList).push_back(iter2->second);
0140
0141
0142 if ( lyrs.size() > 3 )
0143 {
0144 TrkrClusterContainer::ConstRange clusrange3 =
0145 clusters_->GetClusters(TrkrDefs::TRKRID::mvtx_id, lyrs.at(3));
0146 for ( TrkrClusterContainer::ConstIterator iter3 = clusrange3.first;
0147 iter3 != clusrange3.second;
0148 ++iter3)
0149 {
0150
0151
0152 if ( fabs((iter3->second)->GetX() - CalcProjection((iter3->second)->GetY(), mxy, bxy)) < window_x_ &&
0153 fabs((iter3->second)->GetZ() - CalcProjection((iter3->second)->GetY(), mzy, bzy)) < window_z_ )
0154 {
0155
0156 (trk.ClusterList).push_back(iter3->second);
0157 trklst.push_back(trk);
0158 }
0159 }
0160 }
0161
0162 else
0163 {
0164 trklst.push_back(trk);
0165 }
0166
0167 }
0168 }
0169 }
0170 }
0171
0172 }
0173
0174
0175 void
0176 MvtxStandaloneTracking::RunGhostRejection(MvtxTrackList &trklst)
0177 {
0178 if ( verbosity_ > 0 )
0179 std::cout << PHWHERE << " Running Ghost Rejection on "
0180 << trklst.size() << " tracks" << std::endl;
0181
0182
0183 std::multimap<TrkrDefs::cluskey, unsigned int> key_trk_map;
0184
0185 for (unsigned int itrk = 0; itrk < trklst.size(); itrk++)
0186 {
0187 for (unsigned int iclus = 0; iclus < trklst.at(itrk).ClusterList.size(); iclus++)
0188 {
0189 TrkrDefs::cluskey ckey = trklst.at(itrk).ClusterList.at(iclus)->GetClusKey();
0190 key_trk_map.insert(std::make_pair(ckey, itrk));
0191 }
0192 }
0193
0194
0195 std::set<unsigned int> remove_set;
0196 for ( auto iter = key_trk_map.begin(); iter != key_trk_map.end(); ++iter)
0197 {
0198
0199 auto upiter = key_trk_map.upper_bound(iter->first);
0200
0201
0202 double chi2_best = 9999.;
0203 unsigned int idx_best = 0;
0204 int ntrk = 0;
0205 for ( auto jter = iter; jter != upiter; ++jter)
0206 {
0207 ntrk++;
0208 double chi2 = trklst.at(jter->second).chi2_xy + trklst.at(jter->second).chi2_zy;
0209 if ( chi2 < chi2_best && chi2 > 0 )
0210 {
0211 chi2_best = chi2;
0212 idx_best = jter->second;
0213 }
0214 }
0215
0216
0217 if ( ntrk > 1 && verbosity_ > 1 )
0218 {
0219 std::cout << PHWHERE << " Tracks sharing cluster:" << ntrk << std::endl;
0220 for ( auto jter = iter; jter != upiter; ++jter)
0221 {
0222 double chi2 = trklst.at(jter->second).chi2_xy + trklst.at(jter->second).chi2_zy;
0223 std::cout << " "
0224 << " trk idx: " << jter->second
0225 << " chi2:" << chi2
0226 << " m_xy:" << trklst.at(jter->second).m_xy;
0227
0228 if ( jter->second == idx_best)
0229 {
0230 std::cout << " <--- BEST" << std::endl;
0231 }
0232 else
0233 {
0234 std::cout << std::endl;
0235 }
0236 }
0237 }
0238
0239
0240 for ( auto jter = iter; jter != upiter; ++jter)
0241 {
0242 if ( jter->second != idx_best )
0243 {
0244 remove_set.insert(jter->second);
0245 }
0246 }
0247 }
0248
0249
0250
0251
0252 if ( verbosity_ > 0 )
0253 {
0254 std::cout << PHWHERE << " List of idx to remove:";
0255 for ( auto it = remove_set.begin(); it != remove_set.end(); ++it)
0256 {
0257 std::cout << " " << *it;
0258 }
0259 std::cout << std::endl;
0260 }
0261
0262
0263 for ( auto rit = remove_set.rbegin(); rit != remove_set.rend(); ++rit)
0264 trklst.erase(trklst.begin() + *rit);
0265
0266
0267
0268 if ( verbosity_ > 1 )
0269 {
0270 std::cout << PHWHERE << " Remaining tracks:" << std::endl;
0271 for ( unsigned int i = 0; i < trklst.size(); i++)
0272 {
0273 double chi2 = trklst.at(i).chi2_xy + trklst.at(i).chi2_zy;
0274 std::cout << " chi2:" << chi2 << " m_xy:" << trklst.at(i).m_xy << std::endl;
0275 }
0276 }
0277
0278 return;
0279 }
0280
0281
0282 TVectorD
0283 MvtxStandaloneTracking::SolveGLS(TMatrixD &X, TVectorD &y, TMatrixD &L)
0284 {
0285
0286
0287
0288
0289
0290 TMatrixD XT(X); XT.T();
0291 TMatrixD A = XT * L * X;
0292 TVectorD b = XT * L * y;
0293
0294
0295 TDecompSVD svd(A);
0296 TMatrixD UT = svd.GetU(); UT.T();
0297
0298
0299 TVectorD s = svd.GetSig();
0300 TMatrixD Sd(s.GetNrows(), s.GetNrows());
0301 for (int i = 0; i < s.GetNrows(); i++)
0302 Sd(i, i) = s(i) > 0 ? 1. / s(i) : 0.;
0303
0304 TVectorD beta = svd.GetV() * Sd * UT * b;
0305
0306 return beta;
0307 }
0308
0309 void
0310 MvtxStandaloneTracking::TrackFitXY(MvtxTrack &trk)
0311 {
0312
0313
0314
0315
0316
0317 int m = (trk.ClusterList).size(), n = 2;
0318
0319 TMatrixD X(m, n);
0320 TMatrixD Cinv(m, m);
0321 TVectorD y(m);
0322 TVectorD x(m);
0323
0324 for (int iclus = 0; iclus < m; iclus++)
0325 {
0326 TrkrCluster *clus = (trk.ClusterList).at(iclus);
0327
0328 x(iclus) = clus->GetX();
0329 y(iclus) = clus->GetY();
0330
0331 X(iclus, 0) = 1;
0332 X(iclus, 1) = y(iclus);
0333
0334 Cinv(iclus, iclus) = 2.0 * sqrt(clus->GetSize(0, 0));
0335 }
0336
0337 TVectorD beta = SolveGLS(X, x, Cinv);
0338 double x0 = beta(0), c = beta(1);
0339
0340 trk.m_xy = c;
0341 trk.b_xy = x0;
0342
0343 double chi2 = 0;
0344 for (int iclus = 0; iclus < m; iclus++)
0345 {
0346 TrkrCluster *clus = (trk.ClusterList).at(iclus);
0347
0348 double cx = clus->GetX();
0349 double cy = clus->GetY();
0350
0351 double px = cy * c + x0;
0352
0353 double dx = cx - px;
0354 trk.dx.push_back(dx);
0355
0356 chi2 += pow(dx, 2) / clus->GetError(0, 0);
0357 }
0358 chi2 /= double(m - 2);
0359 trk.chi2_xy = chi2;
0360
0361 return;
0362 }
0363
0364 void
0365 MvtxStandaloneTracking::TrackFitZY(MvtxTrack &trk)
0366 {
0367
0368
0369
0370
0371
0372 int m = (trk.ClusterList).size(), n = 2;
0373
0374 TMatrixD X(m, n);
0375 TMatrixD Cinv(m, m);
0376 TVectorD y(m);
0377 TVectorD z(m);
0378
0379 for (int iclus = 0; iclus < m; iclus++)
0380 {
0381 TrkrCluster *clus = (trk.ClusterList).at(iclus);
0382
0383 z(iclus) = clus->GetZ();
0384 y(iclus) = clus->GetY();
0385
0386 X(iclus, 0) = 1;
0387 X(iclus, 1) = y(iclus);
0388
0389 Cinv(iclus, iclus) = 2.0 * sqrt(clus->GetSize(2, 2));
0390 }
0391
0392 TVectorD beta = SolveGLS(X, z, Cinv);
0393 double z0 = beta(0), c = beta(1);
0394
0395 trk.m_zy = c;
0396 trk.b_zy = z0;
0397
0398 double chi2 = 0;
0399 for (int iclus = 0; iclus < m; iclus++)
0400 {
0401 TrkrCluster *clus = (trk.ClusterList).at(iclus);
0402
0403 double cz = clus->GetZ();
0404 double cy = clus->GetY();
0405
0406 double pz = cy * c + z0;
0407
0408 double dz = cz - pz;
0409 trk.dz.push_back(dz);
0410
0411 chi2 += pow(dz, 2) / clus->GetError(2, 2);
0412 }
0413 chi2 /= double(m - 2);
0414 trk.chi2_zy = chi2;
0415
0416 return;
0417 }
0418
0419 void
0420 MvtxStandaloneTracking::PrintTrackCandidates(MvtxTrackList &trklst)
0421 {
0422 std::cout << "===================================================" << std::endl;
0423 std::cout << "== " << PHWHERE << " Found " << trklst.size() << " Track Candidates" << std::endl;
0424 std::cout << "===================================================" << std::endl;
0425 for ( unsigned int i = 0; i < trklst.size(); i++)
0426 {
0427 std::cout << "== " << i << std::endl;
0428 for ( unsigned int j = 0; j < trklst.at(i).ClusterList.size(); j++)
0429 {
0430 std::cout << " clus " << j
0431 << " key:0x" << std::hex << trklst.at(i).ClusterList.at(j)->GetClusKey() << std::dec
0432 << " (" << trklst.at(i).ClusterList.at(j)->GetX()
0433 << ", " << trklst.at(i).ClusterList.at(j)->GetY()
0434 << ", " << trklst.at(i).ClusterList.at(j)->GetZ()
0435 << ")"
0436 << " dx:" << trklst.at(i).dx.at(j)
0437 << " dz:" << trklst.at(i).dz.at(j)
0438 << std::endl;
0439 }
0440 std::cout << " xy"
0441 << " m:" << trklst.at(i).m_xy
0442 << " b:" << trklst.at(i).b_xy
0443 << " chi2:" << trklst.at(i).chi2_xy
0444 << std::endl;
0445 std::cout << " zy"
0446 << " m:" << trklst.at(i).m_zy
0447 << " b:" << trklst.at(i).b_zy
0448 << " chi2:" << trklst.at(i).chi2_zy
0449 << std::endl;
0450 }
0451 std::cout << "===================================================" << std::endl;
0452 }
0453
0454 double
0455 MvtxStandaloneTracking::CalcSlope(double x0, double y0, double x1, double y1)
0456 {
0457 return (y1 - y0) / (x1 - x0);
0458 }
0459
0460 double
0461 MvtxStandaloneTracking::CalcIntecept(double x0, double y0, double m)
0462 {
0463 return y0 - x0 * m;
0464 }
0465
0466 double
0467 MvtxStandaloneTracking::CalcProjection(double x, double m, double b)
0468 {
0469 return m * x + b;
0470 }
0471