Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
defineReconstructionPerformance.C
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file defineReconstructionPerformance.C
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2021 CERN for the benefit of the Acts project
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 
9 #include <array>
10 #include <iostream>
11 #include <string>
12 #include <tuple>
13 #include <vector>
14 
15 #include <TCanvas.h>
16 #include <TEfficiency.h>
17 #include <TFile.h>
18 
19 #include "CommonUtils.h"
20 #include "TreeReader.h"
21 
36  const std::string& inputSimParticleFileName =
37  "performance_track_finder.root",
38  const std::vector<std::string>& inputTrackSummaryFileNames =
39  {"tracksummary_ckf.root"},
40  const std::vector<std::string>& trackSummaryFileLegends =
41  {"CKF with reco seeds"},
42  const std::string& simParticleTreeName = "track_finder_particles",
43  const std::string& trackSummaryTreeName = "tracksummary_ckf",
44  unsigned int nHitsMin = 9, unsigned int nMeasurementsMin = 6,
45  double ptMin = 0.5, double truthMatchProbMin = 0.5) {
46  gStyle->SetOptFit(0011);
47  gStyle->SetOptStat(0000);
48  gStyle->SetPadLeftMargin(0.18);
49  gStyle->SetPadRightMargin(0.05);
50  gStyle->SetPadTopMargin(0.1);
51  gStyle->SetPadBottomMargin(0.15);
52  gStyle->SetTitleSize(0.05, "xy");
53  gStyle->SetLabelSize(0.05, "xy");
54  gStyle->SetTitleOffset(1., "x");
55  gStyle->SetTitleOffset(1.5, "y");
56  gStyle->SetNdivisions(505, "y");
57 
58  // Check the inputs are valid
59  if (inputTrackSummaryFileNames.size() != trackSummaryFileLegends.size()) {
60  throw std::invalid_argument(
61  "Please specify the legends you want to show for all the track files");
62  }
63 
64  // Open the files for reading
65  TFile* particleFile = TFile::Open(inputSimParticleFileName.c_str(), "read");
66  // The number of track files to read
67  unsigned int nTrackFiles = inputTrackSummaryFileNames.size();
68  std::vector<TFile*> trackFiles;
69  trackFiles.reserve(nTrackFiles);
70  for (const auto& fileName : inputTrackSummaryFileNames) {
71  trackFiles.push_back(TFile::Open(fileName.c_str(), "read"));
72  }
73 
74  // Define variables for tree reading (turn on the events sorting since we have more than one root files to read)
75  ParticleReader pReader(
76  (TTree*)particleFile->Get(simParticleTreeName.c_str()), true);
77  std::vector<TrackSummaryReader> tReaders;
78  tReaders.reserve(nTrackFiles);
79  for (const auto& trackFile : trackFiles) {
80  tReaders.emplace_back((TTree*)trackFile->Get(trackSummaryTreeName.c_str()), true);
81  }
82 
83  std::vector<size_t> nEvents;
84  nEvents.reserve(nTrackFiles);
85  for (const auto& tReader : tReaders) {
86  size_t entries = tReader.tree->GetEntries();
87  nEvents.push_back(entries);
88  }
89 
90  // Define the efficiency plots
91  std::vector<TEfficiency*> trackEff_vs_eta;
92  std::vector<TEfficiency*> fakeRate_vs_eta;
93  std::vector<TEfficiency*> duplicateRate_vs_eta;
94  std::vector<TEfficiency*> trackEff_vs_pt;
95  std::vector<TEfficiency*> fakeRate_vs_pt;
96  std::vector<TEfficiency*> duplicateRate_vs_pt;
97 
98  for (int i = 0; i < nTrackFiles; ++i) {
99  trackEff_vs_eta.push_back(new TEfficiency(
100  Form("trackeff_vs_eta_%i", i), ";Truth #eta [GeV/c];Efficiency", 40, -4, 4));
101  fakeRate_vs_eta.push_back(new TEfficiency(
102  Form("fakerate_vs_eta_%i", i), ";#eta [GeV/c];fake rate", 40, -4, 4));
103  duplicateRate_vs_eta.push_back(new TEfficiency(
104  Form("duplicaterate_vs_eta_%i", i), ";#eta [GeV/c];Duplicate rate", 40, -4, 4));
105  trackEff_vs_pt.push_back(new TEfficiency(
106  Form("trackeff_vs_pt_%i", i), ";Truth pt [GeV/c];Efficiency", 40, 0, 100));
107  fakeRate_vs_pt.push_back(new TEfficiency(
108  Form("fakerate_vs_pt_%i", i), ";pt [GeV/c];fake rate", 40, 0, 100));
109  duplicateRate_vs_pt.push_back(new TEfficiency(
110  Form("duplicaterate_vs_pt_%i", i), ";pt [GeV/c];Duplicate rate", 40, 0, 100));
111  }
112 
113  // Set styles
114  for (int i = 0; i < nTrackFiles; ++i) {
115  auto color = i + 1;
116  setEffStyle(trackEff_vs_eta[i], color);
117  setEffStyle(fakeRate_vs_eta[i], color);
118  setEffStyle(duplicateRate_vs_eta[i], color);
119  setEffStyle(trackEff_vs_pt[i], color);
120  setEffStyle(fakeRate_vs_pt[i], color);
121  setEffStyle(duplicateRate_vs_pt[i], color);
122  }
123 
124  // The particles in each event
125  std::map<unsigned int, std::vector<ParticleInfo>> particles;
126 
127  // Loop over the track files
128  for (unsigned int ifile = 0; ifile < nTrackFiles; ++ifile) {
129  std::cout << "Processing track file: " << inputTrackSummaryFileNames[ifile]
130  << std::endl;
131 
132  // The container from track-particle matching info (Flushed per event)
133  std::map<uint64_t, std::vector<RecoTrackInfo>> matchedParticles;
134 
135  // Loop over the events to fill plots
136  for (size_t i = 0; i < nEvents[ifile]; ++i) {
137  if (i % 10 == 0) {
138  std::cout << "Processed events: " << i << std::endl;
139  }
140 
141  // Get the tracks
142  tReaders[ifile].getEntry(i);
143 
144  // Get the particles (do nothing if the particles for this event already
145  // read)
146  auto it = particles.find(i);
147  if (it == particles.end()) {
148  particles.emplace(i, pReader.getParticles(i));
149  }
150 
151  // Loop over the tracks
152  // The fake rate is defined as the ratio of selected truth-matched tracks
153  // over all selected tracks
154  for (size_t j = 0; j < tReaders[ifile].nStates->size(); ++j) {
155  bool hasFittedParameters = tReaders[ifile].hasFittedParams->at(j);
156  auto nMeasurements = tReaders[ifile].nMeasurements->at(j);
157  auto nOutliers = tReaders[ifile].nOutliers->at(j);
158  auto nHoles = tReaders[ifile].nHoles->at(j);
159  auto theta = tReaders[ifile].eTHETA_fit->at(j);
160  auto qop = tReaders[ifile].eQOP_fit->at(j);
161  auto pt = std::abs(1 / qop) * std::sin(theta);
162  auto eta = std::atanh(std::cos(theta));
163  auto nMajorityHits = tReaders[ifile].nMajorityHits->at(j);
164  auto majorityParticleId = tReaders[ifile].majorityParticleId->at(j);
165 
166  // Select the track, e.g. you might also want to add cuts on the
167  // nOutliers, nHoles
168  if ((!hasFittedParameters) or nMeasurements < nMeasurementsMin or
169  pt < ptMin) {
170  continue;
171  }
172 
173  // Fill the fake rate plots
174  if (nMajorityHits * 1. / nMeasurements >= truthMatchProbMin) {
175  matchedParticles[majorityParticleId].push_back(
176  {eta, pt, nMajorityHits, nMeasurements});
177  fakeRate_vs_eta[ifile]->Fill(false, eta);
178  fakeRate_vs_pt[ifile]->Fill(false, pt);
179  } else {
180  fakeRate_vs_eta[ifile]->Fill(true, eta);
181  fakeRate_vs_pt[ifile]->Fill(true, pt);
182  }
183  } // end of all tracks
184 
185  // Loop over all selected and truth-matched tracks
186  // The duplicate rate is defined as the ratio of duplicate tracks among
187  // all the selected truth-matched tracks (only one track is 'real'; others
188  // are 'duplicated')
189  for (auto& [id, matchedTracks] : matchedParticles) {
190  // Sort all tracks matched to this particle according to majority prob
191  // and track quality
192  std::sort(matchedTracks.begin(), matchedTracks.end(),
193  [](const RecoTrackInfo& lhs, const RecoTrackInfo& rhs) {
194  if (lhs.nMajorityHits > rhs.nMajorityHits) {
195  return true;
196  }
197  if (lhs.nMajorityHits < rhs.nMajorityHits) {
198  return false;
199  }
200  if (lhs.nMeasurements > rhs.nMeasurements) {
201  return true;
202  }
203  return false;
204  });
205  // Fill the duplication rate plots
206  for (size_t k = 0; k < matchedTracks.size(); ++k) {
207  auto eta = matchedTracks[k].eta;
208  auto pt = matchedTracks[k].pt;
209  if (k == 0) {
210  duplicateRate_vs_eta[ifile]->Fill(false, eta);
211  duplicateRate_vs_pt[ifile]->Fill(false, pt);
212  } else {
213  duplicateRate_vs_eta[ifile]->Fill(true, eta);
214  duplicateRate_vs_pt[ifile]->Fill(true, pt);
215  }
216  }
217  } // end of all selected truth-matched tracks
218 
219  // Loop over all truth particles in this event
220  // The efficiency is defined as the ratio of selected particles that have
221  // been matched with reco
222  for (const auto& particle : particles[i]) {
223  auto nHits = particle.nHits;
224  auto eta = particle.eta;
225  auto pt = particle.pt;
226  if (nHits < nHitsMin or pt < ptMin) {
227  continue;
228  }
229  uint64_t id = particle.particleId;
230 
231  // Fill the efficiency plots
232  auto ip = matchedParticles.find(id);
233  if (ip != matchedParticles.end()) {
234  trackEff_vs_eta[ifile]->Fill(true, eta);
235  trackEff_vs_pt[ifile]->Fill(true, pt);
236  } else {
237  trackEff_vs_eta[ifile]->Fill(false, eta);
238  trackEff_vs_pt[ifile]->Fill(false, pt);
239  }
240  } // end of all particles
241 
242  matchedParticles.clear();
243  } // end of all events
244  } // end of all track files
245 
246  std::cout << "All good. Now plotting..." << std::endl;
247 
248  // The legends
249  std::vector<TLegend*> legs;
250  for (int i = 0; i < 6; ++i) {
251  TLegend* legend = new TLegend(0.4, 0.8, 0.9, 0.9);
252  legend->SetBorderSize(0);
253  legend->SetFillStyle(0);
254  legend->SetTextFont(42);
255  legs.push_back(legend);
256  }
257  // Add entry for the legends
258  for (int i = 0; i < nTrackFiles; ++i) {
259  legs[0]->AddEntry(trackEff_vs_eta[i],
260  Form("%s", trackSummaryFileLegends[i].c_str()), "lp");
261  legs[1]->AddEntry(fakeRate_vs_eta[i],
262  Form("%s", trackSummaryFileLegends[i].c_str()), "lp");
263  legs[2]->AddEntry(duplicateRate_vs_eta[i],
264  Form("%s", trackSummaryFileLegends[i].c_str()), "lp");
265  legs[3]->AddEntry(trackEff_vs_pt[i],
266  Form("%s", trackSummaryFileLegends[i].c_str()), "lp");
267  legs[4]->AddEntry(fakeRate_vs_pt[i],
268  Form("%s", trackSummaryFileLegends[i].c_str()), "lp");
269  legs[5]->AddEntry(duplicateRate_vs_pt[i],
270  Form("%s", trackSummaryFileLegends[i].c_str()), "lp");
271  }
272 
273  // Now draw the plots
274  TCanvas* c1 = new TCanvas("recoPerf", " ", 1500, 800);
275  c1->Divide(3, 2);
276 
277  float scaleRangeMax = 1.15;
278  for (int i = 0; i < nTrackFiles; ++i) {
279  std::string mode = (i == 0) ? "" : "same";
280  c1->cd(1);
281  trackEff_vs_eta[i]->Draw(mode.c_str());
282  if (i == nTrackFiles - 1) {
283  legs[0]->Draw();
284  }
285  adaptEffRange(trackEff_vs_eta[i], 1, scaleRangeMax);
286 
287  c1->cd(2);
288  fakeRate_vs_eta[i]->Draw(mode.c_str());
289  if (i == nTrackFiles - 1) {
290  legs[1]->Draw();
291  }
292  adaptEffRange(fakeRate_vs_eta[i], 1, scaleRangeMax);
293 
294  c1->cd(3);
295  duplicateRate_vs_eta[i]->Draw(mode.c_str());
296  if (i == nTrackFiles - 1) {
297  legs[2]->Draw();
298  }
299  adaptEffRange(duplicateRate_vs_eta[i], 1, scaleRangeMax);
300 
301  c1->cd(4);
302  trackEff_vs_pt[i]->Draw(mode.c_str());
303  if (i == nTrackFiles - 1) {
304  legs[3]->Draw();
305  }
306  adaptEffRange(trackEff_vs_pt[i], 1, scaleRangeMax);
307 
308  c1->cd(5);
309  fakeRate_vs_pt[i]->Draw(mode.c_str());
310  if (i == nTrackFiles - 1) {
311  legs[4]->Draw();
312  }
313  adaptEffRange(fakeRate_vs_pt[i], 1, scaleRangeMax);
314 
315  c1->cd(6);
316  duplicateRate_vs_pt[i]->Draw(mode.c_str());
317  if (i == nTrackFiles - 1) {
318  legs[5]->Draw();
319  }
320  adaptEffRange(duplicateRate_vs_pt[i], 1, scaleRangeMax);
321  }
322 
323  c1->Update();
324 }