File indexing completed on 2025-08-05 08:10:01
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "ActsExamples/Io/Root/RootMaterialTrackWriter.hpp"
0010
0011 #include "Acts/Geometry/GeometryIdentifier.hpp"
0012 #include "Acts/Geometry/TrackingVolume.hpp"
0013 #include "Acts/Geometry/Volume.hpp"
0014 #include "Acts/Material/Material.hpp"
0015 #include "Acts/Material/MaterialInteraction.hpp"
0016 #include "Acts/Material/MaterialSlab.hpp"
0017 #include "Acts/Surfaces/CylinderBounds.hpp"
0018 #include "Acts/Surfaces/RadialBounds.hpp"
0019 #include "Acts/Surfaces/Surface.hpp"
0020 #include "Acts/Surfaces/SurfaceBounds.hpp"
0021 #include "Acts/Utilities/Intersection.hpp"
0022 #include "Acts/Utilities/Logger.hpp"
0023 #include "ActsExamples/Framework/AlgorithmContext.hpp"
0024
0025 #include <algorithm>
0026 #include <cstddef>
0027 #include <ios>
0028 #include <stdexcept>
0029 #include <type_traits>
0030
0031 #include <TFile.h>
0032 #include <TTree.h>
0033
0034 using Acts::VectorHelpers::eta;
0035 using Acts::VectorHelpers::perp;
0036 using Acts::VectorHelpers::phi;
0037
0038 namespace ActsExamples {
0039
0040 RootMaterialTrackWriter::RootMaterialTrackWriter(
0041 const RootMaterialTrackWriter::Config& config, Acts::Logging::Level level)
0042 : WriterT(config.inputMaterialTracks, "RootMaterialTrackWriter", level),
0043 m_cfg(config) {
0044
0045 if (m_cfg.inputMaterialTracks.empty()) {
0046 throw std::invalid_argument("Missing input collection");
0047 } else if (m_cfg.treeName.empty()) {
0048 throw std::invalid_argument("Missing tree name");
0049 }
0050
0051
0052 m_outputFile = TFile::Open(m_cfg.filePath.c_str(), m_cfg.fileMode.c_str());
0053 if (m_outputFile == nullptr) {
0054 throw std::ios_base::failure("Could not open '" + m_cfg.filePath + "'");
0055 }
0056
0057 m_outputFile->cd();
0058 m_outputTree =
0059 new TTree(m_cfg.treeName.c_str(), "TTree from RootMaterialTrackWriter");
0060 if (m_outputTree == nullptr) {
0061 throw std::bad_alloc();
0062 }
0063
0064
0065 m_outputTree->Branch("event_id", &m_eventId);
0066 m_outputTree->Branch("v_x", &m_v_x);
0067 m_outputTree->Branch("v_y", &m_v_y);
0068 m_outputTree->Branch("v_z", &m_v_z);
0069 m_outputTree->Branch("v_px", &m_v_px);
0070 m_outputTree->Branch("v_py", &m_v_py);
0071 m_outputTree->Branch("v_pz", &m_v_pz);
0072 m_outputTree->Branch("v_phi", &m_v_phi);
0073 m_outputTree->Branch("v_eta", &m_v_eta);
0074 m_outputTree->Branch("t_X0", &m_tX0);
0075 m_outputTree->Branch("t_L0", &m_tL0);
0076 m_outputTree->Branch("mat_x", &m_step_x);
0077 m_outputTree->Branch("mat_y", &m_step_y);
0078 m_outputTree->Branch("mat_z", &m_step_z);
0079 m_outputTree->Branch("mat_dx", &m_step_dx);
0080 m_outputTree->Branch("mat_dy", &m_step_dy);
0081 m_outputTree->Branch("mat_dz", &m_step_dz);
0082 m_outputTree->Branch("mat_step_length", &m_step_length);
0083 m_outputTree->Branch("mat_X0", &m_step_X0);
0084 m_outputTree->Branch("mat_L0", &m_step_L0);
0085 m_outputTree->Branch("mat_A", &m_step_A);
0086 m_outputTree->Branch("mat_Z", &m_step_Z);
0087 m_outputTree->Branch("mat_rho", &m_step_rho);
0088
0089 if (m_cfg.prePostStep) {
0090 m_outputTree->Branch("mat_sx", &m_step_sx);
0091 m_outputTree->Branch("mat_sy", &m_step_sy);
0092 m_outputTree->Branch("mat_sz", &m_step_sz);
0093 m_outputTree->Branch("mat_ex", &m_step_ex);
0094 m_outputTree->Branch("mat_ey", &m_step_ey);
0095 m_outputTree->Branch("mat_ez", &m_step_ez);
0096 }
0097 if (m_cfg.storeSurface) {
0098 m_outputTree->Branch("sur_id", &m_sur_id);
0099 m_outputTree->Branch("sur_type", &m_sur_type);
0100 m_outputTree->Branch("sur_x", &m_sur_x);
0101 m_outputTree->Branch("sur_y", &m_sur_y);
0102 m_outputTree->Branch("sur_z", &m_sur_z);
0103 m_outputTree->Branch("sur_pathCorrection", &m_sur_pathCorrection);
0104 m_outputTree->Branch("sur_range_min", &m_sur_range_min);
0105 m_outputTree->Branch("sur_range_max", &m_sur_range_max);
0106 }
0107 if (m_cfg.storeVolume) {
0108 m_outputTree->Branch("vol_id", &m_vol_id);
0109 }
0110 }
0111
0112 RootMaterialTrackWriter::~RootMaterialTrackWriter() {
0113 if (m_outputFile != nullptr) {
0114 m_outputFile->Close();
0115 }
0116 }
0117
0118 ProcessCode RootMaterialTrackWriter::finalize() {
0119
0120 ACTS_INFO("Writing ROOT output File : " << m_cfg.filePath);
0121
0122 m_outputFile->cd();
0123 m_outputTree->Write();
0124 m_outputFile->Close();
0125
0126 return ProcessCode::SUCCESS;
0127 }
0128
0129 ProcessCode RootMaterialTrackWriter::writeT(
0130 const AlgorithmContext& ctx,
0131 const std::unordered_map<std::size_t, Acts::RecordedMaterialTrack>&
0132 materialTracks) {
0133
0134 std::lock_guard<std::mutex> lock(m_writeMutex);
0135
0136 m_eventId = ctx.eventNumber;
0137
0138 for (auto& [idTrack, mtrack] : materialTracks) {
0139
0140 m_step_sx.clear();
0141 m_step_sy.clear();
0142 m_step_sz.clear();
0143 m_step_x.clear();
0144 m_step_y.clear();
0145 m_step_z.clear();
0146 m_step_ex.clear();
0147 m_step_ey.clear();
0148 m_step_ez.clear();
0149 m_step_dx.clear();
0150 m_step_dy.clear();
0151 m_step_dz.clear();
0152 m_step_length.clear();
0153 m_step_X0.clear();
0154 m_step_L0.clear();
0155 m_step_A.clear();
0156 m_step_Z.clear();
0157 m_step_rho.clear();
0158
0159 m_sur_id.clear();
0160 m_sur_type.clear();
0161 m_sur_x.clear();
0162 m_sur_y.clear();
0163 m_sur_z.clear();
0164 m_sur_pathCorrection.clear();
0165 m_sur_range_min.clear();
0166 m_sur_range_max.clear();
0167
0168 m_vol_id.clear();
0169
0170 auto materialInteractions = mtrack.second.materialInteractions;
0171 if (m_cfg.collapseInteractions) {
0172 std::vector<Acts::MaterialInteraction> collapsed;
0173
0174 Acts::Vector3 positionSum = Acts::Vector3::Zero();
0175 double pathCorrectionSum = 0;
0176
0177 for (std::size_t start = 0, end = 0; end < materialInteractions.size();
0178 ++end) {
0179 const auto& mintStart = materialInteractions[start];
0180 const auto& mintEnd = materialInteractions[end];
0181
0182 positionSum += mintEnd.position;
0183 pathCorrectionSum += mintEnd.pathCorrection;
0184
0185 const bool same = mintStart.materialSlab.material() ==
0186 mintEnd.materialSlab.material();
0187 const bool last = end == materialInteractions.size() - 1;
0188
0189 if (!same || last) {
0190 auto mint = mintStart;
0191 mint.position = positionSum / (end - start);
0192 mint.pathCorrection = pathCorrectionSum;
0193
0194 collapsed.push_back(mint);
0195
0196 start = end;
0197 positionSum = Acts::Vector3::Zero();
0198 pathCorrectionSum = 0;
0199 }
0200 }
0201
0202 materialInteractions = std::move(collapsed);
0203 }
0204
0205
0206 std::size_t mints = materialInteractions.size();
0207 m_step_sx.reserve(mints);
0208 m_step_sy.reserve(mints);
0209 m_step_sz.reserve(mints);
0210 m_step_x.reserve(mints);
0211 m_step_y.reserve(mints);
0212 m_step_z.reserve(mints);
0213 m_step_ex.reserve(mints);
0214 m_step_ey.reserve(mints);
0215 m_step_ez.reserve(mints);
0216 m_step_dx.reserve(mints);
0217 m_step_dy.reserve(mints);
0218 m_step_dz.reserve(mints);
0219 m_step_length.reserve(mints);
0220 m_step_X0.reserve(mints);
0221 m_step_L0.reserve(mints);
0222 m_step_A.reserve(mints);
0223 m_step_Z.reserve(mints);
0224 m_step_rho.reserve(mints);
0225
0226 m_sur_id.reserve(mints);
0227 m_sur_type.reserve(mints);
0228 m_sur_x.reserve(mints);
0229 m_sur_y.reserve(mints);
0230 m_sur_z.reserve(mints);
0231 m_sur_pathCorrection.reserve(mints);
0232 m_sur_range_min.reserve(mints);
0233 m_sur_range_max.reserve(mints);
0234
0235 m_vol_id.reserve(mints);
0236
0237
0238 if (m_cfg.recalculateTotals) {
0239 m_tX0 = 0.;
0240 m_tL0 = 0.;
0241 } else {
0242 m_tX0 = mtrack.second.materialInX0;
0243 m_tL0 = mtrack.second.materialInL0;
0244 }
0245
0246
0247 m_v_x = mtrack.first.first.x();
0248 m_v_y = mtrack.first.first.y();
0249 m_v_z = mtrack.first.first.z();
0250 m_v_px = mtrack.first.second.x();
0251 m_v_py = mtrack.first.second.y();
0252 m_v_pz = mtrack.first.second.z();
0253 m_v_phi = phi(mtrack.first.second);
0254 m_v_eta = eta(mtrack.first.second);
0255
0256
0257 for (const auto& mint : materialInteractions) {
0258 auto direction = mint.direction.normalized();
0259
0260
0261 m_step_x.push_back(mint.position.x());
0262 m_step_y.push_back(mint.position.y());
0263 m_step_z.push_back(mint.position.z());
0264 m_step_dx.push_back(direction.x());
0265 m_step_dy.push_back(direction.y());
0266 m_step_dz.push_back(direction.z());
0267
0268 if (m_cfg.prePostStep) {
0269 Acts::Vector3 prePos =
0270 mint.position - 0.5 * mint.pathCorrection * direction;
0271 Acts::Vector3 posPos =
0272 mint.position + 0.5 * mint.pathCorrection * direction;
0273
0274 m_step_sx.push_back(prePos.x());
0275 m_step_sy.push_back(prePos.y());
0276 m_step_sz.push_back(prePos.z());
0277 m_step_ex.push_back(posPos.x());
0278 m_step_ey.push_back(posPos.y());
0279 m_step_ez.push_back(posPos.z());
0280 }
0281
0282
0283 if (m_cfg.storeSurface) {
0284 const Acts::Surface* surface = mint.surface;
0285 if (mint.intersectionID.value() != 0) {
0286 m_sur_id.push_back(mint.intersectionID.value());
0287 m_sur_pathCorrection.push_back(mint.pathCorrection);
0288 m_sur_x.push_back(mint.intersection.x());
0289 m_sur_y.push_back(mint.intersection.y());
0290 m_sur_z.push_back(mint.intersection.z());
0291 } else if (surface != nullptr) {
0292 auto sfIntersection =
0293 surface
0294 ->intersect(ctx.geoContext, mint.position, mint.direction,
0295 Acts::BoundaryCheck(true))
0296 .closest();
0297 m_sur_id.push_back(surface->geometryId().value());
0298 m_sur_pathCorrection.push_back(1.0);
0299 m_sur_x.push_back(sfIntersection.position().x());
0300 m_sur_y.push_back(sfIntersection.position().y());
0301 m_sur_z.push_back(sfIntersection.position().z());
0302 } else {
0303 m_sur_id.push_back(Acts::GeometryIdentifier().value());
0304 m_sur_x.push_back(0);
0305 m_sur_y.push_back(0);
0306 m_sur_z.push_back(0);
0307 m_sur_pathCorrection.push_back(1.0);
0308 }
0309 if (surface != nullptr) {
0310 m_sur_type.push_back(surface->type());
0311 const Acts::SurfaceBounds& surfaceBounds = surface->bounds();
0312 const Acts::RadialBounds* radialBounds =
0313 dynamic_cast<const Acts::RadialBounds*>(&surfaceBounds);
0314 const Acts::CylinderBounds* cylinderBounds =
0315 dynamic_cast<const Acts::CylinderBounds*>(&surfaceBounds);
0316 if (radialBounds != nullptr) {
0317 m_sur_range_min.push_back(radialBounds->rMin());
0318 m_sur_range_max.push_back(radialBounds->rMax());
0319 } else if (cylinderBounds != nullptr) {
0320 m_sur_range_min.push_back(
0321 -cylinderBounds->get(Acts::CylinderBounds::eHalfLengthZ));
0322 m_sur_range_max.push_back(
0323 cylinderBounds->get(Acts::CylinderBounds::eHalfLengthZ));
0324 } else {
0325 m_sur_range_min.push_back(0);
0326 m_sur_range_max.push_back(0);
0327 }
0328 } else {
0329 m_sur_type.push_back(-1);
0330 m_sur_range_min.push_back(0);
0331 m_sur_range_max.push_back(0);
0332 }
0333 }
0334
0335
0336 if (m_cfg.storeVolume) {
0337 Acts::GeometryIdentifier vlayerID;
0338 if (!mint.volume.empty()) {
0339 vlayerID = mint.volume.geometryId();
0340 m_vol_id.push_back(vlayerID.value());
0341 } else {
0342 vlayerID.setVolume(0);
0343 vlayerID.setBoundary(0);
0344 vlayerID.setLayer(0);
0345 vlayerID.setApproach(0);
0346 vlayerID.setSensitive(0);
0347 m_vol_id.push_back(vlayerID.value());
0348 }
0349 }
0350
0351
0352 const auto& mprops = mint.materialSlab;
0353 m_step_length.push_back(mprops.thickness());
0354 m_step_X0.push_back(mprops.material().X0());
0355 m_step_L0.push_back(mprops.material().L0());
0356 m_step_A.push_back(mprops.material().Ar());
0357 m_step_Z.push_back(mprops.material().Z());
0358 m_step_rho.push_back(mprops.material().massDensity());
0359
0360 if (m_cfg.recalculateTotals) {
0361 m_tX0 += mprops.thicknessInX0();
0362 m_tL0 += mprops.thicknessInL0();
0363 }
0364 }
0365
0366 m_outputTree->Fill();
0367 }
0368
0369
0370 return ProcessCode::SUCCESS;
0371 }
0372
0373 }