File indexing completed on 2025-12-17 09:12:31
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <array>
0010 #include <iostream>
0011 #include <string>
0012 #include <tuple>
0013 #include <vector>
0014
0015 #include <TCanvas.h>
0016 #include <TEfficiency.h>
0017 #include <TFile.h>
0018
0019 #include "CommonUtils.h"
0020 #include "TreeReader.h"
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035 void defineReconstructionPerformance(
0036 const std::string& inputSimParticleFileName =
0037 "performance_track_finder.root",
0038 const std::vector<std::string>& inputTrackSummaryFileNames =
0039 {"tracksummary_ckf.root"},
0040 const std::vector<std::string>& trackSummaryFileLegends =
0041 {"CKF with reco seeds"},
0042 const std::string& simParticleTreeName = "track_finder_particles",
0043 const std::string& trackSummaryTreeName = "tracksummary_ckf",
0044 unsigned int nHitsMin = 9, unsigned int nMeasurementsMin = 6,
0045 double ptMin = 0.5, double truthMatchProbMin = 0.5) {
0046 gStyle->SetOptFit(0011);
0047 gStyle->SetOptStat(0000);
0048 gStyle->SetPadLeftMargin(0.18);
0049 gStyle->SetPadRightMargin(0.05);
0050 gStyle->SetPadTopMargin(0.1);
0051 gStyle->SetPadBottomMargin(0.15);
0052 gStyle->SetTitleSize(0.05, "xy");
0053 gStyle->SetLabelSize(0.05, "xy");
0054 gStyle->SetTitleOffset(1., "x");
0055 gStyle->SetTitleOffset(1.5, "y");
0056 gStyle->SetNdivisions(505, "y");
0057
0058
0059 if (inputTrackSummaryFileNames.size() != trackSummaryFileLegends.size()) {
0060 throw std::invalid_argument(
0061 "Please specify the legends you want to show for all the track files");
0062 }
0063
0064
0065 TFile* particleFile = TFile::Open(inputSimParticleFileName.c_str(), "read");
0066
0067 unsigned int nTrackFiles = inputTrackSummaryFileNames.size();
0068 std::vector<TFile*> trackFiles;
0069 trackFiles.reserve(nTrackFiles);
0070 for (const auto& fileName : inputTrackSummaryFileNames) {
0071 trackFiles.push_back(TFile::Open(fileName.c_str(), "read"));
0072 }
0073
0074
0075 ParticleReader pReader(
0076 (TTree*)particleFile->Get(simParticleTreeName.c_str()), true);
0077 std::vector<TrackSummaryReader> tReaders;
0078 tReaders.reserve(nTrackFiles);
0079 for (const auto& trackFile : trackFiles) {
0080 tReaders.emplace_back((TTree*)trackFile->Get(trackSummaryTreeName.c_str()), true);
0081 }
0082
0083 std::vector<std::size_t> nEvents;
0084 nEvents.reserve(nTrackFiles);
0085 for (const auto& tReader : tReaders) {
0086 std::size_t entries = tReader.tree->GetEntries();
0087 nEvents.push_back(entries);
0088 }
0089
0090
0091 std::vector<TEfficiency*> trackEff_vs_eta;
0092 std::vector<TEfficiency*> fakeRate_vs_eta;
0093 std::vector<TEfficiency*> duplicateRate_vs_eta;
0094 std::vector<TEfficiency*> trackEff_vs_pt;
0095 std::vector<TEfficiency*> fakeRate_vs_pt;
0096 std::vector<TEfficiency*> duplicateRate_vs_pt;
0097
0098 for (int i = 0; i < nTrackFiles; ++i) {
0099 trackEff_vs_eta.push_back(new TEfficiency(
0100 Form("trackeff_vs_eta_%i", i), ";Truth #eta [GeV/c];Efficiency", 40, -4, 4));
0101 fakeRate_vs_eta.push_back(new TEfficiency(
0102 Form("fakerate_vs_eta_%i", i), ";#eta [GeV/c];fake rate", 40, -4, 4));
0103 duplicateRate_vs_eta.push_back(new TEfficiency(
0104 Form("duplicaterate_vs_eta_%i", i), ";#eta [GeV/c];Duplicate rate", 40, -4, 4));
0105 trackEff_vs_pt.push_back(new TEfficiency(
0106 Form("trackeff_vs_pt_%i", i), ";Truth pt [GeV/c];Efficiency", 40, 0, 100));
0107 fakeRate_vs_pt.push_back(new TEfficiency(
0108 Form("fakerate_vs_pt_%i", i), ";pt [GeV/c];fake rate", 40, 0, 100));
0109 duplicateRate_vs_pt.push_back(new TEfficiency(
0110 Form("duplicaterate_vs_pt_%i", i), ";pt [GeV/c];Duplicate rate", 40, 0, 100));
0111 }
0112
0113
0114 for (int i = 0; i < nTrackFiles; ++i) {
0115 auto color = i + 1;
0116 setEffStyle(trackEff_vs_eta[i], color);
0117 setEffStyle(fakeRate_vs_eta[i], color);
0118 setEffStyle(duplicateRate_vs_eta[i], color);
0119 setEffStyle(trackEff_vs_pt[i], color);
0120 setEffStyle(fakeRate_vs_pt[i], color);
0121 setEffStyle(duplicateRate_vs_pt[i], color);
0122 }
0123
0124
0125 std::map<unsigned int, std::vector<ParticleInfo>> particles;
0126
0127
0128 for (unsigned int ifile = 0; ifile < nTrackFiles; ++ifile) {
0129 std::cout << "Processing track file: " << inputTrackSummaryFileNames[ifile]
0130 << std::endl;
0131
0132
0133 std::map<uint64_t, std::vector<RecoTrackInfo>> matchedParticles;
0134
0135
0136 for (std::size_t i = 0; i < nEvents[ifile]; ++i) {
0137 if (i % 10 == 0) {
0138 std::cout << "Processed events: " << i << std::endl;
0139 }
0140
0141
0142 tReaders[ifile].getEntry(i);
0143
0144
0145
0146 auto it = particles.find(i);
0147 if (it == particles.end()) {
0148 particles.emplace(i, pReader.getParticles(i));
0149 }
0150
0151
0152
0153
0154 for (std::size_t j = 0; j < tReaders[ifile].nStates->size(); ++j) {
0155 bool hasFittedParameters = tReaders[ifile].hasFittedParams->at(j);
0156 auto nMeasurements = tReaders[ifile].nMeasurements->at(j);
0157 auto nOutliers = tReaders[ifile].nOutliers->at(j);
0158 auto nHoles = tReaders[ifile].nHoles->at(j);
0159 auto theta = tReaders[ifile].eTHETA_fit->at(j);
0160 auto qop = tReaders[ifile].eQOP_fit->at(j);
0161 auto pt = std::abs(1 / qop) * std::sin(theta);
0162 auto eta = std::atanh(std::cos(theta));
0163 auto nMajorityHits = tReaders[ifile].nMajorityHits->at(j);
0164 auto majorityParticleId = tReaders[ifile].majorityParticleId->at(j);
0165
0166
0167
0168 if ((!hasFittedParameters) or nMeasurements < nMeasurementsMin or
0169 pt < ptMin) {
0170 continue;
0171 }
0172
0173
0174 if (nMajorityHits * 1. / nMeasurements >= truthMatchProbMin) {
0175 matchedParticles[majorityParticleId].push_back(
0176 {eta, pt, nMajorityHits, nMeasurements});
0177 fakeRate_vs_eta[ifile]->Fill(false, eta);
0178 fakeRate_vs_pt[ifile]->Fill(false, pt);
0179 } else {
0180 fakeRate_vs_eta[ifile]->Fill(true, eta);
0181 fakeRate_vs_pt[ifile]->Fill(true, pt);
0182 }
0183 }
0184
0185
0186
0187
0188
0189 for (auto& [id, matchedTracks] : matchedParticles) {
0190
0191
0192 std::sort(matchedTracks.begin(), matchedTracks.end(),
0193 [](const RecoTrackInfo& lhs, const RecoTrackInfo& rhs) {
0194 if (lhs.nMajorityHits > rhs.nMajorityHits) {
0195 return true;
0196 }
0197 if (lhs.nMajorityHits < rhs.nMajorityHits) {
0198 return false;
0199 }
0200 if (lhs.nMeasurements > rhs.nMeasurements) {
0201 return true;
0202 }
0203 return false;
0204 });
0205
0206 for (std::size_t k = 0; k < matchedTracks.size(); ++k) {
0207 auto eta = matchedTracks[k].eta;
0208 auto pt = matchedTracks[k].pt;
0209 if (k == 0) {
0210 duplicateRate_vs_eta[ifile]->Fill(false, eta);
0211 duplicateRate_vs_pt[ifile]->Fill(false, pt);
0212 } else {
0213 duplicateRate_vs_eta[ifile]->Fill(true, eta);
0214 duplicateRate_vs_pt[ifile]->Fill(true, pt);
0215 }
0216 }
0217 }
0218
0219
0220
0221
0222 for (const auto& particle : particles[i]) {
0223 auto nHits = particle.nHits;
0224 auto eta = particle.eta;
0225 auto pt = particle.pt;
0226 if (nHits < nHitsMin or pt < ptMin) {
0227 continue;
0228 }
0229 uint64_t id = particle.particleId;
0230
0231
0232 auto ip = matchedParticles.find(id);
0233 if (ip != matchedParticles.end()) {
0234 trackEff_vs_eta[ifile]->Fill(true, eta);
0235 trackEff_vs_pt[ifile]->Fill(true, pt);
0236 } else {
0237 trackEff_vs_eta[ifile]->Fill(false, eta);
0238 trackEff_vs_pt[ifile]->Fill(false, pt);
0239 }
0240 }
0241
0242 matchedParticles.clear();
0243 }
0244 }
0245
0246 std::cout << "All good. Now plotting..." << std::endl;
0247
0248
0249 std::vector<TLegend*> legs;
0250 for (int i = 0; i < 6; ++i) {
0251 TLegend* legend = new TLegend(0.4, 0.8, 0.9, 0.9);
0252 legend->SetBorderSize(0);
0253 legend->SetFillStyle(0);
0254 legend->SetTextFont(42);
0255 legs.push_back(legend);
0256 }
0257
0258 for (int i = 0; i < nTrackFiles; ++i) {
0259 legs[0]->AddEntry(trackEff_vs_eta[i],
0260 Form("%s", trackSummaryFileLegends[i].c_str()), "lp");
0261 legs[1]->AddEntry(fakeRate_vs_eta[i],
0262 Form("%s", trackSummaryFileLegends[i].c_str()), "lp");
0263 legs[2]->AddEntry(duplicateRate_vs_eta[i],
0264 Form("%s", trackSummaryFileLegends[i].c_str()), "lp");
0265 legs[3]->AddEntry(trackEff_vs_pt[i],
0266 Form("%s", trackSummaryFileLegends[i].c_str()), "lp");
0267 legs[4]->AddEntry(fakeRate_vs_pt[i],
0268 Form("%s", trackSummaryFileLegends[i].c_str()), "lp");
0269 legs[5]->AddEntry(duplicateRate_vs_pt[i],
0270 Form("%s", trackSummaryFileLegends[i].c_str()), "lp");
0271 }
0272
0273
0274 TCanvas* c1 = new TCanvas("recoPerf", " ", 1500, 800);
0275 c1->Divide(3, 2);
0276
0277 float scaleRangeMax = 1.15;
0278 for (int i = 0; i < nTrackFiles; ++i) {
0279 std::string mode = (i == 0) ? "" : "same";
0280 c1->cd(1);
0281 trackEff_vs_eta[i]->Draw(mode.c_str());
0282 if (i == nTrackFiles - 1) {
0283 legs[0]->Draw();
0284 }
0285 adaptEffRange(trackEff_vs_eta[i], 1, scaleRangeMax);
0286
0287 c1->cd(2);
0288 fakeRate_vs_eta[i]->Draw(mode.c_str());
0289 if (i == nTrackFiles - 1) {
0290 legs[1]->Draw();
0291 }
0292 adaptEffRange(fakeRate_vs_eta[i], 1, scaleRangeMax);
0293
0294 c1->cd(3);
0295 duplicateRate_vs_eta[i]->Draw(mode.c_str());
0296 if (i == nTrackFiles - 1) {
0297 legs[2]->Draw();
0298 }
0299 adaptEffRange(duplicateRate_vs_eta[i], 1, scaleRangeMax);
0300
0301 c1->cd(4);
0302 trackEff_vs_pt[i]->Draw(mode.c_str());
0303 if (i == nTrackFiles - 1) {
0304 legs[3]->Draw();
0305 }
0306 adaptEffRange(trackEff_vs_pt[i], 1, scaleRangeMax);
0307
0308 c1->cd(5);
0309 fakeRate_vs_pt[i]->Draw(mode.c_str());
0310 if (i == nTrackFiles - 1) {
0311 legs[4]->Draw();
0312 }
0313 adaptEffRange(fakeRate_vs_pt[i], 1, scaleRangeMax);
0314
0315 c1->cd(6);
0316 duplicateRate_vs_pt[i]->Draw(mode.c_str());
0317 if (i == nTrackFiles - 1) {
0318 legs[5]->Draw();
0319 }
0320 adaptEffRange(duplicateRate_vs_pt[i], 1, scaleRangeMax);
0321 }
0322
0323 c1->Update();
0324 }