File indexing completed on 2025-08-05 08:10:02
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "ActsExamples/Io/Root/RootParticleWriter.hpp"
0010
0011 #include "Acts/Definitions/Units.hpp"
0012 #include "Acts/Utilities/Helpers.hpp"
0013 #include "Acts/Utilities/VectorHelpers.hpp"
0014 #include "ActsExamples/Framework/AlgorithmContext.hpp"
0015 #include "ActsFatras/EventData/Barcode.hpp"
0016 #include "ActsFatras/EventData/Particle.hpp"
0017
0018 #include <cstdint>
0019 #include <ios>
0020 #include <limits>
0021 #include <ostream>
0022 #include <stdexcept>
0023
0024 #include <TFile.h>
0025 #include <TTree.h>
0026
0027 ActsExamples::RootParticleWriter::RootParticleWriter(
0028 const ActsExamples::RootParticleWriter::Config& cfg,
0029 Acts::Logging::Level lvl)
0030 : WriterT(cfg.inputParticles, "RootParticleWriter", lvl), m_cfg(cfg) {
0031
0032 if (m_cfg.filePath.empty()) {
0033 throw std::invalid_argument("Missing file path");
0034 }
0035 if (m_cfg.treeName.empty()) {
0036 throw std::invalid_argument("Missing tree name");
0037 }
0038
0039 m_inputFinalParticles.maybeInitialize(m_cfg.inputFinalParticles);
0040
0041
0042 m_outputFile = TFile::Open(m_cfg.filePath.c_str(), m_cfg.fileMode.c_str());
0043 if (m_outputFile == nullptr) {
0044 throw std::ios_base::failure("Could not open '" + m_cfg.filePath + "'");
0045 }
0046 m_outputFile->cd();
0047 m_outputTree = new TTree(m_cfg.treeName.c_str(), m_cfg.treeName.c_str());
0048 if (m_outputTree == nullptr) {
0049 throw std::bad_alloc();
0050 }
0051
0052
0053 m_outputTree->Branch("event_id", &m_eventId);
0054 m_outputTree->Branch("particle_id", &m_particleId);
0055 m_outputTree->Branch("particle_type", &m_particleType);
0056 m_outputTree->Branch("process", &m_process);
0057 m_outputTree->Branch("vx", &m_vx);
0058 m_outputTree->Branch("vy", &m_vy);
0059 m_outputTree->Branch("vz", &m_vz);
0060 m_outputTree->Branch("vt", &m_vt);
0061 m_outputTree->Branch("px", &m_px);
0062 m_outputTree->Branch("py", &m_py);
0063 m_outputTree->Branch("pz", &m_pz);
0064 m_outputTree->Branch("m", &m_m);
0065 m_outputTree->Branch("q", &m_q);
0066 m_outputTree->Branch("eta", &m_eta);
0067 m_outputTree->Branch("phi", &m_phi);
0068 m_outputTree->Branch("pt", &m_pt);
0069 m_outputTree->Branch("p", &m_p);
0070 m_outputTree->Branch("vertex_primary", &m_vertexPrimary);
0071 m_outputTree->Branch("vertex_secondary", &m_vertexSecondary);
0072 m_outputTree->Branch("particle", &m_particle);
0073 m_outputTree->Branch("generation", &m_generation);
0074 m_outputTree->Branch("sub_particle", &m_subParticle);
0075
0076 if (m_inputFinalParticles.isInitialized()) {
0077 m_outputTree->Branch("e_loss", &m_eLoss);
0078 m_outputTree->Branch("total_x0", &m_pathInX0);
0079 m_outputTree->Branch("total_l0", &m_pathInL0);
0080 m_outputTree->Branch("number_of_hits", &m_numberOfHits);
0081 m_outputTree->Branch("outcome", &m_outcome);
0082 }
0083 }
0084
0085 ActsExamples::RootParticleWriter::~RootParticleWriter() {
0086 if (m_outputFile != nullptr) {
0087 m_outputFile->Close();
0088 }
0089 }
0090
0091 ActsExamples::ProcessCode ActsExamples::RootParticleWriter::finalize() {
0092 m_outputFile->cd();
0093 m_outputTree->Write();
0094 m_outputFile->Close();
0095
0096 ACTS_INFO("Wrote particles to tree '" << m_cfg.treeName << "' in '"
0097 << m_cfg.filePath << "'");
0098
0099 return ProcessCode::SUCCESS;
0100 }
0101
0102 ActsExamples::ProcessCode ActsExamples::RootParticleWriter::writeT(
0103 const AlgorithmContext& ctx, const SimParticleContainer& particles) {
0104 const SimParticleContainer* finalParticles = nullptr;
0105 if (m_inputFinalParticles.isInitialized()) {
0106 finalParticles = &m_inputFinalParticles(ctx);
0107 }
0108
0109
0110 std::lock_guard<std::mutex> lock(m_writeMutex);
0111
0112 auto nan = std::numeric_limits<float>::quiet_NaN();
0113
0114 m_eventId = ctx.eventNumber;
0115 for (const auto& particle : particles) {
0116 m_particleId.push_back(particle.particleId().value());
0117 m_particleType.push_back(particle.pdg());
0118 m_process.push_back(static_cast<uint32_t>(particle.process()));
0119
0120 m_vx.push_back(Acts::clampValue<float>(particle.fourPosition().x() /
0121 Acts::UnitConstants::mm));
0122 m_vy.push_back(Acts::clampValue<float>(particle.fourPosition().y() /
0123 Acts::UnitConstants::mm));
0124 m_vz.push_back(Acts::clampValue<float>(particle.fourPosition().z() /
0125 Acts::UnitConstants::mm));
0126 m_vt.push_back(Acts::clampValue<float>(particle.fourPosition().w() /
0127 Acts::UnitConstants::mm));
0128
0129 const auto p = particle.absoluteMomentum() / Acts::UnitConstants::GeV;
0130 m_p.push_back(Acts::clampValue<float>(p));
0131 m_px.push_back(Acts::clampValue<float>(p * particle.direction().x()));
0132 m_py.push_back(Acts::clampValue<float>(p * particle.direction().y()));
0133 m_pz.push_back(Acts::clampValue<float>(p * particle.direction().z()));
0134
0135 m_m.push_back(
0136 Acts::clampValue<float>(particle.mass() / Acts::UnitConstants::GeV));
0137 m_q.push_back(
0138 Acts::clampValue<float>(particle.charge() / Acts::UnitConstants::e));
0139
0140 m_eta.push_back(Acts::clampValue<float>(
0141 Acts::VectorHelpers::eta(particle.direction())));
0142 m_phi.push_back(Acts::clampValue<float>(
0143 Acts::VectorHelpers::phi(particle.direction())));
0144 m_pt.push_back(Acts::clampValue<float>(
0145 p * Acts::VectorHelpers::perp(particle.direction())));
0146
0147 m_vertexPrimary.push_back(particle.particleId().vertexPrimary());
0148 m_vertexSecondary.push_back(particle.particleId().vertexSecondary());
0149 m_particle.push_back(particle.particleId().particle());
0150 m_generation.push_back(particle.particleId().generation());
0151 m_subParticle.push_back(particle.particleId().subParticle());
0152
0153 bool wroteFinalParticle = false;
0154 if (finalParticles != nullptr) {
0155
0156 auto it = finalParticles->find(particle);
0157 if (it == finalParticles->end()) {
0158 ACTS_ERROR("Could not find final particle for "
0159 << particle.particleId() << " in event " << ctx.eventNumber);
0160 } else {
0161 const auto& finalParticle = *it;
0162
0163 m_eLoss.push_back(Acts::clampValue<float>(
0164 (particle.energy() - finalParticle.energy()) /
0165 Acts::UnitConstants::GeV));
0166
0167 m_pathInX0.push_back(Acts::clampValue<float>(finalParticle.pathInX0() /
0168 Acts::UnitConstants::mm));
0169
0170 m_pathInL0.push_back(Acts::clampValue<float>(finalParticle.pathInL0() /
0171 Acts::UnitConstants::mm));
0172
0173 m_numberOfHits.push_back(finalParticle.numberOfHits());
0174
0175 m_outcome.push_back(
0176 static_cast<std::uint32_t>(finalParticle.outcome()));
0177
0178 wroteFinalParticle = true;
0179 }
0180 }
0181 if (!wroteFinalParticle) {
0182 m_eLoss.push_back(nan);
0183 m_pathInX0.push_back(nan);
0184 m_pathInL0.push_back(nan);
0185 m_numberOfHits.push_back(-1);
0186 m_outcome.push_back(0);
0187 }
0188 }
0189
0190 m_outputTree->Fill();
0191
0192 m_particleId.clear();
0193 m_particleType.clear();
0194 m_process.clear();
0195 m_vx.clear();
0196 m_vy.clear();
0197 m_vz.clear();
0198 m_vt.clear();
0199 m_p.clear();
0200 m_px.clear();
0201 m_py.clear();
0202 m_pz.clear();
0203 m_m.clear();
0204 m_q.clear();
0205 m_eta.clear();
0206 m_phi.clear();
0207 m_pt.clear();
0208 m_vertexPrimary.clear();
0209 m_vertexSecondary.clear();
0210 m_particle.clear();
0211 m_generation.clear();
0212 m_subParticle.clear();
0213 m_eLoss.clear();
0214 m_numberOfHits.clear();
0215 m_outcome.clear();
0216 m_pathInX0.clear();
0217 m_pathInL0.clear();
0218
0219 return ProcessCode::SUCCESS;
0220 }