Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
TrackFitterPerformanceWriter.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file TrackFitterPerformanceWriter.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2019-2020 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 
10 
19 
20 #include <algorithm>
21 #include <cstddef>
22 #include <memory>
23 #include <ostream>
24 #include <stdexcept>
25 #include <utility>
26 #include <vector>
27 
28 #include <TFile.h>
29 
31 
35  : WriterT(config.inputTrajectories, "TrackFitterPerformanceWriter", level),
36  m_cfg(std::move(config)),
37  m_resPlotTool(m_cfg.resPlotToolConfig, level),
38  m_effPlotTool(m_cfg.effPlotToolConfig, level),
39  m_trackSummaryPlotTool(m_cfg.trackSummaryPlotToolConfig, level)
40 
41 {
42  // trajectories collection name is already checked by base ctor
43  if (m_cfg.inputParticles.empty()) {
44  throw std::invalid_argument("Missing particles input collection");
45  }
46  if (m_cfg.inputMeasurementParticlesMap.empty()) {
47  throw std::invalid_argument("Missing hit-particles map input collection");
48  }
49  if (m_cfg.filePath.empty()) {
50  throw std::invalid_argument("Missing output filename");
51  }
52 
55 
56  // the output file can not be given externally since TFile accesses to the
57  // same file from multiple threads are unsafe.
58  // must always be opened internally
59  auto path = m_cfg.filePath;
60  m_outputFile = TFile::Open(path.c_str(), "RECREATE");
61  if (m_outputFile == nullptr) {
62  throw std::invalid_argument("Could not open '" + path + "'");
63  }
64 
65  // initialize the residual and efficiency plots tool
69 }
70 
72  m_resPlotTool.clear(m_resPlotCache);
73  m_effPlotTool.clear(m_effPlotCache);
74  m_trackSummaryPlotTool.clear(m_trackSummaryPlotCache);
75 
76  if (m_outputFile != nullptr) {
77  m_outputFile->Close();
78  }
79 }
80 
83  // fill residual and pull details into additional hists
84  m_resPlotTool.refinement(m_resPlotCache);
85 
86  if (m_outputFile != nullptr) {
87  m_outputFile->cd();
88  m_resPlotTool.write(m_resPlotCache);
89  m_effPlotTool.write(m_effPlotCache);
90  m_trackSummaryPlotTool.write(m_trackSummaryPlotCache);
91 
92  ACTS_INFO("Wrote performance plots to '" << m_outputFile->GetPath() << "'");
93  }
94  return ProcessCode::SUCCESS;
95 }
96 
98  const AlgorithmContext& ctx, const TrajectoriesContainer& trajectories) {
99  // Read truth input collections
100  const auto& particles = m_inputParticles(ctx);
101  const auto& hitParticlesMap = m_inputMeasurementParticlesMap(ctx);
102 
103  // Truth particles with corresponding reconstructed tracks
104  std::vector<ActsFatras::Barcode> reconParticleIds;
105  reconParticleIds.reserve(particles.size());
106  // For each particle within a track, how many hits did it contribute
107  std::vector<ParticleHitCount> particleHitCounts;
108 
109  // Exclusive access to the tree while writing
110  std::lock_guard<std::mutex> lock(m_writeMutex);
111 
112  // Loop over all trajectories
113  for (size_t itraj = 0; itraj < trajectories.size(); ++itraj) {
114  const auto& traj = trajectories[itraj];
115 
116  // The trajectory entry indices and the multiTrajectory
117  const auto& trackTips = traj.tips();
118  const auto& mj = traj.multiTrajectory();
119 
120  if (trackTips.empty()) {
121  ACTS_WARNING("No trajectory found for entry " << itraj);
122  continue;
123  }
124 
125  // Check the size of the trajectory entry indices. For track fitting, there
126  // should be at most one trajectory
127  if (trackTips.size() > 1) {
128  ACTS_ERROR("Track fitting should not result in multiple trajectories.");
129  return ProcessCode::ABORT;
130  }
131  // Get the entry index for the single trajectory
132  auto trackTip = trackTips.front();
133 
134  // Select reco track with fitted parameters
135  if (not traj.hasTrackParameters(trackTip)) {
136  ACTS_WARNING("No fitted track parameters.");
137  continue;
138  }
139  const auto& fittedParameters = traj.trackParameters(trackTip);
140 
141  // Get the majority truth particle for this trajectory
142  identifyContributingParticles(hitParticlesMap, traj, trackTip,
143  particleHitCounts);
144  if (particleHitCounts.empty()) {
145  ACTS_WARNING("No truth particle associated with this trajectory.");
146  continue;
147  }
148  // Find the truth particle for the majority barcode
149  const auto ip = particles.find(particleHitCounts.front().particleId);
150  if (ip == particles.end()) {
151  ACTS_WARNING("Majority particle not found in the particles collection.");
152  continue;
153  }
154 
155  // Record this majority particle ID of this trajectory
156  reconParticleIds.push_back(ip->particleId());
157  // Fill the residual plots
158  m_resPlotTool.fill(m_resPlotCache, ctx.geoContext, *ip,
159  traj.trackParameters(trackTip));
160  // Collect the trajectory summary info
161  auto trajState =
163  // Fill the trajectory summary info
164  m_trackSummaryPlotTool.fill(m_trackSummaryPlotCache, fittedParameters,
165  trajState.nStates, trajState.nMeasurements,
166  trajState.nOutliers, trajState.nHoles,
167  trajState.nSharedHits);
168  }
169 
170  // Fill the efficiency, defined as the ratio between number of tracks with
171  // fitted parameter and total truth tracks (assumes one truth partilce has
172  // one truth track)
173  for (const auto& particle : particles) {
174  bool isReconstructed = false;
175  // Find if the particle has been reconstructed
176  auto it = std::find(reconParticleIds.begin(), reconParticleIds.end(),
177  particle.particleId());
178  if (it != reconParticleIds.end()) {
179  isReconstructed = true;
180  }
181  m_effPlotTool.fill(m_effPlotCache, particle, isReconstructed);
182  }
183 
184  return ProcessCode::SUCCESS;
185 }