File indexing completed on 2025-08-05 08:10:01
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "ActsExamples/Io/Root/RootMeasurementWriter.hpp"
0010
0011 #include "Acts/Geometry/TrackingGeometry.hpp"
0012 #include "ActsExamples/EventData/AverageSimHits.hpp"
0013 #include "ActsExamples/EventData/Index.hpp"
0014 #include "ActsExamples/EventData/IndexSourceLink.hpp"
0015 #include "ActsExamples/Framework/AlgorithmContext.hpp"
0016 #include "ActsExamples/Utilities/Range.hpp"
0017
0018 #include <cstddef>
0019 #include <ios>
0020 #include <stdexcept>
0021 #include <utility>
0022 #include <variant>
0023
0024 #include <TFile.h>
0025
0026 namespace Acts {
0027 class Surface;
0028 }
0029
0030 ActsExamples::RootMeasurementWriter::RootMeasurementWriter(
0031 const ActsExamples::RootMeasurementWriter::Config& config,
0032 Acts::Logging::Level level)
0033 : WriterT(config.inputMeasurements, "RootMeasurementWriter", level),
0034 m_cfg(config) {
0035
0036 if (m_cfg.inputSimHits.empty()) {
0037 throw std::invalid_argument("Missing simulated hits input collection");
0038 }
0039 if (m_cfg.inputMeasurementSimHitsMap.empty()) {
0040 throw std::invalid_argument(
0041 "Missing hit-to-simulated-hits map input collection");
0042 }
0043
0044 m_inputSimHits.initialize(m_cfg.inputSimHits);
0045 m_inputMeasurementSimHitsMap.initialize(m_cfg.inputMeasurementSimHitsMap);
0046 m_inputClusters.maybeInitialize(m_cfg.inputClusters);
0047
0048 if (!m_cfg.trackingGeometry) {
0049 throw std::invalid_argument("Missing tracking geometry");
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
0059
0060 std::vector<
0061 std::pair<Acts::GeometryIdentifier, std::unique_ptr<DigitizationTree>>>
0062 dTrees;
0063 if (!m_cfg.boundIndices.empty()) {
0064 ACTS_DEBUG("Bound indices are declared, preparing trees.");
0065 for (std::size_t ikv = 0; ikv < m_cfg.boundIndices.size(); ++ikv) {
0066 auto geoID = m_cfg.boundIndices.idAt(ikv);
0067 auto bIndices = m_cfg.boundIndices.valueAt(ikv);
0068 auto dTree = std::make_unique<DigitizationTree>(geoID);
0069 for (const auto& bIndex : bIndices) {
0070 ACTS_VERBOSE("- setup branch for index: " << bIndex);
0071 dTree->setupBoundRecBranch(bIndex);
0072 }
0073 if (!m_cfg.inputClusters.empty()) {
0074 dTree->setupClusterBranch(bIndices);
0075 }
0076 dTrees.push_back({geoID, std::move(dTree)});
0077 }
0078 } else {
0079 ACTS_DEBUG("Bound indices are not declared, no reco setup.")
0080 }
0081
0082 m_outputTrees = Acts::GeometryHierarchyMap<std::unique_ptr<DigitizationTree>>(
0083 std::move(dTrees));
0084 }
0085
0086 ActsExamples::RootMeasurementWriter::~RootMeasurementWriter() {
0087 if (m_outputFile != nullptr) {
0088 m_outputFile->Close();
0089 }
0090 }
0091
0092 ActsExamples::ProcessCode ActsExamples::RootMeasurementWriter::finalize() {
0093
0094 m_outputFile->cd();
0095 for (auto dTree = m_outputTrees.begin(); dTree != m_outputTrees.end();
0096 ++dTree) {
0097 (*dTree)->tree->Write();
0098 }
0099 m_outputFile->Close();
0100
0101 return ProcessCode::SUCCESS;
0102 }
0103
0104 ActsExamples::ProcessCode ActsExamples::RootMeasurementWriter::writeT(
0105 const AlgorithmContext& ctx, const MeasurementContainer& measurements) {
0106 const auto& simHits = m_inputSimHits(ctx);
0107 const auto& hitSimHitsMap = m_inputMeasurementSimHitsMap(ctx);
0108
0109 ClusterContainer clusters;
0110 if (!m_cfg.inputClusters.empty()) {
0111 clusters = m_inputClusters(ctx);
0112 }
0113
0114
0115 std::lock_guard<std::mutex> lock(m_writeMutex);
0116
0117 for (Index hitIdx = 0u; hitIdx < measurements.size(); ++hitIdx) {
0118 const auto& meas = measurements[hitIdx];
0119
0120 std::visit(
0121 [&](const auto& m) {
0122 Acts::GeometryIdentifier geoId =
0123 m.sourceLink().template get<IndexSourceLink>().geometryId();
0124
0125 const Acts::Surface* surfacePtr =
0126 m_cfg.trackingGeometry->findSurface(geoId);
0127 if (!surfacePtr) {
0128 return;
0129 }
0130 const Acts::Surface& surface = *surfacePtr;
0131
0132 auto dTreeItr = m_outputTrees.find(geoId);
0133 if (dTreeItr == m_outputTrees.end()) {
0134 return;
0135 }
0136 auto& dTree = *dTreeItr;
0137
0138
0139 dTree->fillIdentification(ctx.eventNumber, geoId);
0140
0141
0142 auto indices = makeRange(hitSimHitsMap.equal_range(hitIdx));
0143
0144 auto [local, pos4, dir] = averageSimHits(ctx.geoContext, surface,
0145 simHits, indices, logger());
0146 Acts::RotationMatrix3 rot =
0147 surface
0148 .referenceFrame(ctx.geoContext, pos4.segment<3>(Acts::ePos0),
0149 dir)
0150 .inverse();
0151 std::pair<double, double> angles =
0152 Acts::VectorHelpers::incidentAngles(dir, rot);
0153 dTree->fillTruthParameters(local, pos4, dir, angles);
0154 dTree->fillBoundMeasurement(m);
0155 if (!clusters.empty()) {
0156 const auto& c = clusters[hitIdx];
0157 dTree->fillCluster(c);
0158 }
0159 dTree->tree->Fill();
0160 if (dTree->chValue != nullptr) {
0161 dTree->chValue->clear();
0162 }
0163 if (dTree->chId[0] != nullptr) {
0164 dTree->chId[0]->clear();
0165 }
0166 if (dTree->chId[1] != nullptr) {
0167 dTree->chId[1]->clear();
0168 }
0169 },
0170 meas);
0171 }
0172
0173 return ActsExamples::ProcessCode::SUCCESS;
0174 }