Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
RootTrackParameterWriter.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file RootTrackParameterWriter.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2017-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 
10 
21 
22 #include <cmath>
23 #include <cstddef>
24 #include <ios>
25 #include <iostream>
26 #include <memory>
27 #include <stdexcept>
28 #include <tuple>
29 #include <utility>
30 #include <vector>
31 
32 #include <TFile.h>
33 #include <TTree.h>
34 
38 
42  : TrackParameterWriter(config.inputTrackParameters,
43  "RootTrackParameterWriter", level),
44  m_cfg(config) {
45  if (m_cfg.inputProtoTracks.empty()) {
46  throw std::invalid_argument("Missing proto tracks input collection");
47  }
48  if (m_cfg.inputParticles.empty()) {
49  throw std::invalid_argument("Missing particles input collection");
50  }
51  if (m_cfg.inputSimHits.empty()) {
52  throw std::invalid_argument("Missing simulated hits input collection");
53  }
54  if (m_cfg.inputMeasurementParticlesMap.empty()) {
55  throw std::invalid_argument("Missing hit-particles map input collection");
56  }
57  if (m_cfg.inputMeasurementSimHitsMap.empty()) {
58  throw std::invalid_argument(
59  "Missing hit-simulated-hits map input collection");
60  }
61  if (m_cfg.filePath.empty()) {
62  throw std::invalid_argument("Missing output filename");
63  }
64  if (m_cfg.treeName.empty()) {
65  throw std::invalid_argument("Missing tree name");
66  }
67 
73 
74  // Setup ROOT I/O
75  if (m_outputFile == nullptr) {
76  auto path = m_cfg.filePath;
77  m_outputFile = TFile::Open(path.c_str(), m_cfg.fileMode.c_str());
78  if (m_outputFile == nullptr) {
79  throw std::ios_base::failure("Could not open '" + path);
80  }
81  }
82  m_outputFile->cd();
83  m_outputTree = new TTree(m_cfg.treeName.c_str(), m_cfg.treeName.c_str());
84  if (m_outputTree == nullptr) {
85  throw std::bad_alloc();
86  } else {
87  // The estimated track parameters
88  m_outputTree->Branch("event_nr", &m_eventNr);
89  m_outputTree->Branch("loc0", &m_loc0);
90  m_outputTree->Branch("loc1", &m_loc1);
91  m_outputTree->Branch("phi", &m_phi);
92  m_outputTree->Branch("theta", &m_theta);
93  m_outputTree->Branch("qop", &m_qop);
94  m_outputTree->Branch("time", &m_time);
95  m_outputTree->Branch("p", &m_p);
96  m_outputTree->Branch("pt", &m_pt);
97  m_outputTree->Branch("eta", &m_eta);
98  // The truth track parameters
99  m_outputTree->Branch("eventNr", &m_eventNr);
100  m_outputTree->Branch("t_loc0", &m_t_loc0);
101  m_outputTree->Branch("t_loc1", &m_t_loc1);
102  m_outputTree->Branch("t_phi", &m_t_phi);
103  m_outputTree->Branch("t_theta", &m_t_theta);
104  m_outputTree->Branch("t_qop", &m_t_qop);
105  m_outputTree->Branch("t_time", &m_t_time);
106  m_outputTree->Branch("truthMatched", &m_truthMatched);
107  }
108 }
109 
111  if (m_outputFile != nullptr) {
112  m_outputFile->Close();
113  }
114 }
115 
117  m_outputFile->cd();
118  m_outputTree->Write();
119  m_outputFile->Close();
120 
121  ACTS_INFO("Wrote estimated parameters from seed to tree '"
122  << m_cfg.treeName << "' in '" << m_cfg.filePath << "'");
123 
124  return ProcessCode::SUCCESS;
125 }
126 
129  const TrackParametersContainer& trackParams) {
130  // Read additional input collections
131  const auto& protoTracks = m_inputProtoTracks(ctx);
132  const auto& particles = m_inputParticles(ctx);
133  const auto& simHits = m_inputSimHits(ctx);
134  const auto& hitParticlesMap = m_inputMeasurementParticlesMap(ctx);
135  const auto& hitSimHitsMap = m_inputMeasurementSimHitsMap(ctx);
136 
137  // Exclusive access to the tree while writing
138  std::lock_guard<std::mutex> lock(m_writeMutex);
139 
140  // Get the event number
141  m_eventNr = ctx.eventNumber;
142 
143  ACTS_VERBOSE("Writing " << trackParams.size() << " track parameters");
144 
145  // Loop over the estimated track parameters
146  for (size_t iparams = 0; iparams < trackParams.size(); ++iparams) {
147  // The reference surface of the parameters, i.e. also the reference surface
148  // of the first space point
149  const auto& surface = trackParams[iparams].referenceSurface();
150  // The estimated bound parameters vector
151  const auto params = trackParams[iparams].parameters();
152  m_loc0 = params[Acts::eBoundLoc0];
153  m_loc1 = params[Acts::eBoundLoc1];
154  m_phi = params[Acts::eBoundPhi];
155  m_theta = params[Acts::eBoundTheta];
156  m_qop = params[Acts::eBoundQOverP];
157  m_time = params[Acts::eBoundTime];
158  m_p = std::abs(1.0 / m_qop);
159  m_pt = m_p * std::sin(m_theta);
160  m_eta = std::atanh(std::cos(m_theta));
161 
162  // Get the proto track from which the track parameters are estimated
163  const auto& ptrack = protoTracks[iparams];
164  std::vector<ParticleHitCount> particleHitCounts;
165  identifyContributingParticles(hitParticlesMap, ptrack, particleHitCounts);
166  m_truthMatched = false;
167  if (particleHitCounts.size() == 1) {
168  m_truthMatched = true;
169  }
170  // Get the index of the first space point
171  const auto& hitIdx = ptrack.front();
172  // Get the sim hits via the measurement to sim hits map
173  auto indices = makeRange(hitSimHitsMap.equal_range(hitIdx));
174  auto [truthLocal, truthPos4, truthUnitDir] =
175  averageSimHits(ctx.geoContext, surface, simHits, indices, logger());
176  // Get the truth track parameter at the first space point
177  m_t_loc0 = truthLocal[Acts::ePos0];
178  m_t_loc1 = truthLocal[Acts::ePos1];
179  m_t_phi = phi(truthUnitDir);
180  m_t_theta = theta(truthUnitDir);
181  m_t_time = truthPos4[Acts::eTime];
182  // momentum averaging makes even less sense than averaging position and
183  // direction. use the first momentum or set q/p to zero
184  if (not indices.empty()) {
185  // we assume that the indices are within valid ranges so we do not
186  // need to check their validity again.
187  const auto simHitIdx0 = indices.begin()->second;
188  const auto& simHit0 = *simHits.nth(simHitIdx0);
189  const auto p =
190  simHit0.momentum4Before().template segment<3>(Acts::eMom0).norm();
191  const auto& particleId = simHit0.particleId();
192  // The truth charge has to be retrieved from the sim particle
193  auto ip = particles.find(particleId);
194  if (ip != particles.end()) {
195  const auto& particle = *ip;
196  m_t_charge = static_cast<int>(particle.charge());
197  m_t_qop = m_t_charge / p;
198  } else {
199  ACTS_DEBUG("Truth particle with barcode "
200  << particleId << "=" << particleId.value() << " not found!");
201  }
202  }
203 
204  m_outputTree->Fill();
205  }
206 
207  return ProcessCode::SUCCESS;
208 }