File indexing completed on 2025-01-18 09:11:59
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "ActsExamples/Io/Root/TrackFinderNTupleWriter.hpp"
0010
0011 #include "Acts/Definitions/Units.hpp"
0012 #include "ActsExamples/EventData/Measurement.hpp"
0013 #include "ActsExamples/EventData/SimParticle.hpp"
0014 #include "ActsExamples/EventData/TruthMatching.hpp"
0015 #include "ActsExamples/Framework/AlgorithmContext.hpp"
0016 #include "ActsExamples/Framework/DataHandle.hpp"
0017 #include "ActsExamples/Utilities/Range.hpp"
0018 #include "ActsExamples/Validation/TrackClassification.hpp"
0019 #include "ActsFatras/EventData/Barcode.hpp"
0020
0021 #include <cstddef>
0022 #include <cstdint>
0023 #include <mutex>
0024 #include <stdexcept>
0025 #include <unordered_map>
0026 #include <utility>
0027 #include <vector>
0028
0029 #include <RtypesCore.h>
0030 #include <TFile.h>
0031 #include <TTree.h>
0032
0033 namespace ActsExamples {
0034
0035 struct TrackFinderNTupleWriter::Impl {
0036 Config cfg;
0037
0038 ReadDataHandle<SimParticleContainer> inputParticles;
0039 ReadDataHandle<ParticleMeasurementsMap> inputParticleMeasurementsMap;
0040 ReadDataHandle<TrackParticleMatching> inputTrackParticleMatching;
0041
0042 TFile* file = nullptr;
0043
0044
0045 TTree* trkTree = nullptr;
0046 std::mutex trkMutex;
0047
0048 ULong64_t trkEventId = 0;
0049 ULong64_t trkTrackId = 0;
0050
0051
0052 UShort_t trkNumHits = 0;
0053
0054 UShort_t trkNumParticles = 0;
0055
0056 std::vector<ULong64_t> trkParticleId;
0057
0058 std::vector<UShort_t> trkParticleNumHitsTotal;
0059
0060 std::vector<UShort_t> trkParticleNumHitsOnTrack;
0061
0062
0063 TTree* prtTree = nullptr;
0064 std::mutex prtMutex;
0065
0066 ULong64_t prtEventId = 0;
0067 ULong64_t prtParticleId = 0;
0068 Int_t prtParticleType = 0;
0069
0070
0071 float prtVx = 0, prtVy = 0, prtVz = 0;
0072
0073 float prtVt = 0;
0074
0075 float prtPx = 0, prtPy = 0, prtPz = 0;
0076
0077 float prtM = 0;
0078
0079 float prtQ = 0;
0080
0081 UShort_t prtNumMeasurements = 0;
0082 UShort_t prtNumTracks =
0083 0;
0084 UShort_t prtNumTracksMajority =
0085 0;
0086
0087 const Acts::Logger& _logger;
0088
0089 Impl(TrackFinderNTupleWriter* parent, Config&& c, const Acts::Logger& l)
0090 : cfg(std::move(c)),
0091 inputParticles{parent, "InputParticles"},
0092 inputParticleMeasurementsMap{parent, "InputParticleMeasurementsMap"},
0093 inputTrackParticleMatching{parent, "InputTrackParticleMatching"},
0094 _logger(l) {
0095 if (cfg.inputTracks.empty()) {
0096 throw std::invalid_argument("Missing track input collection");
0097 }
0098 if (cfg.inputParticles.empty()) {
0099 throw std::invalid_argument("Missing particles input collection");
0100 }
0101 if (cfg.inputParticleMeasurementsMap.empty()) {
0102 throw std::invalid_argument(
0103 "Missing particle-measurements map input collection");
0104 }
0105 if (cfg.inputTrackParticleMatching.empty()) {
0106 throw std::invalid_argument(
0107 "Missing proto track-particle matching input collection");
0108 }
0109 if (cfg.filePath.empty()) {
0110 throw std::invalid_argument("Missing output filename");
0111 }
0112
0113 inputParticles.initialize(cfg.inputParticles);
0114 inputParticleMeasurementsMap.initialize(cfg.inputParticleMeasurementsMap);
0115 inputTrackParticleMatching.initialize(cfg.inputTrackParticleMatching);
0116
0117
0118
0119
0120 file = TFile::Open(cfg.filePath.c_str(), cfg.fileMode.c_str());
0121 if (file == nullptr) {
0122 throw std::invalid_argument("Could not open '" + cfg.filePath + "'");
0123 }
0124
0125
0126 trkTree = new TTree(cfg.treeNameTracks.c_str(), cfg.treeNameTracks.c_str());
0127 trkTree->SetDirectory(file);
0128 trkTree->Branch("event_id", &trkEventId);
0129 trkTree->Branch("track_id", &trkTrackId);
0130 trkTree->Branch("size", &trkNumHits);
0131 trkTree->Branch("nparticles", &trkNumParticles);
0132 trkTree->Branch("particle_id", &trkParticleId);
0133 trkTree->Branch("particle_nhits_total", &trkParticleNumHitsTotal);
0134 trkTree->Branch("particle_nhits_on_track", &trkParticleNumHitsOnTrack);
0135 prtTree =
0136 new TTree(cfg.treeNameParticles.c_str(), cfg.treeNameParticles.c_str());
0137 prtTree->SetDirectory(file);
0138 prtTree->Branch("event_id", &prtEventId);
0139 prtTree->Branch("particle_id", &prtParticleId);
0140 prtTree->Branch("particle_type", &prtParticleType);
0141 prtTree->Branch("vx", &prtVx);
0142 prtTree->Branch("vy", &prtVy);
0143 prtTree->Branch("vz", &prtVz);
0144 prtTree->Branch("vt", &prtVt);
0145 prtTree->Branch("px", &prtPx);
0146 prtTree->Branch("py", &prtPy);
0147 prtTree->Branch("pz", &prtPz);
0148 prtTree->Branch("m", &prtM);
0149 prtTree->Branch("q", &prtQ);
0150 prtTree->Branch("nhits", &prtNumMeasurements);
0151 prtTree->Branch("ntracks", &prtNumTracks);
0152 prtTree->Branch("ntracks_majority", &prtNumTracksMajority);
0153 }
0154
0155 const Acts::Logger& logger() const { return _logger; }
0156
0157 void write(std::uint64_t eventId, const ConstTrackContainer& tracks,
0158 const SimParticleContainer& particles,
0159 const ParticleMeasurementsMap& particleMeasurementsMap,
0160 const TrackParticleMatching& trackParticleMatching) {
0161
0162 std::unordered_map<ActsFatras::Barcode, std::size_t> reconCount;
0163 reconCount.reserve(particles.size());
0164
0165 std::unordered_map<ActsFatras::Barcode, std::size_t> majorityCount;
0166 majorityCount.reserve(particles.size());
0167
0168
0169 {
0170 std::lock_guard<std::mutex> guardTrk(trkMutex);
0171 for (auto track : tracks) {
0172
0173 auto imatched = trackParticleMatching.find(track.index());
0174 if (imatched == trackParticleMatching.end()) {
0175 ACTS_DEBUG(
0176 "No truth particle associated with this proto track, index = "
0177 << track.index());
0178 continue;
0179 }
0180 const auto& particleMatch = imatched->second;
0181
0182 if (particleMatch.particle.has_value()) {
0183 SimBarcode majorityParticleId = particleMatch.particle.value();
0184
0185 auto it = majorityCount.try_emplace(majorityParticleId, 0u).first;
0186 it->second += 1;
0187
0188
0189 if (auto ip = particles.find(majorityParticleId);
0190 ip == particles.end()) {
0191 ACTS_WARNING(
0192 "Majority particle not found in the particles collection.");
0193 }
0194 }
0195
0196 for (const auto& hc : particleMatch.contributingParticles) {
0197 auto it = reconCount.try_emplace(hc.particleId, 0u).first;
0198 it->second += 1;
0199 }
0200
0201 trkEventId = eventId;
0202 trkTrackId = track.index();
0203 trkNumHits = track.nMeasurements();
0204 trkNumParticles = particleMatch.contributingParticles.size();
0205 trkParticleId.clear();
0206 trkParticleNumHitsTotal.clear();
0207 trkParticleNumHitsOnTrack.clear();
0208 for (const auto& phc : particleMatch.contributingParticles) {
0209 trkParticleId.push_back(phc.particleId.value());
0210
0211 auto trueParticleHits = makeRange(
0212 particleMeasurementsMap.equal_range(phc.particleId.value()));
0213 trkParticleNumHitsTotal.push_back(trueParticleHits.size());
0214 trkParticleNumHitsOnTrack.push_back(phc.hitCount);
0215 }
0216
0217 trkTree->Fill();
0218 }
0219 }
0220
0221
0222 {
0223 std::lock_guard<std::mutex> guardPrt(trkMutex);
0224 for (const auto& particle : particles) {
0225
0226 auto measurements = makeRange(
0227 particleMeasurementsMap.equal_range(particle.particleId()));
0228
0229
0230 prtEventId = eventId;
0231 prtParticleId = particle.particleId().value();
0232 prtParticleType = particle.pdg();
0233
0234 prtVx = particle.position().x() / Acts::UnitConstants::mm;
0235 prtVy = particle.position().y() / Acts::UnitConstants::mm;
0236 prtVz = particle.position().z() / Acts::UnitConstants::mm;
0237 prtVt = particle.time() / Acts::UnitConstants::mm;
0238 const auto p = particle.absoluteMomentum() / Acts::UnitConstants::GeV;
0239 prtPx = p * particle.direction().x();
0240 prtPy = p * particle.direction().y();
0241 prtPz = p * particle.direction().z();
0242 prtM = particle.mass() / Acts::UnitConstants::GeV;
0243 prtQ = particle.charge() / Acts::UnitConstants::e;
0244
0245 prtNumMeasurements = measurements.size();
0246 auto nt = reconCount.find(particle.particleId());
0247 prtNumTracks = (nt != reconCount.end()) ? nt->second : 0u;
0248 auto nm = majorityCount.find(particle.particleId());
0249 prtNumTracksMajority = (nm != majorityCount.end()) ? nm->second : 0u;
0250
0251 prtTree->Fill();
0252 }
0253 }
0254 }
0255
0256
0257 void close() {
0258 if (file == nullptr) {
0259 ACTS_ERROR("Output file is not available");
0260 return;
0261 }
0262 file->Write();
0263 file->Close();
0264 }
0265 };
0266
0267 TrackFinderNTupleWriter::TrackFinderNTupleWriter(
0268 TrackFinderNTupleWriter::Config config, Acts::Logging::Level level)
0269 : WriterT(config.inputTracks, "TrackFinderNTupleWriter", level),
0270 m_impl(std::make_unique<Impl>(this, std::move(config), logger())) {}
0271
0272 TrackFinderNTupleWriter::~TrackFinderNTupleWriter() = default;
0273
0274 ProcessCode TrackFinderNTupleWriter::writeT(const AlgorithmContext& ctx,
0275 const ConstTrackContainer& tracks) {
0276 const auto& particles = m_impl->inputParticles(ctx);
0277 const auto& particleMeasurementsMap =
0278 m_impl->inputParticleMeasurementsMap(ctx);
0279 const auto& trackParticleMatching = m_impl->inputTrackParticleMatching(ctx);
0280 m_impl->write(ctx.eventNumber, tracks, particles, particleMeasurementsMap,
0281 trackParticleMatching);
0282 return ProcessCode::SUCCESS;
0283 }
0284
0285 ProcessCode TrackFinderNTupleWriter::finalize() {
0286 m_impl->close();
0287 return ProcessCode::SUCCESS;
0288 }
0289
0290 const TrackFinderNTupleWriter::Config& TrackFinderNTupleWriter::config() const {
0291 return m_impl->cfg;
0292 }
0293
0294 }