File indexing completed on 2025-08-05 08:10:02
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "ActsExamples/Io/Root/RootTrackParameterWriter.hpp"
0010
0011 #include "Acts/Definitions/Common.hpp"
0012 #include "Acts/Definitions/TrackParametrization.hpp"
0013 #include "Acts/Utilities/MultiIndex.hpp"
0014 #include "ActsExamples/EventData/AverageSimHits.hpp"
0015 #include "ActsExamples/Framework/AlgorithmContext.hpp"
0016 #include "ActsExamples/Utilities/Range.hpp"
0017 #include "ActsExamples/Validation/TrackClassification.hpp"
0018 #include "ActsFatras/EventData/Barcode.hpp"
0019 #include "ActsFatras/EventData/Hit.hpp"
0020 #include "ActsFatras/EventData/Particle.hpp"
0021
0022 #include <cmath>
0023 #include <cstddef>
0024 #include <ios>
0025 #include <iostream>
0026 #include <memory>
0027 #include <stdexcept>
0028 #include <tuple>
0029 #include <utility>
0030 #include <vector>
0031
0032 #include <TFile.h>
0033 #include <TTree.h>
0034
0035 using Acts::VectorHelpers::eta;
0036 using Acts::VectorHelpers::phi;
0037 using Acts::VectorHelpers::theta;
0038
0039 ActsExamples::RootTrackParameterWriter::RootTrackParameterWriter(
0040 const ActsExamples::RootTrackParameterWriter::Config& config,
0041 Acts::Logging::Level level)
0042 : TrackParameterWriter(config.inputTrackParameters,
0043 "RootTrackParameterWriter", level),
0044 m_cfg(config) {
0045 if (m_cfg.inputProtoTracks.empty()) {
0046 throw std::invalid_argument("Missing proto tracks input collection");
0047 }
0048 if (m_cfg.inputParticles.empty()) {
0049 throw std::invalid_argument("Missing particles input collection");
0050 }
0051 if (m_cfg.inputSimHits.empty()) {
0052 throw std::invalid_argument("Missing simulated hits input collection");
0053 }
0054 if (m_cfg.inputMeasurementParticlesMap.empty()) {
0055 throw std::invalid_argument("Missing hit-particles map input collection");
0056 }
0057 if (m_cfg.inputMeasurementSimHitsMap.empty()) {
0058 throw std::invalid_argument(
0059 "Missing hit-simulated-hits map input collection");
0060 }
0061 if (m_cfg.filePath.empty()) {
0062 throw std::invalid_argument("Missing output filename");
0063 }
0064 if (m_cfg.treeName.empty()) {
0065 throw std::invalid_argument("Missing tree name");
0066 }
0067
0068 m_inputProtoTracks.initialize(m_cfg.inputProtoTracks);
0069 m_inputParticles.initialize(m_cfg.inputParticles);
0070 m_inputSimHits.initialize(m_cfg.inputSimHits);
0071 m_inputMeasurementParticlesMap.initialize(m_cfg.inputMeasurementParticlesMap);
0072 m_inputMeasurementSimHitsMap.initialize(m_cfg.inputMeasurementSimHitsMap);
0073
0074
0075 if (m_outputFile == nullptr) {
0076 auto path = m_cfg.filePath;
0077 m_outputFile = TFile::Open(path.c_str(), m_cfg.fileMode.c_str());
0078 if (m_outputFile == nullptr) {
0079 throw std::ios_base::failure("Could not open '" + path + "'");
0080 }
0081 }
0082 m_outputFile->cd();
0083 m_outputTree = new TTree(m_cfg.treeName.c_str(), m_cfg.treeName.c_str());
0084 if (m_outputTree == nullptr) {
0085 throw std::bad_alloc();
0086 } else {
0087
0088 m_outputTree->Branch("event_nr", &m_eventNr);
0089 m_outputTree->Branch("loc0", &m_loc0);
0090 m_outputTree->Branch("loc1", &m_loc1);
0091 m_outputTree->Branch("phi", &m_phi);
0092 m_outputTree->Branch("theta", &m_theta);
0093 m_outputTree->Branch("qop", &m_qop);
0094 m_outputTree->Branch("time", &m_time);
0095 m_outputTree->Branch("p", &m_p);
0096 m_outputTree->Branch("pt", &m_pt);
0097 m_outputTree->Branch("eta", &m_eta);
0098
0099 m_outputTree->Branch("eventNr", &m_eventNr);
0100 m_outputTree->Branch("t_loc0", &m_t_loc0);
0101 m_outputTree->Branch("t_loc1", &m_t_loc1);
0102 m_outputTree->Branch("t_phi", &m_t_phi);
0103 m_outputTree->Branch("t_theta", &m_t_theta);
0104 m_outputTree->Branch("t_qop", &m_t_qop);
0105 m_outputTree->Branch("t_time", &m_t_time);
0106 m_outputTree->Branch("truthMatched", &m_truthMatched);
0107 }
0108 }
0109
0110 ActsExamples::RootTrackParameterWriter::~RootTrackParameterWriter() {
0111 if (m_outputFile != nullptr) {
0112 m_outputFile->Close();
0113 }
0114 }
0115
0116 ActsExamples::ProcessCode ActsExamples::RootTrackParameterWriter::finalize() {
0117 m_outputFile->cd();
0118 m_outputTree->Write();
0119 m_outputFile->Close();
0120
0121 ACTS_INFO("Wrote estimated parameters from seed to tree '"
0122 << m_cfg.treeName << "' in '" << m_cfg.filePath << "'");
0123
0124 return ProcessCode::SUCCESS;
0125 }
0126
0127 ActsExamples::ProcessCode ActsExamples::RootTrackParameterWriter::writeT(
0128 const ActsExamples::AlgorithmContext& ctx,
0129 const TrackParametersContainer& trackParams) {
0130
0131 const auto& protoTracks = m_inputProtoTracks(ctx);
0132 const auto& particles = m_inputParticles(ctx);
0133 const auto& simHits = m_inputSimHits(ctx);
0134 const auto& hitParticlesMap = m_inputMeasurementParticlesMap(ctx);
0135 const auto& hitSimHitsMap = m_inputMeasurementSimHitsMap(ctx);
0136
0137
0138 std::lock_guard<std::mutex> lock(m_writeMutex);
0139
0140
0141 m_eventNr = ctx.eventNumber;
0142
0143 ACTS_VERBOSE("Writing " << trackParams.size() << " track parameters");
0144
0145
0146 for (std::size_t iparams = 0; iparams < trackParams.size(); ++iparams) {
0147
0148
0149 const auto& surface = trackParams[iparams].referenceSurface();
0150
0151 const auto params = trackParams[iparams].parameters();
0152 m_loc0 = params[Acts::eBoundLoc0];
0153 m_loc1 = params[Acts::eBoundLoc1];
0154 m_phi = params[Acts::eBoundPhi];
0155 m_theta = params[Acts::eBoundTheta];
0156 m_qop = params[Acts::eBoundQOverP];
0157 m_time = params[Acts::eBoundTime];
0158 m_p = std::abs(1.0 / m_qop);
0159 m_pt = m_p * std::sin(m_theta);
0160 m_eta = std::atanh(std::cos(m_theta));
0161
0162
0163 const auto& ptrack = protoTracks[iparams];
0164 std::vector<ParticleHitCount> particleHitCounts;
0165 identifyContributingParticles(hitParticlesMap, ptrack, particleHitCounts);
0166 m_truthMatched = false;
0167 if (particleHitCounts.size() == 1) {
0168 m_truthMatched = true;
0169 }
0170
0171 const auto& hitIdx = ptrack.front();
0172
0173 auto indices = makeRange(hitSimHitsMap.equal_range(hitIdx));
0174 auto [truthLocal, truthPos4, truthUnitDir] =
0175 averageSimHits(ctx.geoContext, surface, simHits, indices, logger());
0176
0177 m_t_loc0 = truthLocal[Acts::ePos0];
0178 m_t_loc1 = truthLocal[Acts::ePos1];
0179 m_t_phi = phi(truthUnitDir);
0180 m_t_theta = theta(truthUnitDir);
0181 m_t_time = truthPos4[Acts::eTime];
0182
0183
0184 if (!indices.empty()) {
0185
0186
0187 const auto simHitIdx0 = indices.begin()->second;
0188 const auto& simHit0 = *simHits.nth(simHitIdx0);
0189 const auto p =
0190 simHit0.momentum4Before().template segment<3>(Acts::eMom0).norm();
0191 const auto& particleId = simHit0.particleId();
0192
0193 auto ip = particles.find(particleId);
0194 if (ip != particles.end()) {
0195 const auto& particle = *ip;
0196 m_t_charge = static_cast<int>(particle.charge());
0197 m_t_qop = m_t_charge / p;
0198 } else {
0199 ACTS_DEBUG("Truth particle with barcode "
0200 << particleId << "=" << particleId.value() << " not found!");
0201 }
0202 }
0203
0204 m_outputTree->Fill();
0205 }
0206
0207 return ProcessCode::SUCCESS;
0208 }