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