Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-05 08:12:03

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
0008 
0009 #include "ActsExamples/Io/Root/RootTrackSummaryWriter.hpp"
0010 
0011 #include "Acts/Definitions/TrackParametrization.hpp"
0012 #include "Acts/EventData/GenericBoundTrackParameters.hpp"
0013 #include "Acts/EventData/MultiTrajectoryHelpers.hpp"
0014 #include "Acts/EventData/VectorMultiTrajectory.hpp"
0015 #include "Acts/Surfaces/Surface.hpp"
0016 #include "Acts/TrackFitting/GsfOptions.hpp"
0017 #include "Acts/Utilities/Intersection.hpp"
0018 #include "Acts/Utilities/MultiIndex.hpp"
0019 #include "Acts/Utilities/Result.hpp"
0020 #include "Acts/Utilities/detail/periodic.hpp"
0021 #include "ActsExamples/EventData/IndexSourceLink.hpp"
0022 #include "ActsExamples/EventData/TruthMatching.hpp"
0023 #include "ActsExamples/Framework/AlgorithmContext.hpp"
0024 #include "ActsExamples/Framework/WriterT.hpp"
0025 #include "ActsExamples/Validation/TrackClassification.hpp"
0026 #include "ActsFatras/EventData/Barcode.hpp"
0027 #include "ActsFatras/EventData/Particle.hpp"
0028 
0029 #include <array>
0030 #include <cmath>
0031 #include <cstddef>
0032 #include <cstdint>
0033 #include <ios>
0034 #include <limits>
0035 #include <memory>
0036 #include <numbers>
0037 #include <optional>
0038 #include <ostream>
0039 #include <stdexcept>
0040 
0041 #include <TFile.h>
0042 #include <TTree.h>
0043 
0044 using Acts::VectorHelpers::eta;
0045 using Acts::VectorHelpers::perp;
0046 using Acts::VectorHelpers::phi;
0047 using Acts::VectorHelpers::theta;
0048 
0049 namespace ActsExamples {
0050 
0051 RootTrackSummaryWriter::RootTrackSummaryWriter(
0052     const RootTrackSummaryWriter::Config& config, Acts::Logging::Level level)
0053     : WriterT(config.inputTracks, "RootTrackSummaryWriter", level),
0054       m_cfg(config) {
0055   // tracks collection name is already checked by base ctor
0056   if (m_cfg.filePath.empty()) {
0057     throw std::invalid_argument("Missing output filename");
0058   }
0059   if (m_cfg.treeName.empty()) {
0060     throw std::invalid_argument("Missing tree name");
0061   }
0062 
0063   m_inputParticles.maybeInitialize(m_cfg.inputParticles);
0064   m_inputTrackParticleMatching.maybeInitialize(
0065       m_cfg.inputTrackParticleMatching);
0066 
0067   // Setup ROOT I/O
0068   auto path = m_cfg.filePath;
0069   m_outputFile = TFile::Open(path.c_str(), m_cfg.fileMode.c_str());
0070   if (m_outputFile == nullptr) {
0071     throw std::ios_base::failure("Could not open '" + path + "'");
0072   }
0073   m_outputFile->cd();
0074   m_outputTree = new TTree(m_cfg.treeName.c_str(), m_cfg.treeName.c_str());
0075   if (m_outputTree == nullptr) {
0076     throw std::bad_alloc();
0077   }
0078 
0079   // I/O parameters
0080   m_outputTree->Branch("event_nr", &m_eventNr);
0081   m_outputTree->Branch("track_nr", &m_trackNr);
0082 
0083   m_outputTree->Branch("nStates", &m_nStates);
0084   m_outputTree->Branch("nMeasurements", &m_nMeasurements);
0085   m_outputTree->Branch("nOutliers", &m_nOutliers);
0086   m_outputTree->Branch("nHoles", &m_nHoles);
0087   m_outputTree->Branch("nSharedHits", &m_nSharedHits);
0088   m_outputTree->Branch("chi2Sum", &m_chi2Sum);
0089   m_outputTree->Branch("NDF", &m_NDF);
0090   m_outputTree->Branch("measurementChi2", &m_measurementChi2);
0091   m_outputTree->Branch("outlierChi2", &m_outlierChi2);
0092   m_outputTree->Branch("measurementVolume", &m_measurementVolume);
0093   m_outputTree->Branch("measurementLayer", &m_measurementLayer);
0094   m_outputTree->Branch("outlierVolume", &m_outlierVolume);
0095   m_outputTree->Branch("outlierLayer", &m_outlierLayer);
0096 
0097   m_outputTree->Branch("nMajorityHits", &m_nMajorityHits);
0098   m_outputTree->Branch("majorityParticleId", &m_majorityParticleId);
0099   m_outputTree->Branch("trackClassification", &m_trackClassification);
0100   m_outputTree->Branch("t_charge", &m_t_charge);
0101   m_outputTree->Branch("t_time", &m_t_time);
0102   m_outputTree->Branch("t_vx", &m_t_vx);
0103   m_outputTree->Branch("t_vy", &m_t_vy);
0104   m_outputTree->Branch("t_vz", &m_t_vz);
0105   m_outputTree->Branch("t_px", &m_t_px);
0106   m_outputTree->Branch("t_py", &m_t_py);
0107   m_outputTree->Branch("t_pz", &m_t_pz);
0108   m_outputTree->Branch("t_theta", &m_t_theta);
0109   m_outputTree->Branch("t_phi", &m_t_phi);
0110   m_outputTree->Branch("t_eta", &m_t_eta);
0111   m_outputTree->Branch("t_p", &m_t_p);
0112   m_outputTree->Branch("t_pT", &m_t_pT);
0113   m_outputTree->Branch("t_d0", &m_t_d0);
0114   m_outputTree->Branch("t_z0", &m_t_z0);
0115   m_outputTree->Branch("t_prodR", &m_t_prodR);
0116 
0117   m_outputTree->Branch("hasFittedParams", &m_hasFittedParams);
0118   m_outputTree->Branch("eLOC0_fit", &m_eLOC0_fit);
0119   m_outputTree->Branch("eLOC1_fit", &m_eLOC1_fit);
0120   m_outputTree->Branch("ePHI_fit", &m_ePHI_fit);
0121   m_outputTree->Branch("eTHETA_fit", &m_eTHETA_fit);
0122   m_outputTree->Branch("eQOP_fit", &m_eQOP_fit);
0123   m_outputTree->Branch("eT_fit", &m_eT_fit);
0124   m_outputTree->Branch("err_eLOC0_fit", &m_err_eLOC0_fit);
0125   m_outputTree->Branch("err_eLOC1_fit", &m_err_eLOC1_fit);
0126   m_outputTree->Branch("err_ePHI_fit", &m_err_ePHI_fit);
0127   m_outputTree->Branch("err_eTHETA_fit", &m_err_eTHETA_fit);
0128   m_outputTree->Branch("err_eQOP_fit", &m_err_eQOP_fit);
0129   m_outputTree->Branch("err_eT_fit", &m_err_eT_fit);
0130   m_outputTree->Branch("res_eLOC0_fit", &m_res_eLOC0_fit);
0131   m_outputTree->Branch("res_eLOC1_fit", &m_res_eLOC1_fit);
0132   m_outputTree->Branch("res_ePHI_fit", &m_res_ePHI_fit);
0133   m_outputTree->Branch("res_eTHETA_fit", &m_res_eTHETA_fit);
0134   m_outputTree->Branch("res_eQOP_fit", &m_res_eQOP_fit);
0135   m_outputTree->Branch("res_eT_fit", &m_res_eT_fit);
0136   m_outputTree->Branch("pull_eLOC0_fit", &m_pull_eLOC0_fit);
0137   m_outputTree->Branch("pull_eLOC1_fit", &m_pull_eLOC1_fit);
0138   m_outputTree->Branch("pull_ePHI_fit", &m_pull_ePHI_fit);
0139   m_outputTree->Branch("pull_eTHETA_fit", &m_pull_eTHETA_fit);
0140   m_outputTree->Branch("pull_eQOP_fit", &m_pull_eQOP_fit);
0141   m_outputTree->Branch("pull_eT_fit", &m_pull_eT_fit);
0142 
0143   if (m_cfg.writeGsfSpecific) {
0144     m_outputTree->Branch("max_material_fwd", &m_gsf_max_material_fwd);
0145     m_outputTree->Branch("sum_material_fwd", &m_gsf_sum_material_fwd);
0146   }
0147 
0148   if (m_cfg.writeCovMat) {
0149     // create one branch for every entry of covariance matrix
0150     // one block for every row of the matrix, every entry gets own branch
0151     m_outputTree->Branch("cov_eLOC0_eLOC0", &m_cov_eLOC0_eLOC0);
0152     m_outputTree->Branch("cov_eLOC0_eLOC1", &m_cov_eLOC0_eLOC1);
0153     m_outputTree->Branch("cov_eLOC0_ePHI", &m_cov_eLOC0_ePHI);
0154     m_outputTree->Branch("cov_eLOC0_eTHETA", &m_cov_eLOC0_eTHETA);
0155     m_outputTree->Branch("cov_eLOC0_eQOP", &m_cov_eLOC0_eQOP);
0156     m_outputTree->Branch("cov_eLOC0_eT", &m_cov_eLOC0_eT);
0157 
0158     m_outputTree->Branch("cov_eLOC1_eLOC0", &m_cov_eLOC1_eLOC0);
0159     m_outputTree->Branch("cov_eLOC1_eLOC1", &m_cov_eLOC1_eLOC1);
0160     m_outputTree->Branch("cov_eLOC1_ePHI", &m_cov_eLOC1_ePHI);
0161     m_outputTree->Branch("cov_eLOC1_eTHETA", &m_cov_eLOC1_eTHETA);
0162     m_outputTree->Branch("cov_eLOC1_eQOP", &m_cov_eLOC1_eQOP);
0163     m_outputTree->Branch("cov_eLOC1_eT", &m_cov_eLOC1_eT);
0164 
0165     m_outputTree->Branch("cov_ePHI_eLOC0", &m_cov_ePHI_eLOC0);
0166     m_outputTree->Branch("cov_ePHI_eLOC1", &m_cov_ePHI_eLOC1);
0167     m_outputTree->Branch("cov_ePHI_ePHI", &m_cov_ePHI_ePHI);
0168     m_outputTree->Branch("cov_ePHI_eTHETA", &m_cov_ePHI_eTHETA);
0169     m_outputTree->Branch("cov_ePHI_eQOP", &m_cov_ePHI_eQOP);
0170     m_outputTree->Branch("cov_ePHI_eT", &m_cov_ePHI_eT);
0171 
0172     m_outputTree->Branch("cov_eTHETA_eLOC0", &m_cov_eTHETA_eLOC0);
0173     m_outputTree->Branch("cov_eTHETA_eLOC1", &m_cov_eTHETA_eLOC1);
0174     m_outputTree->Branch("cov_eTHETA_ePHI", &m_cov_eTHETA_ePHI);
0175     m_outputTree->Branch("cov_eTHETA_eTHETA", &m_cov_eTHETA_eTHETA);
0176     m_outputTree->Branch("cov_eTHETA_eQOP", &m_cov_eTHETA_eQOP);
0177     m_outputTree->Branch("cov_eTHETA_eT", &m_cov_eTHETA_eT);
0178 
0179     m_outputTree->Branch("cov_eQOP_eLOC0", &m_cov_eQOP_eLOC0);
0180     m_outputTree->Branch("cov_eQOP_eLOC1", &m_cov_eQOP_eLOC1);
0181     m_outputTree->Branch("cov_eQOP_ePHI", &m_cov_eQOP_ePHI);
0182     m_outputTree->Branch("cov_eQOP_eTHETA", &m_cov_eQOP_eTHETA);
0183     m_outputTree->Branch("cov_eQOP_eQOP", &m_cov_eQOP_eQOP);
0184     m_outputTree->Branch("cov_eQOP_eT", &m_cov_eQOP_eT);
0185 
0186     m_outputTree->Branch("cov_eT_eLOC0", &m_cov_eT_eLOC0);
0187     m_outputTree->Branch("cov_eT_eLOC1", &m_cov_eT_eLOC1);
0188     m_outputTree->Branch("cov_eT_ePHI", &m_cov_eT_ePHI);
0189     m_outputTree->Branch("cov_eT_eTHETA", &m_cov_eT_eTHETA);
0190     m_outputTree->Branch("cov_eT_eQOP", &m_cov_eT_eQOP);
0191     m_outputTree->Branch("cov_eT_eT", &m_cov_eT_eT);
0192   }
0193 
0194   if (m_cfg.writeGx2fSpecific) {
0195     m_outputTree->Branch("nUpdatesGx2f", &m_nUpdatesGx2f);
0196   }
0197 }
0198 
0199 RootTrackSummaryWriter::~RootTrackSummaryWriter() {
0200   m_outputFile->Close();
0201 }
0202 
0203 ProcessCode RootTrackSummaryWriter::finalize() {
0204   m_outputFile->cd();
0205   m_outputTree->Write();
0206   m_outputFile->Close();
0207 
0208   if (m_cfg.writeCovMat) {
0209     ACTS_INFO("Wrote full covariance matrix to tree");
0210   }
0211   ACTS_INFO("Wrote parameters of tracks to tree '" << m_cfg.treeName << "' in '"
0212                                                    << m_cfg.filePath << "'");
0213 
0214   return ProcessCode::SUCCESS;
0215 }
0216 
0217 ProcessCode RootTrackSummaryWriter::writeT(const AlgorithmContext& ctx,
0218                                            const ConstTrackContainer& tracks) {
0219   // In case we do not have truth info, we bind to a empty collection
0220   const static SimParticleContainer emptyParticles;
0221   const static TrackParticleMatching emptyTrackParticleMatching;
0222 
0223   const auto& particles =
0224       m_inputParticles.isInitialized() ? m_inputParticles(ctx) : emptyParticles;
0225   const auto& trackParticleMatching =
0226       m_inputTrackParticleMatching.isInitialized()
0227           ? m_inputTrackParticleMatching(ctx)
0228           : emptyTrackParticleMatching;
0229 
0230   // For each particle within a track, how many hits did it contribute
0231   std::vector<ParticleHitCount> particleHitCounts;
0232 
0233   // Exclusive access to the tree while writing
0234   std::lock_guard<std::mutex> lock(m_writeMutex);
0235 
0236   // Get the event number
0237   m_eventNr = ctx.eventNumber;
0238 
0239   for (const auto& track : tracks) {
0240     m_trackNr.push_back(track.index());
0241 
0242     // Collect the trajectory summary info
0243     m_nStates.push_back(track.nTrackStates());
0244     m_nMeasurements.push_back(track.nMeasurements());
0245     m_nOutliers.push_back(track.nOutliers());
0246     m_nHoles.push_back(track.nHoles());
0247     m_nSharedHits.push_back(track.nSharedHits());
0248     m_chi2Sum.push_back(track.chi2());
0249     m_NDF.push_back(track.nDoF());
0250 
0251     {
0252       std::vector<double> measurementChi2;
0253       std::vector<std::uint32_t> measurementVolume;
0254       std::vector<std::uint32_t> measurementLayer;
0255       std::vector<double> outlierChi2;
0256       std::vector<std::uint32_t> outlierVolume;
0257       std::vector<std::uint32_t> outlierLayer;
0258       for (const auto& state : track.trackStatesReversed()) {
0259         const auto& geoID = state.referenceSurface().geometryId();
0260         const auto& volume = geoID.volume();
0261         const auto& layer = geoID.layer();
0262         if (state.typeFlags().test(Acts::TrackStateFlag::OutlierFlag)) {
0263           outlierChi2.push_back(state.chi2());
0264           outlierVolume.push_back(volume);
0265           outlierLayer.push_back(layer);
0266         } else if (state.typeFlags().test(
0267                        Acts::TrackStateFlag::MeasurementFlag)) {
0268           measurementChi2.push_back(state.chi2());
0269           measurementVolume.push_back(volume);
0270           measurementLayer.push_back(layer);
0271         }
0272       }
0273       m_measurementChi2.push_back(std::move(measurementChi2));
0274       m_measurementVolume.push_back(std::move(measurementVolume));
0275       m_measurementLayer.push_back(std::move(measurementLayer));
0276       m_outlierChi2.push_back(std::move(outlierChi2));
0277       m_outlierVolume.push_back(std::move(outlierVolume));
0278       m_outlierLayer.push_back(std::move(outlierLayer));
0279     }
0280 
0281     // Initialize the truth particle info
0282     ActsFatras::Barcode majorityParticleId(
0283         std::numeric_limits<std::size_t>::max());
0284     TrackMatchClassification trackClassification =
0285         TrackMatchClassification::Unknown;
0286     unsigned int nMajorityHits = std::numeric_limits<unsigned int>::max();
0287     int t_charge = std::numeric_limits<int>::max();
0288     float t_time = NaNfloat;
0289     float t_vx = NaNfloat;
0290     float t_vy = NaNfloat;
0291     float t_vz = NaNfloat;
0292     float t_px = NaNfloat;
0293     float t_py = NaNfloat;
0294     float t_pz = NaNfloat;
0295     float t_theta = NaNfloat;
0296     float t_phi = NaNfloat;
0297     float t_eta = NaNfloat;
0298     float t_p = NaNfloat;
0299     float t_pT = NaNfloat;
0300     float t_d0 = NaNfloat;
0301     float t_z0 = NaNfloat;
0302     float t_qop = NaNfloat;
0303     float t_prodR = NaNfloat;
0304 
0305     // Get the perigee surface
0306     const Acts::Surface* pSurface =
0307         track.hasReferenceSurface() ? &track.referenceSurface() : nullptr;
0308 
0309     // Get the majority truth particle to this track
0310     auto match = trackParticleMatching.find(track.index());
0311     bool foundMajorityParticle = false;
0312     // Get the truth particle info
0313     if (match != trackParticleMatching.end() &&
0314         match->second.particle.has_value()) {
0315       // Get the barcode of the majority truth particle
0316       majorityParticleId = match->second.particle.value();
0317       trackClassification = match->second.classification;
0318       nMajorityHits = match->second.contributingParticles.front().hitCount;
0319 
0320       // Find the truth particle via the barcode
0321       auto ip = particles.find(majorityParticleId);
0322       if (ip != particles.end()) {
0323         foundMajorityParticle = true;
0324 
0325         const auto& particle = *ip;
0326         ACTS_VERBOSE("Find the truth particle with barcode "
0327                      << majorityParticleId << "="
0328                      << majorityParticleId.value());
0329         // Get the truth particle info at vertex
0330         t_p = particle.absoluteMomentum();
0331         t_charge = static_cast<int>(particle.charge());
0332         t_time = particle.time();
0333         t_vx = particle.position().x();
0334         t_vy = particle.position().y();
0335         t_vz = particle.position().z();
0336         t_px = t_p * particle.direction().x();
0337         t_py = t_p * particle.direction().y();
0338         t_pz = t_p * particle.direction().z();
0339         t_theta = theta(particle.direction());
0340         t_phi = phi(particle.direction());
0341         t_eta = eta(particle.direction());
0342         t_pT = t_p * perp(particle.direction());
0343         t_qop = particle.qOverP();
0344         t_prodR = std::sqrt(t_vx * t_vx + t_vy * t_vy);
0345 
0346         if (pSurface != nullptr) {
0347           auto intersection =
0348               pSurface
0349                   ->intersect(ctx.geoContext, particle.position(),
0350                               particle.direction(),
0351                               Acts::BoundaryTolerance::Infinite())
0352                   .closest();
0353           auto position = intersection.position();
0354 
0355           // get the truth perigee parameter
0356           auto lpResult = pSurface->globalToLocal(ctx.geoContext, position,
0357                                                   particle.direction());
0358           if (lpResult.ok()) {
0359             t_d0 = lpResult.value()[Acts::BoundIndices::eBoundLoc0];
0360             t_z0 = lpResult.value()[Acts::BoundIndices::eBoundLoc1];
0361           } else {
0362             ACTS_ERROR("Global to local transformation did not succeed.");
0363           }
0364         }
0365       } else {
0366         ACTS_DEBUG("Truth particle with barcode "
0367                    << majorityParticleId << "=" << majorityParticleId.value()
0368                    << " not found in the input collection!");
0369       }
0370     }
0371     if (!foundMajorityParticle) {
0372       ACTS_DEBUG("Truth particle for track " << track.tipIndex()
0373                                              << " not found!");
0374     }
0375 
0376     // Push the corresponding truth particle info for the track.
0377     // Always push back even if majority particle not found
0378     m_majorityParticleId.push_back(majorityParticleId.value());
0379     m_trackClassification.push_back(static_cast<int>(trackClassification));
0380     m_nMajorityHits.push_back(nMajorityHits);
0381     m_t_charge.push_back(t_charge);
0382     m_t_time.push_back(t_time);
0383     m_t_vx.push_back(t_vx);
0384     m_t_vy.push_back(t_vy);
0385     m_t_vz.push_back(t_vz);
0386     m_t_px.push_back(t_px);
0387     m_t_py.push_back(t_py);
0388     m_t_pz.push_back(t_pz);
0389     m_t_theta.push_back(t_theta);
0390     m_t_phi.push_back(t_phi);
0391     m_t_eta.push_back(t_eta);
0392     m_t_p.push_back(t_p);
0393     m_t_pT.push_back(t_pT);
0394     m_t_d0.push_back(t_d0);
0395     m_t_z0.push_back(t_z0);
0396     m_t_prodR.push_back(t_prodR);
0397 
0398     // Initialize the fitted track parameters info
0399     std::array<float, Acts::eBoundSize> param = {NaNfloat, NaNfloat, NaNfloat,
0400                                                  NaNfloat, NaNfloat, NaNfloat};
0401     std::array<float, Acts::eBoundSize> error = {NaNfloat, NaNfloat, NaNfloat,
0402                                                  NaNfloat, NaNfloat, NaNfloat};
0403 
0404     // get entries of covariance matrix. If no entry, return NaN
0405     auto getCov = [&](auto i, auto j) { return track.covariance()(i, j); };
0406 
0407     bool hasFittedParams = track.hasReferenceSurface();
0408     if (hasFittedParams) {
0409       const auto& parameter = track.parameters();
0410       for (unsigned int i = 0; i < Acts::eBoundSize; ++i) {
0411         param[i] = parameter[i];
0412       }
0413 
0414       for (unsigned int i = 0; i < Acts::eBoundSize; ++i) {
0415         double variance = getCov(i, i);
0416         error[i] = variance >= 0 ? std::sqrt(variance) : NaNfloat;
0417       }
0418     }
0419 
0420     std::array<float, Acts::eBoundSize> res = {NaNfloat, NaNfloat, NaNfloat,
0421                                                NaNfloat, NaNfloat, NaNfloat};
0422     std::array<float, Acts::eBoundSize> pull = {NaNfloat, NaNfloat, NaNfloat,
0423                                                 NaNfloat, NaNfloat, NaNfloat};
0424     if (foundMajorityParticle && hasFittedParams) {
0425       res = {param[Acts::eBoundLoc0] - t_d0,
0426              param[Acts::eBoundLoc1] - t_z0,
0427              Acts::detail::difference_periodic(
0428                  param[Acts::eBoundPhi], t_phi,
0429                  static_cast<float>(2 * std::numbers::pi)),
0430              param[Acts::eBoundTheta] - t_theta,
0431              param[Acts::eBoundQOverP] - t_qop,
0432              param[Acts::eBoundTime] - t_time};
0433 
0434       for (unsigned int i = 0; i < Acts::eBoundSize; ++i) {
0435         pull[i] = res[i] / error[i];
0436       }
0437     }
0438 
0439     // Push the fitted track parameters.
0440     // Always push back even if no fitted track parameters
0441     m_eLOC0_fit.push_back(param[Acts::eBoundLoc0]);
0442     m_eLOC1_fit.push_back(param[Acts::eBoundLoc1]);
0443     m_ePHI_fit.push_back(param[Acts::eBoundPhi]);
0444     m_eTHETA_fit.push_back(param[Acts::eBoundTheta]);
0445     m_eQOP_fit.push_back(param[Acts::eBoundQOverP]);
0446     m_eT_fit.push_back(param[Acts::eBoundTime]);
0447 
0448     m_res_eLOC0_fit.push_back(res[Acts::eBoundLoc0]);
0449     m_res_eLOC1_fit.push_back(res[Acts::eBoundLoc1]);
0450     m_res_ePHI_fit.push_back(res[Acts::eBoundPhi]);
0451     m_res_eTHETA_fit.push_back(res[Acts::eBoundTheta]);
0452     m_res_eQOP_fit.push_back(res[Acts::eBoundQOverP]);
0453     m_res_eT_fit.push_back(res[Acts::eBoundTime]);
0454 
0455     m_err_eLOC0_fit.push_back(error[Acts::eBoundLoc0]);
0456     m_err_eLOC1_fit.push_back(error[Acts::eBoundLoc1]);
0457     m_err_ePHI_fit.push_back(error[Acts::eBoundPhi]);
0458     m_err_eTHETA_fit.push_back(error[Acts::eBoundTheta]);
0459     m_err_eQOP_fit.push_back(error[Acts::eBoundQOverP]);
0460     m_err_eT_fit.push_back(error[Acts::eBoundTime]);
0461 
0462     m_pull_eLOC0_fit.push_back(pull[Acts::eBoundLoc0]);
0463     m_pull_eLOC1_fit.push_back(pull[Acts::eBoundLoc1]);
0464     m_pull_ePHI_fit.push_back(pull[Acts::eBoundPhi]);
0465     m_pull_eTHETA_fit.push_back(pull[Acts::eBoundTheta]);
0466     m_pull_eQOP_fit.push_back(pull[Acts::eBoundQOverP]);
0467     m_pull_eT_fit.push_back(pull[Acts::eBoundTime]);
0468 
0469     m_hasFittedParams.push_back(hasFittedParams);
0470 
0471     if (m_cfg.writeGsfSpecific) {
0472       using namespace Acts::GsfConstants;
0473       if (tracks.hasColumn(Acts::hashString(kFwdMaxMaterialXOverX0))) {
0474         m_gsf_max_material_fwd.push_back(
0475             track.template component<double>(kFwdMaxMaterialXOverX0));
0476       } else {
0477         m_gsf_max_material_fwd.push_back(NaNfloat);
0478       }
0479 
0480       if (tracks.hasColumn(Acts::hashString(kFwdSumMaterialXOverX0))) {
0481         m_gsf_sum_material_fwd.push_back(
0482             track.template component<double>(kFwdSumMaterialXOverX0));
0483       } else {
0484         m_gsf_sum_material_fwd.push_back(NaNfloat);
0485       }
0486     }
0487 
0488     if (m_cfg.writeCovMat) {
0489       // write all entries of covariance matrix to output file
0490       // one branch for every entry of the matrix.
0491       m_cov_eLOC0_eLOC0.push_back(getCov(0, 0));
0492       m_cov_eLOC0_eLOC1.push_back(getCov(0, 1));
0493       m_cov_eLOC0_ePHI.push_back(getCov(0, 2));
0494       m_cov_eLOC0_eTHETA.push_back(getCov(0, 3));
0495       m_cov_eLOC0_eQOP.push_back(getCov(0, 4));
0496       m_cov_eLOC0_eT.push_back(getCov(0, 5));
0497 
0498       m_cov_eLOC1_eLOC0.push_back(getCov(1, 0));
0499       m_cov_eLOC1_eLOC1.push_back(getCov(1, 1));
0500       m_cov_eLOC1_ePHI.push_back(getCov(1, 2));
0501       m_cov_eLOC1_eTHETA.push_back(getCov(1, 3));
0502       m_cov_eLOC1_eQOP.push_back(getCov(1, 4));
0503       m_cov_eLOC1_eT.push_back(getCov(1, 5));
0504 
0505       m_cov_ePHI_eLOC0.push_back(getCov(2, 0));
0506       m_cov_ePHI_eLOC1.push_back(getCov(2, 1));
0507       m_cov_ePHI_ePHI.push_back(getCov(2, 2));
0508       m_cov_ePHI_eTHETA.push_back(getCov(2, 3));
0509       m_cov_ePHI_eQOP.push_back(getCov(2, 4));
0510       m_cov_ePHI_eT.push_back(getCov(2, 5));
0511 
0512       m_cov_eTHETA_eLOC0.push_back(getCov(3, 0));
0513       m_cov_eTHETA_eLOC1.push_back(getCov(3, 1));
0514       m_cov_eTHETA_ePHI.push_back(getCov(3, 2));
0515       m_cov_eTHETA_eTHETA.push_back(getCov(3, 3));
0516       m_cov_eTHETA_eQOP.push_back(getCov(3, 4));
0517       m_cov_eTHETA_eT.push_back(getCov(3, 5));
0518 
0519       m_cov_eQOP_eLOC0.push_back(getCov(4, 0));
0520       m_cov_eQOP_eLOC1.push_back(getCov(4, 1));
0521       m_cov_eQOP_ePHI.push_back(getCov(4, 2));
0522       m_cov_eQOP_eTHETA.push_back(getCov(4, 3));
0523       m_cov_eQOP_eQOP.push_back(getCov(4, 4));
0524       m_cov_eQOP_eT.push_back(getCov(4, 5));
0525 
0526       m_cov_eT_eLOC0.push_back(getCov(5, 0));
0527       m_cov_eT_eLOC1.push_back(getCov(5, 1));
0528       m_cov_eT_ePHI.push_back(getCov(5, 2));
0529       m_cov_eT_eTHETA.push_back(getCov(5, 3));
0530       m_cov_eT_eQOP.push_back(getCov(5, 4));
0531       m_cov_eT_eT.push_back(getCov(5, 5));
0532     }
0533 
0534     if (m_cfg.writeGx2fSpecific) {
0535       if (tracks.hasColumn(Acts::hashString("Gx2fnUpdateColumn"))) {
0536         int nUpdate = static_cast<int>(
0537             track.template component<std::uint32_t,
0538                                      Acts::hashString("Gx2fnUpdateColumn")>());
0539         m_nUpdatesGx2f.push_back(nUpdate);
0540       } else {
0541         m_nUpdatesGx2f.push_back(-1);
0542       }
0543     }
0544   }
0545 
0546   // fill the variables
0547   m_outputTree->Fill();
0548 
0549   m_trackNr.clear();
0550   m_nStates.clear();
0551   m_nMeasurements.clear();
0552   m_nOutliers.clear();
0553   m_nHoles.clear();
0554   m_nSharedHits.clear();
0555   m_chi2Sum.clear();
0556   m_NDF.clear();
0557   m_measurementChi2.clear();
0558   m_outlierChi2.clear();
0559   m_measurementVolume.clear();
0560   m_measurementLayer.clear();
0561   m_outlierVolume.clear();
0562   m_outlierLayer.clear();
0563 
0564   m_nMajorityHits.clear();
0565   m_majorityParticleId.clear();
0566   m_trackClassification.clear();
0567   m_t_charge.clear();
0568   m_t_time.clear();
0569   m_t_vx.clear();
0570   m_t_vy.clear();
0571   m_t_vz.clear();
0572   m_t_px.clear();
0573   m_t_py.clear();
0574   m_t_pz.clear();
0575   m_t_theta.clear();
0576   m_t_phi.clear();
0577   m_t_p.clear();
0578   m_t_pT.clear();
0579   m_t_eta.clear();
0580   m_t_d0.clear();
0581   m_t_z0.clear();
0582   m_t_prodR.clear();
0583 
0584   m_hasFittedParams.clear();
0585   m_eLOC0_fit.clear();
0586   m_eLOC1_fit.clear();
0587   m_ePHI_fit.clear();
0588   m_eTHETA_fit.clear();
0589   m_eQOP_fit.clear();
0590   m_eT_fit.clear();
0591   m_err_eLOC0_fit.clear();
0592   m_err_eLOC1_fit.clear();
0593   m_err_ePHI_fit.clear();
0594   m_err_eTHETA_fit.clear();
0595   m_err_eQOP_fit.clear();
0596   m_err_eT_fit.clear();
0597   m_res_eLOC0_fit.clear();
0598   m_res_eLOC1_fit.clear();
0599   m_res_ePHI_fit.clear();
0600   m_res_eTHETA_fit.clear();
0601   m_res_eQOP_fit.clear();
0602   m_res_eT_fit.clear();
0603   m_pull_eLOC0_fit.clear();
0604   m_pull_eLOC1_fit.clear();
0605   m_pull_ePHI_fit.clear();
0606   m_pull_eTHETA_fit.clear();
0607   m_pull_eQOP_fit.clear();
0608   m_pull_eT_fit.clear();
0609 
0610   m_gsf_max_material_fwd.clear();
0611   m_gsf_sum_material_fwd.clear();
0612 
0613   if (m_cfg.writeCovMat) {
0614     m_cov_eLOC0_eLOC0.clear();
0615     m_cov_eLOC0_eLOC1.clear();
0616     m_cov_eLOC0_ePHI.clear();
0617     m_cov_eLOC0_eTHETA.clear();
0618     m_cov_eLOC0_eQOP.clear();
0619     m_cov_eLOC0_eT.clear();
0620 
0621     m_cov_eLOC1_eLOC0.clear();
0622     m_cov_eLOC1_eLOC1.clear();
0623     m_cov_eLOC1_ePHI.clear();
0624     m_cov_eLOC1_eTHETA.clear();
0625     m_cov_eLOC1_eQOP.clear();
0626     m_cov_eLOC1_eT.clear();
0627 
0628     m_cov_ePHI_eLOC0.clear();
0629     m_cov_ePHI_eLOC1.clear();
0630     m_cov_ePHI_ePHI.clear();
0631     m_cov_ePHI_eTHETA.clear();
0632     m_cov_ePHI_eQOP.clear();
0633     m_cov_ePHI_eT.clear();
0634 
0635     m_cov_eTHETA_eLOC0.clear();
0636     m_cov_eTHETA_eLOC1.clear();
0637     m_cov_eTHETA_ePHI.clear();
0638     m_cov_eTHETA_eTHETA.clear();
0639     m_cov_eTHETA_eQOP.clear();
0640     m_cov_eTHETA_eT.clear();
0641 
0642     m_cov_eQOP_eLOC0.clear();
0643     m_cov_eQOP_eLOC1.clear();
0644     m_cov_eQOP_ePHI.clear();
0645     m_cov_eQOP_eTHETA.clear();
0646     m_cov_eQOP_eQOP.clear();
0647     m_cov_eQOP_eT.clear();
0648 
0649     m_cov_eT_eLOC0.clear();
0650     m_cov_eT_eLOC1.clear();
0651     m_cov_eT_ePHI.clear();
0652     m_cov_eT_eTHETA.clear();
0653     m_cov_eT_eQOP.clear();
0654     m_cov_eT_eT.clear();
0655   }
0656 
0657   m_nUpdatesGx2f.clear();
0658 
0659   return ProcessCode::SUCCESS;
0660 }
0661 
0662 }  // namespace ActsExamples