File indexing completed on 2025-08-06 08:22:00
0001 #include "MvtxStandaloneTracking.h"
0002
0003 #include <trackbase/TrkrClusterContainer.h>
0004 #include <trackbase/TrkrClusterv1.h>
0005 #include <trackbase/TrkrDefs.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, "TRKR_CLUSTER");
0049 if (!clusters_)
0050 {
0051 std::cout << PHWHERE << "ERROR: Can't find node TRKR_CLUSTER" << 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
0092
0093
0094
0095 TrkrClusterContainer::ConstRange clusrange0 =
0096 clusters_->getClusters(TrkrDefs::TrkrId::mvtxId, 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::mvtxId, 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(), mzy);
0121
0122
0123 TrkrClusterContainer::ConstRange clusrange2 =
0124 clusters_->getClusters(TrkrDefs::TrkrId::mvtxId, 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 bool found_clu3 = false;
0145 TrkrClusterContainer::ConstRange clusrange3 =
0146 clusters_->getClusters(TrkrDefs::TrkrId::mvtxId, lyrs.at(3));
0147 for ( TrkrClusterContainer::ConstIterator iter3 = clusrange3.first;
0148 iter3 != clusrange3.second;
0149 ++iter3)
0150 {
0151
0152
0153 if ( fabs((iter3->second)->getX() - CalcProjection((iter3->second)->getY(), mxy, bxy)) < window_x_ &&
0154 fabs((iter3->second)->getZ() - CalcProjection((iter3->second)->getY(), mzy, bzy)) < window_z_ )
0155 {
0156 found_clu3 = true;
0157 MvtxTrack tmp_trk = trk;
0158 (tmp_trk.ClusterList).push_back(iter3->second);
0159 trklst.push_back(tmp_trk);
0160 }
0161 }
0162 if ( !found_clu3 ) trklst.push_back(trk);
0163 }
0164 else
0165 {
0166
0167 trklst.push_back(trk);
0168 }
0169 }
0170 }
0171 }
0172 }
0173
0174 }
0175
0176
0177 void
0178 MvtxStandaloneTracking::RunGhostRejection(MvtxTrackList &trklst)
0179 {
0180 if ( verbosity_ > 0 )
0181 std::cout << PHWHERE << " Running Ghost Rejection on "
0182 << trklst.size() << " tracks" << std::endl;
0183
0184
0185 std::multimap<TrkrDefs::cluskey, unsigned int> key_trk_map;
0186
0187 for (unsigned int itrk = 0; itrk < trklst.size(); itrk++)
0188 {
0189 for (unsigned int iclus = 0; iclus < trklst.at(itrk).ClusterList.size(); iclus++)
0190 {
0191 TrkrDefs::cluskey ckey = trklst.at(itrk).ClusterList.at(iclus)->getClusKey();
0192 key_trk_map.insert(std::make_pair(ckey, itrk));
0193 }
0194 }
0195
0196
0197 std::set<unsigned int> remove_set;
0198 for ( auto iter = key_trk_map.begin(); iter != key_trk_map.end(); ++iter)
0199 {
0200 int ntrk = key_trk_map.count(iter->first);
0201 if ( ntrk > 1 )
0202 {
0203 if ( verbosity_ > 1 )
0204 {
0205 std::cout << PHWHERE << " Tracks sharing cluster:" << ntrk << std::endl;
0206 }
0207
0208
0209 auto upiter = key_trk_map.upper_bound(iter->first);
0210
0211
0212 double chi2_best = 9999.;
0213 unsigned int idx_best = 0;
0214 int ntrk = 0;
0215 for ( auto jter = iter; jter != upiter; ++jter)
0216 {
0217 ntrk++;
0218 double chi2 = trklst.at(jter->second).chi2_xy + trklst.at(jter->second).chi2_zy;
0219 if ( chi2 < chi2_best && chi2 > 0 )
0220 {
0221 chi2_best = chi2;
0222 idx_best = jter->second;
0223 }
0224 }
0225
0226 for ( auto jter = iter; jter != upiter; ++jter)
0227 {
0228 if ( verbosity_ > 1 )
0229 {
0230 double chi2 = trklst.at(jter->second).chi2_xy + trklst.at(jter->second).chi2_zy;
0231 std::cout << " "
0232 << " trk idx: " << jter->second
0233 << " chi2:" << chi2
0234 << " m_xy:" << trklst.at(jter->second).m_xy;
0235
0236 if ( jter->second == idx_best)
0237 {
0238 std::cout << " <--- BEST" << std::endl;
0239 }
0240 else
0241 {
0242 std::cout << std::endl;
0243 }
0244 }
0245
0246 if ( jter->second != idx_best )
0247 {
0248 remove_set.insert(jter->second);
0249 }
0250 }
0251 }
0252
0253 }
0254
0255
0256
0257
0258 if ( verbosity_ > 0 )
0259 {
0260 std::cout << PHWHERE << " List of idx to remove:";
0261 for ( auto it = remove_set.begin(); it != remove_set.end(); ++it)
0262 {
0263 std::cout << " " << *it;
0264 }
0265 std::cout << std::endl;
0266 }
0267
0268
0269 for ( auto rit = remove_set.rbegin(); rit != remove_set.rend(); ++rit)
0270 trklst.erase(trklst.begin() + *rit);
0271
0272
0273
0274 if ( verbosity_ > 1 )
0275 {
0276 std::cout << PHWHERE << " Remaining tracks:" << std::endl;
0277 for ( unsigned int i = 0; i < trklst.size(); i++)
0278 {
0279 double chi2 = trklst.at(i).chi2_xy + trklst.at(i).chi2_zy;
0280 std::cout << " chi2:" << chi2 << " m_xy:" << trklst.at(i).m_xy << std::endl;
0281 }
0282 }
0283
0284 return;
0285 }
0286
0287
0288 TVectorD
0289 MvtxStandaloneTracking::SolveGLS(TMatrixD &X, TVectorD &y, TMatrixD &L)
0290 {
0291
0292
0293
0294
0295
0296 TMatrixD XT(X); XT.T();
0297 TMatrixD A = XT * L * X;
0298 TVectorD b = XT * L * y;
0299
0300
0301 TDecompSVD svd(A);
0302 TMatrixD UT = svd.GetU(); UT.T();
0303
0304
0305 TVectorD s = svd.GetSig();
0306 TMatrixD Sd(s.GetNrows(), s.GetNrows());
0307 for (int i = 0; i < s.GetNrows(); i++)
0308 Sd(i, i) = s(i) > 0 ? 1. / s(i) : 0.;
0309
0310 TVectorD beta = svd.GetV() * Sd * UT * b;
0311
0312 return beta;
0313 }
0314
0315 void
0316 MvtxStandaloneTracking::TrackFitXY(MvtxTrack &trk)
0317 {
0318
0319
0320
0321
0322
0323 int m = (trk.ClusterList).size(), n = 2;
0324
0325 TMatrixD X(m, n);
0326 TMatrixD Cinv(m, m);
0327 TVectorD y(m);
0328 TVectorD x(m);
0329
0330 for (int iclus = 0; iclus < m; iclus++)
0331 {
0332 TrkrCluster *clus = (trk.ClusterList).at(iclus);
0333
0334 x(iclus) = clus->getX();
0335 y(iclus) = clus->getY();
0336
0337 X(iclus, 0) = 1;
0338 X(iclus, 1) = y(iclus);
0339
0340 Cinv(iclus, iclus) = 2.0 * sqrt(clus->getSize(0, 0));
0341 }
0342
0343 TVectorD beta = SolveGLS(X, x, Cinv);
0344 double x0 = beta(0), c = beta(1);
0345
0346 trk.m_xy = c;
0347 trk.b_xy = x0;
0348
0349 double chi2 = 0;
0350 for (int iclus = 0; iclus < m; iclus++)
0351 {
0352 TrkrCluster *clus = (trk.ClusterList).at(iclus);
0353
0354 double cx = clus->getX();
0355 double cy = clus->getY();
0356
0357 double px = cy * c + x0;
0358
0359 double dx = cx - px;
0360 trk.dx.push_back(dx);
0361
0362 chi2 += pow(dx, 2) / clus->getError(0, 0);
0363 }
0364 chi2 /= double(m - 2);
0365 trk.chi2_xy = chi2;
0366
0367 return;
0368 }
0369
0370 void
0371 MvtxStandaloneTracking::TrackFitZY(MvtxTrack &trk)
0372 {
0373
0374
0375
0376
0377
0378 int m = (trk.ClusterList).size(), n = 2;
0379
0380 TMatrixD X(m, n);
0381 TMatrixD Cinv(m, m);
0382 TVectorD y(m);
0383 TVectorD z(m);
0384
0385 for (int iclus = 0; iclus < m; iclus++)
0386 {
0387 TrkrCluster *clus = (trk.ClusterList).at(iclus);
0388
0389 z(iclus) = clus->getZ();
0390 y(iclus) = clus->getY();
0391
0392 X(iclus, 0) = 1;
0393 X(iclus, 1) = y(iclus);
0394
0395 Cinv(iclus, iclus) = 2.0 * sqrt(clus->getSize(2, 2));
0396 }
0397
0398 TVectorD beta = SolveGLS(X, z, Cinv);
0399 double z0 = beta(0), c = beta(1);
0400
0401 trk.m_zy = c;
0402 trk.b_zy = z0;
0403
0404 double chi2 = 0;
0405 for (int iclus = 0; iclus < m; iclus++)
0406 {
0407 TrkrCluster *clus = (trk.ClusterList).at(iclus);
0408
0409 double cz = clus->getZ();
0410 double cy = clus->getY();
0411
0412 double pz = cy * c + z0;
0413
0414 double dz = cz - pz;
0415 trk.dz.push_back(dz);
0416
0417 chi2 += pow(dz, 2) / clus->getError(2, 2);
0418 }
0419 chi2 /= double(m - 2);
0420 trk.chi2_zy = chi2;
0421
0422 return;
0423 }
0424
0425 void
0426 MvtxStandaloneTracking::PrintTrackCandidates(MvtxTrackList &trklst)
0427 {
0428 std::cout << "===================================================" << std::endl;
0429 std::cout << "== " << PHWHERE << " Found " << trklst.size() << " Track Candidates" << std::endl;
0430 std::cout << "===================================================" << std::endl;
0431 for ( unsigned int i = 0; i < trklst.size(); i++)
0432 {
0433 std::cout << "== " << i << std::endl;
0434 for ( unsigned int j = 0; j < trklst.at(i).ClusterList.size(); j++)
0435 {
0436 std::cout << " clus " << j
0437 << " key:0x" << std::hex << trklst.at(i).ClusterList.at(j)->getClusKey() << std::dec
0438 << " (" << trklst.at(i).ClusterList.at(j)->getX()
0439 << ", " << trklst.at(i).ClusterList.at(j)->getY()
0440 << ", " << trklst.at(i).ClusterList.at(j)->getZ()
0441 << ")"
0442 << " dx:" << trklst.at(i).dx.at(j)
0443 << " dz:" << trklst.at(i).dz.at(j)
0444 << std::endl;
0445 }
0446 std::cout << " xy"
0447 << " m:" << trklst.at(i).m_xy
0448 << " b:" << trklst.at(i).b_xy
0449 << " chi2:" << trklst.at(i).chi2_xy
0450 << std::endl;
0451 std::cout << " zy"
0452 << " m:" << trklst.at(i).m_zy
0453 << " b:" << trklst.at(i).b_zy
0454 << " chi2:" << trklst.at(i).chi2_zy
0455 << std::endl;
0456 }
0457 std::cout << "===================================================" << std::endl;
0458 }
0459
0460 double
0461 MvtxStandaloneTracking::CalcSlope(double x0, double y0, double x1, double y1)
0462 {
0463 return (y1 - y0) / (x1 - x0);
0464 }
0465
0466 double
0467 MvtxStandaloneTracking::CalcIntecept(double x0, double y0, double m)
0468 {
0469 return y0 - x0 * m;
0470 }
0471
0472 double
0473 MvtxStandaloneTracking::CalcProjection(double x, double m, double b)
0474 {
0475 return m * x + b;
0476 }
0477