File indexing completed on 2025-08-05 08:10:02
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "ActsExamples/Io/Root/RootTrackStatesWriter.hpp"
0010
0011 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/Definitions/Common.hpp"
0013 #include "Acts/Definitions/TrackParametrization.hpp"
0014 #include "Acts/EventData/MultiTrajectory.hpp"
0015 #include "Acts/EventData/MultiTrajectoryHelpers.hpp"
0016 #include "Acts/EventData/TrackParameters.hpp"
0017 #include "Acts/EventData/TransformationHelpers.hpp"
0018 #include "Acts/EventData/VectorMultiTrajectory.hpp"
0019 #include "Acts/Geometry/GeometryContext.hpp"
0020 #include "Acts/Utilities/MultiIndex.hpp"
0021 #include "Acts/Utilities/detail/periodic.hpp"
0022 #include "ActsExamples/EventData/AverageSimHits.hpp"
0023 #include "ActsExamples/EventData/IndexSourceLink.hpp"
0024 #include "ActsExamples/EventData/Track.hpp"
0025 #include "ActsExamples/Framework/AlgorithmContext.hpp"
0026 #include "ActsExamples/Utilities/Range.hpp"
0027 #include "ActsExamples/Validation/TrackClassification.hpp"
0028 #include "ActsFatras/EventData/Barcode.hpp"
0029 #include "ActsFatras/EventData/Particle.hpp"
0030
0031 #include <cmath>
0032 #include <cstddef>
0033 #include <ios>
0034 #include <limits>
0035 #include <memory>
0036 #include <optional>
0037 #include <ostream>
0038 #include <stdexcept>
0039 #include <utility>
0040
0041 #include <TFile.h>
0042 #include <TTree.h>
0043
0044 namespace ActsExamples {
0045 class IndexSourceLink;
0046 }
0047
0048 using Acts::VectorHelpers::eta;
0049 using Acts::VectorHelpers::perp;
0050 using Acts::VectorHelpers::phi;
0051 using Acts::VectorHelpers::theta;
0052
0053 ActsExamples::RootTrackStatesWriter::RootTrackStatesWriter(
0054 const ActsExamples::RootTrackStatesWriter::Config& config,
0055 Acts::Logging::Level level)
0056 : WriterT(config.inputTracks, "RootTrackStatesWriter", level),
0057 m_cfg(config) {
0058
0059 if (m_cfg.inputParticles.empty()) {
0060 throw std::invalid_argument("Missing particles input collection");
0061 }
0062 if (m_cfg.inputTrackParticleMatching.empty()) {
0063 throw std::invalid_argument("Missing input track particles matching");
0064 }
0065 if (m_cfg.inputSimHits.empty()) {
0066 throw std::invalid_argument("Missing simulated hits input collection");
0067 }
0068 if (m_cfg.inputMeasurementSimHitsMap.empty()) {
0069 throw std::invalid_argument(
0070 "Missing hit-simulated-hits map input collection");
0071 }
0072 if (m_cfg.filePath.empty()) {
0073 throw std::invalid_argument("Missing output filename");
0074 }
0075 if (m_cfg.treeName.empty()) {
0076 throw std::invalid_argument("Missing tree name");
0077 }
0078
0079 m_inputParticles.initialize(m_cfg.inputParticles);
0080 m_inputTrackParticleMatching.initialize(m_cfg.inputTrackParticleMatching);
0081 m_inputSimHits.initialize(m_cfg.inputSimHits);
0082 m_inputMeasurementSimHitsMap.initialize(m_cfg.inputMeasurementSimHitsMap);
0083
0084
0085 auto path = m_cfg.filePath;
0086 m_outputFile = TFile::Open(path.c_str(), m_cfg.fileMode.c_str());
0087 if (m_outputFile == nullptr) {
0088 throw std::ios_base::failure("Could not open '" + path + "'");
0089 }
0090 m_outputFile->cd();
0091 m_outputTree = new TTree(m_cfg.treeName.c_str(), m_cfg.treeName.c_str());
0092 if (m_outputTree == nullptr) {
0093 throw std::bad_alloc();
0094 } else {
0095
0096 m_outputTree->Branch("event_nr", &m_eventNr);
0097 m_outputTree->Branch("track_nr", &m_trackNr);
0098
0099 m_outputTree->Branch("t_x", &m_t_x);
0100 m_outputTree->Branch("t_y", &m_t_y);
0101 m_outputTree->Branch("t_z", &m_t_z);
0102 m_outputTree->Branch("t_r", &m_t_r);
0103 m_outputTree->Branch("t_dx", &m_t_dx);
0104 m_outputTree->Branch("t_dy", &m_t_dy);
0105 m_outputTree->Branch("t_dz", &m_t_dz);
0106 m_outputTree->Branch("t_eLOC0", &m_t_eLOC0);
0107 m_outputTree->Branch("t_eLOC1", &m_t_eLOC1);
0108 m_outputTree->Branch("t_ePHI", &m_t_ePHI);
0109 m_outputTree->Branch("t_eTHETA", &m_t_eTHETA);
0110 m_outputTree->Branch("t_eQOP", &m_t_eQOP);
0111 m_outputTree->Branch("t_eT", &m_t_eT);
0112 m_outputTree->Branch("particle_ids", &m_particleId);
0113
0114 m_outputTree->Branch("nStates", &m_nStates);
0115 m_outputTree->Branch("nMeasurements", &m_nMeasurements);
0116 m_outputTree->Branch("volume_id", &m_volumeID);
0117 m_outputTree->Branch("layer_id", &m_layerID);
0118 m_outputTree->Branch("module_id", &m_moduleID);
0119 m_outputTree->Branch("pathLength", &m_pathLength);
0120 m_outputTree->Branch("l_x_hit", &m_lx_hit);
0121 m_outputTree->Branch("l_y_hit", &m_ly_hit);
0122 m_outputTree->Branch("g_x_hit", &m_x_hit);
0123 m_outputTree->Branch("g_y_hit", &m_y_hit);
0124 m_outputTree->Branch("g_z_hit", &m_z_hit);
0125 m_outputTree->Branch("res_x_hit", &m_res_x_hit);
0126 m_outputTree->Branch("res_y_hit", &m_res_y_hit);
0127 m_outputTree->Branch("err_x_hit", &m_err_x_hit);
0128 m_outputTree->Branch("err_y_hit", &m_err_y_hit);
0129 m_outputTree->Branch("pull_x_hit", &m_pull_x_hit);
0130 m_outputTree->Branch("pull_y_hit", &m_pull_y_hit);
0131 m_outputTree->Branch("dim_hit", &m_dim_hit);
0132
0133 m_outputTree->Branch("nPredicted", &m_nParams[ePredicted]);
0134 m_outputTree->Branch("predicted", &m_hasParams[ePredicted]);
0135 m_outputTree->Branch("eLOC0_prt", &m_eLOC0[ePredicted]);
0136 m_outputTree->Branch("eLOC1_prt", &m_eLOC1[ePredicted]);
0137 m_outputTree->Branch("ePHI_prt", &m_ePHI[ePredicted]);
0138 m_outputTree->Branch("eTHETA_prt", &m_eTHETA[ePredicted]);
0139 m_outputTree->Branch("eQOP_prt", &m_eQOP[ePredicted]);
0140 m_outputTree->Branch("eT_prt", &m_eT[ePredicted]);
0141 m_outputTree->Branch("res_eLOC0_prt", &m_res_eLOC0[ePredicted]);
0142 m_outputTree->Branch("res_eLOC1_prt", &m_res_eLOC1[ePredicted]);
0143 m_outputTree->Branch("res_ePHI_prt", &m_res_ePHI[ePredicted]);
0144 m_outputTree->Branch("res_eTHETA_prt", &m_res_eTHETA[ePredicted]);
0145 m_outputTree->Branch("res_eQOP_prt", &m_res_eQOP[ePredicted]);
0146 m_outputTree->Branch("res_eT_prt", &m_res_eT[ePredicted]);
0147 m_outputTree->Branch("err_eLOC0_prt", &m_err_eLOC0[ePredicted]);
0148 m_outputTree->Branch("err_eLOC1_prt", &m_err_eLOC1[ePredicted]);
0149 m_outputTree->Branch("err_ePHI_prt", &m_err_ePHI[ePredicted]);
0150 m_outputTree->Branch("err_eTHETA_prt", &m_err_eTHETA[ePredicted]);
0151 m_outputTree->Branch("err_eQOP_prt", &m_err_eQOP[ePredicted]);
0152 m_outputTree->Branch("err_eT_prt", &m_err_eT[ePredicted]);
0153 m_outputTree->Branch("pull_eLOC0_prt", &m_pull_eLOC0[ePredicted]);
0154 m_outputTree->Branch("pull_eLOC1_prt", &m_pull_eLOC1[ePredicted]);
0155 m_outputTree->Branch("pull_ePHI_prt", &m_pull_ePHI[ePredicted]);
0156 m_outputTree->Branch("pull_eTHETA_prt", &m_pull_eTHETA[ePredicted]);
0157 m_outputTree->Branch("pull_eQOP_prt", &m_pull_eQOP[ePredicted]);
0158 m_outputTree->Branch("pull_eT_prt", &m_pull_eT[ePredicted]);
0159 m_outputTree->Branch("g_x_prt", &m_x[ePredicted]);
0160 m_outputTree->Branch("g_y_prt", &m_y[ePredicted]);
0161 m_outputTree->Branch("g_z_prt", &m_z[ePredicted]);
0162 m_outputTree->Branch("px_prt", &m_px[ePredicted]);
0163 m_outputTree->Branch("py_prt", &m_py[ePredicted]);
0164 m_outputTree->Branch("pz_prt", &m_pz[ePredicted]);
0165 m_outputTree->Branch("eta_prt", &m_eta[ePredicted]);
0166 m_outputTree->Branch("pT_prt", &m_pT[ePredicted]);
0167
0168 m_outputTree->Branch("nFiltered", &m_nParams[eFiltered]);
0169 m_outputTree->Branch("filtered", &m_hasParams[eFiltered]);
0170 m_outputTree->Branch("eLOC0_flt", &m_eLOC0[eFiltered]);
0171 m_outputTree->Branch("eLOC1_flt", &m_eLOC1[eFiltered]);
0172 m_outputTree->Branch("ePHI_flt", &m_ePHI[eFiltered]);
0173 m_outputTree->Branch("eTHETA_flt", &m_eTHETA[eFiltered]);
0174 m_outputTree->Branch("eQOP_flt", &m_eQOP[eFiltered]);
0175 m_outputTree->Branch("eT_flt", &m_eT[eFiltered]);
0176 m_outputTree->Branch("res_eLOC0_flt", &m_res_eLOC0[eFiltered]);
0177 m_outputTree->Branch("res_eLOC1_flt", &m_res_eLOC1[eFiltered]);
0178 m_outputTree->Branch("res_ePHI_flt", &m_res_ePHI[eFiltered]);
0179 m_outputTree->Branch("res_eTHETA_flt", &m_res_eTHETA[eFiltered]);
0180 m_outputTree->Branch("res_eQOP_flt", &m_res_eQOP[eFiltered]);
0181 m_outputTree->Branch("res_eT_flt", &m_res_eT[eFiltered]);
0182 m_outputTree->Branch("err_eLOC0_flt", &m_err_eLOC0[eFiltered]);
0183 m_outputTree->Branch("err_eLOC1_flt", &m_err_eLOC1[eFiltered]);
0184 m_outputTree->Branch("err_ePHI_flt", &m_err_ePHI[eFiltered]);
0185 m_outputTree->Branch("err_eTHETA_flt", &m_err_eTHETA[eFiltered]);
0186 m_outputTree->Branch("err_eQOP_flt", &m_err_eQOP[eFiltered]);
0187 m_outputTree->Branch("err_eT_flt", &m_err_eT[eFiltered]);
0188 m_outputTree->Branch("pull_eLOC0_flt", &m_pull_eLOC0[eFiltered]);
0189 m_outputTree->Branch("pull_eLOC1_flt", &m_pull_eLOC1[eFiltered]);
0190 m_outputTree->Branch("pull_ePHI_flt", &m_pull_ePHI[eFiltered]);
0191 m_outputTree->Branch("pull_eTHETA_flt", &m_pull_eTHETA[eFiltered]);
0192 m_outputTree->Branch("pull_eQOP_flt", &m_pull_eQOP[eFiltered]);
0193 m_outputTree->Branch("pull_eT_flt", &m_pull_eT[eFiltered]);
0194 m_outputTree->Branch("g_x_flt", &m_x[eFiltered]);
0195 m_outputTree->Branch("g_y_flt", &m_y[eFiltered]);
0196 m_outputTree->Branch("g_z_flt", &m_z[eFiltered]);
0197 m_outputTree->Branch("px_flt", &m_px[eFiltered]);
0198 m_outputTree->Branch("py_flt", &m_py[eFiltered]);
0199 m_outputTree->Branch("pz_flt", &m_pz[eFiltered]);
0200 m_outputTree->Branch("eta_flt", &m_eta[eFiltered]);
0201 m_outputTree->Branch("pT_flt", &m_pT[eFiltered]);
0202
0203 m_outputTree->Branch("nSmoothed", &m_nParams[eSmoothed]);
0204 m_outputTree->Branch("smoothed", &m_hasParams[eSmoothed]);
0205 m_outputTree->Branch("eLOC0_smt", &m_eLOC0[eSmoothed]);
0206 m_outputTree->Branch("eLOC1_smt", &m_eLOC1[eSmoothed]);
0207 m_outputTree->Branch("ePHI_smt", &m_ePHI[eSmoothed]);
0208 m_outputTree->Branch("eTHETA_smt", &m_eTHETA[eSmoothed]);
0209 m_outputTree->Branch("eQOP_smt", &m_eQOP[eSmoothed]);
0210 m_outputTree->Branch("eT_smt", &m_eT[eSmoothed]);
0211 m_outputTree->Branch("res_eLOC0_smt", &m_res_eLOC0[eSmoothed]);
0212 m_outputTree->Branch("res_eLOC1_smt", &m_res_eLOC1[eSmoothed]);
0213 m_outputTree->Branch("res_ePHI_smt", &m_res_ePHI[eSmoothed]);
0214 m_outputTree->Branch("res_eTHETA_smt", &m_res_eTHETA[eSmoothed]);
0215 m_outputTree->Branch("res_eQOP_smt", &m_res_eQOP[eSmoothed]);
0216 m_outputTree->Branch("res_eT_smt", &m_res_eT[eSmoothed]);
0217 m_outputTree->Branch("err_eLOC0_smt", &m_err_eLOC0[eSmoothed]);
0218 m_outputTree->Branch("err_eLOC1_smt", &m_err_eLOC1[eSmoothed]);
0219 m_outputTree->Branch("err_ePHI_smt", &m_err_ePHI[eSmoothed]);
0220 m_outputTree->Branch("err_eTHETA_smt", &m_err_eTHETA[eSmoothed]);
0221 m_outputTree->Branch("err_eQOP_smt", &m_err_eQOP[eSmoothed]);
0222 m_outputTree->Branch("err_eT_smt", &m_err_eT[eSmoothed]);
0223 m_outputTree->Branch("pull_eLOC0_smt", &m_pull_eLOC0[eSmoothed]);
0224 m_outputTree->Branch("pull_eLOC1_smt", &m_pull_eLOC1[eSmoothed]);
0225 m_outputTree->Branch("pull_ePHI_smt", &m_pull_ePHI[eSmoothed]);
0226 m_outputTree->Branch("pull_eTHETA_smt", &m_pull_eTHETA[eSmoothed]);
0227 m_outputTree->Branch("pull_eQOP_smt", &m_pull_eQOP[eSmoothed]);
0228 m_outputTree->Branch("pull_eT_smt", &m_pull_eT[eSmoothed]);
0229 m_outputTree->Branch("g_x_smt", &m_x[eSmoothed]);
0230 m_outputTree->Branch("g_y_smt", &m_y[eSmoothed]);
0231 m_outputTree->Branch("g_z_smt", &m_z[eSmoothed]);
0232 m_outputTree->Branch("px_smt", &m_px[eSmoothed]);
0233 m_outputTree->Branch("py_smt", &m_py[eSmoothed]);
0234 m_outputTree->Branch("pz_smt", &m_pz[eSmoothed]);
0235 m_outputTree->Branch("eta_smt", &m_eta[eSmoothed]);
0236 m_outputTree->Branch("pT_smt", &m_pT[eSmoothed]);
0237
0238 m_outputTree->Branch("nUnbiased", &m_nParams[eUnbiased]);
0239 m_outputTree->Branch("unbiased", &m_hasParams[eUnbiased]);
0240 m_outputTree->Branch("eLOC0_ubs", &m_eLOC0[eUnbiased]);
0241 m_outputTree->Branch("eLOC1_ubs", &m_eLOC1[eUnbiased]);
0242 m_outputTree->Branch("ePHI_ubs", &m_ePHI[eUnbiased]);
0243 m_outputTree->Branch("eTHETA_ubs", &m_eTHETA[eUnbiased]);
0244 m_outputTree->Branch("eQOP_ubs", &m_eQOP[eUnbiased]);
0245 m_outputTree->Branch("eT_ubs", &m_eT[eUnbiased]);
0246 m_outputTree->Branch("res_eLOC0_ubs", &m_res_eLOC0[eUnbiased]);
0247 m_outputTree->Branch("res_eLOC1_ubs", &m_res_eLOC1[eUnbiased]);
0248 m_outputTree->Branch("res_ePHI_ubs", &m_res_ePHI[eUnbiased]);
0249 m_outputTree->Branch("res_eTHETA_ubs", &m_res_eTHETA[eUnbiased]);
0250 m_outputTree->Branch("res_eQOP_ubs", &m_res_eQOP[eUnbiased]);
0251 m_outputTree->Branch("res_eT_ubs", &m_res_eT[eUnbiased]);
0252 m_outputTree->Branch("err_eLOC0_ubs", &m_err_eLOC0[eUnbiased]);
0253 m_outputTree->Branch("err_eLOC1_ubs", &m_err_eLOC1[eUnbiased]);
0254 m_outputTree->Branch("err_ePHI_ubs", &m_err_ePHI[eUnbiased]);
0255 m_outputTree->Branch("err_eTHETA_ubs", &m_err_eTHETA[eUnbiased]);
0256 m_outputTree->Branch("err_eQOP_ubs", &m_err_eQOP[eUnbiased]);
0257 m_outputTree->Branch("err_eT_ubs", &m_err_eT[eUnbiased]);
0258 m_outputTree->Branch("pull_eLOC0_ubs", &m_pull_eLOC0[eUnbiased]);
0259 m_outputTree->Branch("pull_eLOC1_ubs", &m_pull_eLOC1[eUnbiased]);
0260 m_outputTree->Branch("pull_ePHI_ubs", &m_pull_ePHI[eUnbiased]);
0261 m_outputTree->Branch("pull_eTHETA_ubs", &m_pull_eTHETA[eUnbiased]);
0262 m_outputTree->Branch("pull_eQOP_ubs", &m_pull_eQOP[eUnbiased]);
0263 m_outputTree->Branch("pull_eT_ubs", &m_pull_eT[eUnbiased]);
0264 m_outputTree->Branch("g_x_ubs", &m_x[eUnbiased]);
0265 m_outputTree->Branch("g_y_ubs", &m_y[eUnbiased]);
0266 m_outputTree->Branch("g_z_ubs", &m_z[eUnbiased]);
0267 m_outputTree->Branch("px_ubs", &m_px[eUnbiased]);
0268 m_outputTree->Branch("py_ubs", &m_py[eUnbiased]);
0269 m_outputTree->Branch("pz_ubs", &m_pz[eUnbiased]);
0270 m_outputTree->Branch("eta_ubs", &m_eta[eUnbiased]);
0271 m_outputTree->Branch("pT_ubs", &m_pT[eUnbiased]);
0272
0273 m_outputTree->Branch("chi2", &m_chi2);
0274 }
0275 }
0276
0277 ActsExamples::RootTrackStatesWriter::~RootTrackStatesWriter() {
0278 m_outputFile->Close();
0279 }
0280
0281 ActsExamples::ProcessCode ActsExamples::RootTrackStatesWriter::finalize() {
0282 m_outputFile->cd();
0283 m_outputTree->Write();
0284 m_outputFile->Close();
0285
0286 ACTS_INFO("Wrote states of trajectories to tree '"
0287 << m_cfg.treeName << "' in '" << m_cfg.treeName << "'");
0288
0289 return ProcessCode::SUCCESS;
0290 }
0291
0292 ActsExamples::ProcessCode ActsExamples::RootTrackStatesWriter::writeT(
0293 const AlgorithmContext& ctx, const ConstTrackContainer& tracks) {
0294 float nan = std::numeric_limits<float>::quiet_NaN();
0295
0296 auto& gctx = ctx.geoContext;
0297
0298 const auto& particles = m_inputParticles(ctx);
0299 const auto& trackParticleMatching = m_inputTrackParticleMatching(ctx);
0300 const auto& simHits = m_inputSimHits(ctx);
0301 const auto& hitSimHitsMap = m_inputMeasurementSimHitsMap(ctx);
0302
0303
0304 std::lock_guard<std::mutex> lock(m_writeMutex);
0305
0306
0307 m_eventNr = ctx.eventNumber;
0308
0309 for (const auto& track : tracks) {
0310 m_trackNr = track.index();
0311
0312
0313 m_nMeasurements = track.nMeasurements();
0314 m_nStates = track.nTrackStates();
0315
0316
0317 int truthQ = 1.;
0318 auto match = trackParticleMatching.find(track.index());
0319 if (match != trackParticleMatching.end() &&
0320 match->second.particle.has_value()) {
0321
0322 auto barcode = match->second.particle.value();
0323
0324 auto ip = particles.find(barcode);
0325 if (ip != particles.end()) {
0326 const auto& particle = *ip;
0327 ACTS_VERBOSE("Find the truth particle with barcode "
0328 << barcode << "=" << barcode.value());
0329
0330 truthQ = static_cast<int>(particle.charge());
0331 } else {
0332 ACTS_DEBUG("Truth particle with barcode "
0333 << barcode << "=" << barcode.value() << " not found!");
0334 }
0335 }
0336
0337
0338 m_nParams = {0, 0, 0, 0};
0339
0340
0341
0342 std::vector<std::uint64_t> particleIds;
0343
0344 for (const auto& state : track.trackStatesReversed()) {
0345 const auto& surface = state.referenceSurface();
0346
0347
0348 auto geoID = surface.geometryId();
0349 m_volumeID.push_back(geoID.volume());
0350 m_layerID.push_back(geoID.layer());
0351 m_moduleID.push_back(geoID.sensitive());
0352
0353
0354 m_pathLength.push_back(state.pathLength());
0355
0356
0357 m_chi2.push_back(state.chi2());
0358
0359
0360 float truthLOC0 = nan;
0361 float truthLOC1 = nan;
0362 float truthTIME = nan;
0363 float truthPHI = nan;
0364 float truthTHETA = nan;
0365 float truthQOP = nan;
0366
0367 particleIds.clear();
0368
0369 if (!state.hasUncalibratedSourceLink()) {
0370 m_t_x.push_back(nan);
0371 m_t_y.push_back(nan);
0372 m_t_z.push_back(nan);
0373 m_t_r.push_back(nan);
0374 m_t_dx.push_back(nan);
0375 m_t_dy.push_back(nan);
0376 m_t_dz.push_back(nan);
0377 m_t_eLOC0.push_back(nan);
0378 m_t_eLOC1.push_back(nan);
0379 m_t_ePHI.push_back(nan);
0380 m_t_eTHETA.push_back(nan);
0381 m_t_eQOP.push_back(nan);
0382 m_t_eT.push_back(nan);
0383
0384 m_lx_hit.push_back(nan);
0385 m_ly_hit.push_back(nan);
0386 m_x_hit.push_back(nan);
0387 m_y_hit.push_back(nan);
0388 m_z_hit.push_back(nan);
0389 } else {
0390
0391
0392 auto sl =
0393 state.getUncalibratedSourceLink().template get<IndexSourceLink>();
0394 const auto hitIdx = sl.index();
0395 auto indices = makeRange(hitSimHitsMap.equal_range(hitIdx));
0396 auto [truthLocal, truthPos4, truthUnitDir] =
0397 averageSimHits(ctx.geoContext, surface, simHits, indices, logger());
0398
0399
0400 if (!indices.empty()) {
0401
0402
0403 const auto simHitIdx0 = indices.begin()->second;
0404 const auto& simHit0 = *simHits.nth(simHitIdx0);
0405 const auto p =
0406 simHit0.momentum4Before().template segment<3>(Acts::eMom0).norm();
0407 truthQOP = truthQ / p;
0408
0409
0410 for (auto const& [key, simHitIdx] : indices) {
0411 const auto& simHit = *simHits.nth(simHitIdx);
0412 particleIds.push_back(simHit.particleId().value());
0413 }
0414 }
0415
0416
0417 m_t_x.push_back(truthPos4[Acts::ePos0]);
0418 m_t_y.push_back(truthPos4[Acts::ePos1]);
0419 m_t_z.push_back(truthPos4[Acts::ePos2]);
0420 m_t_r.push_back(perp(truthPos4.template segment<3>(Acts::ePos0)));
0421 m_t_dx.push_back(truthUnitDir[Acts::eMom0]);
0422 m_t_dy.push_back(truthUnitDir[Acts::eMom1]);
0423 m_t_dz.push_back(truthUnitDir[Acts::eMom2]);
0424
0425
0426 truthLOC0 = truthLocal[Acts::ePos0];
0427 truthLOC1 = truthLocal[Acts::ePos1];
0428 truthTIME = truthPos4[Acts::eTime];
0429 truthPHI = phi(truthUnitDir);
0430 truthTHETA = theta(truthUnitDir);
0431
0432
0433 m_t_eLOC0.push_back(truthLOC0);
0434 m_t_eLOC1.push_back(truthLOC1);
0435 m_t_ePHI.push_back(truthPHI);
0436 m_t_eTHETA.push_back(truthTHETA);
0437 m_t_eQOP.push_back(truthQOP);
0438 m_t_eT.push_back(truthTIME);
0439
0440
0441 Acts::BoundVector meas = state.effectiveProjector().transpose() *
0442 state.effectiveCalibrated();
0443
0444 Acts::Vector2 local(meas[Acts::eBoundLoc0], meas[Acts::eBoundLoc1]);
0445 Acts::Vector3 global =
0446 surface.localToGlobal(ctx.geoContext, local, truthUnitDir);
0447
0448
0449 m_lx_hit.push_back(local[Acts::ePos0]);
0450 m_ly_hit.push_back(local[Acts::ePos1]);
0451 m_x_hit.push_back(global[Acts::ePos0]);
0452 m_y_hit.push_back(global[Acts::ePos1]);
0453 m_z_hit.push_back(global[Acts::ePos2]);
0454 }
0455
0456
0457 auto getTrackParams = [&](unsigned int ipar)
0458 -> std::optional<std::pair<Acts::BoundVector, Acts::BoundMatrix>> {
0459 if (ipar == ePredicted && state.hasPredicted()) {
0460 return std::make_pair(state.predicted(), state.predictedCovariance());
0461 }
0462 if (ipar == eFiltered && state.hasFiltered()) {
0463 return std::make_pair(state.filtered(), state.filteredCovariance());
0464 }
0465 if (ipar == eSmoothed && state.hasSmoothed()) {
0466 return std::make_pair(state.smoothed(), state.smoothedCovariance());
0467 }
0468 if (ipar == eUnbiased && state.hasSmoothed() && state.hasProjector()) {
0469
0470
0471
0472 auto m = state.effectiveCalibrated();
0473 auto H = state.effectiveProjector();
0474 auto V = state.effectiveCalibratedCovariance();
0475 auto K =
0476 (state.smoothedCovariance() * H.transpose() *
0477 (H * state.smoothedCovariance() * H.transpose() - V).inverse())
0478 .eval();
0479 auto unbiasedParamsVec =
0480 state.smoothed() + K * (m - H * state.smoothed());
0481 auto unbiasedParamsCov =
0482 state.smoothedCovariance() - K * H * state.smoothedCovariance();
0483 return std::make_pair(unbiasedParamsVec, unbiasedParamsCov);
0484 }
0485 if (ipar == eUnbiased && !state.hasSmoothed() && state.hasFiltered() &&
0486 state.hasProjector() && state.hasCalibrated()) {
0487
0488 auto m = state.effectiveCalibrated();
0489 auto H = state.effectiveProjector();
0490 auto V = state.effectiveCalibratedCovariance();
0491 auto K =
0492 (state.filteredCovariance() * H.transpose() *
0493 (H * state.filteredCovariance() * H.transpose() - V).inverse())
0494 .eval();
0495 auto unbiasedParamsVec =
0496 state.filtered() + K * (m - H * state.filtered());
0497 auto unbiasedParamsCov =
0498 state.filteredCovariance() - K * H * state.filteredCovariance();
0499 return std::make_pair(unbiasedParamsVec, unbiasedParamsCov);
0500 }
0501 if (ipar == eUnbiased && !state.hasSmoothed() && !state.hasFiltered() &&
0502 state.hasPredicted() && state.hasProjector() &&
0503 state.hasCalibrated()) {
0504
0505 auto m = state.effectiveCalibrated();
0506 auto H = state.effectiveProjector();
0507 auto V = state.effectiveCalibratedCovariance();
0508 auto K =
0509 (state.predictedCovariance() * H.transpose() *
0510 (H * state.predictedCovariance() * H.transpose() - V).inverse())
0511 .eval();
0512 auto unbiasedParamsVec =
0513 state.predicted() + K * (m - H * state.predicted());
0514 auto unbiasedParamsCov =
0515 state.predictedCovariance() - K * H * state.predictedCovariance();
0516 return std::make_pair(unbiasedParamsVec, unbiasedParamsCov);
0517 }
0518 return std::nullopt;
0519 };
0520
0521
0522 for (unsigned int ipar = 0; ipar < eSize; ++ipar) {
0523
0524 auto trackParamsOpt = getTrackParams(ipar);
0525
0526 m_hasParams[ipar].push_back(trackParamsOpt.has_value());
0527
0528 if (!trackParamsOpt) {
0529 if (ipar == ePredicted) {
0530
0531 m_res_x_hit.push_back(nan);
0532 m_res_y_hit.push_back(nan);
0533 m_err_x_hit.push_back(nan);
0534 m_err_y_hit.push_back(nan);
0535 m_pull_x_hit.push_back(nan);
0536 m_pull_y_hit.push_back(nan);
0537 m_dim_hit.push_back(0);
0538 }
0539
0540
0541 m_eLOC0[ipar].push_back(nan);
0542 m_eLOC1[ipar].push_back(nan);
0543 m_ePHI[ipar].push_back(nan);
0544 m_eTHETA[ipar].push_back(nan);
0545 m_eQOP[ipar].push_back(nan);
0546 m_eT[ipar].push_back(nan);
0547 m_res_eLOC0[ipar].push_back(nan);
0548 m_res_eLOC1[ipar].push_back(nan);
0549 m_res_ePHI[ipar].push_back(nan);
0550 m_res_eTHETA[ipar].push_back(nan);
0551 m_res_eQOP[ipar].push_back(nan);
0552 m_res_eT[ipar].push_back(nan);
0553 m_err_eLOC0[ipar].push_back(nan);
0554 m_err_eLOC1[ipar].push_back(nan);
0555 m_err_ePHI[ipar].push_back(nan);
0556 m_err_eTHETA[ipar].push_back(nan);
0557 m_err_eQOP[ipar].push_back(nan);
0558 m_err_eT[ipar].push_back(nan);
0559 m_pull_eLOC0[ipar].push_back(nan);
0560 m_pull_eLOC1[ipar].push_back(nan);
0561 m_pull_ePHI[ipar].push_back(nan);
0562 m_pull_eTHETA[ipar].push_back(nan);
0563 m_pull_eQOP[ipar].push_back(nan);
0564 m_pull_eT[ipar].push_back(nan);
0565 m_x[ipar].push_back(nan);
0566 m_y[ipar].push_back(nan);
0567 m_z[ipar].push_back(nan);
0568 m_px[ipar].push_back(nan);
0569 m_py[ipar].push_back(nan);
0570 m_pz[ipar].push_back(nan);
0571 m_pT[ipar].push_back(nan);
0572 m_eta[ipar].push_back(nan);
0573
0574 continue;
0575 }
0576
0577 ++m_nParams[ipar];
0578 const auto& [parameters, covariance] = *trackParamsOpt;
0579
0580
0581 m_eLOC0[ipar].push_back(parameters[Acts::eBoundLoc0]);
0582 m_eLOC1[ipar].push_back(parameters[Acts::eBoundLoc1]);
0583 m_ePHI[ipar].push_back(parameters[Acts::eBoundPhi]);
0584 m_eTHETA[ipar].push_back(parameters[Acts::eBoundTheta]);
0585 m_eQOP[ipar].push_back(parameters[Acts::eBoundQOverP]);
0586 m_eT[ipar].push_back(parameters[Acts::eBoundTime]);
0587
0588
0589
0590 m_err_eLOC0[ipar].push_back(
0591 std::sqrt(covariance(Acts::eBoundLoc0, Acts::eBoundLoc0)));
0592 m_err_eLOC1[ipar].push_back(
0593 std::sqrt(covariance(Acts::eBoundLoc1, Acts::eBoundLoc1)));
0594 m_err_ePHI[ipar].push_back(
0595 std::sqrt(covariance(Acts::eBoundPhi, Acts::eBoundPhi)));
0596 m_err_eTHETA[ipar].push_back(
0597 std::sqrt(covariance(Acts::eBoundTheta, Acts::eBoundTheta)));
0598 m_err_eQOP[ipar].push_back(
0599 std::sqrt(covariance(Acts::eBoundQOverP, Acts::eBoundQOverP)));
0600 m_err_eT[ipar].push_back(
0601 std::sqrt(covariance(Acts::eBoundTime, Acts::eBoundTime)));
0602
0603
0604
0605 Acts::FreeVector freeParams =
0606 Acts::transformBoundToFreeParameters(surface, gctx, parameters);
0607 m_x[ipar].push_back(freeParams[Acts::eFreePos0]);
0608 m_y[ipar].push_back(freeParams[Acts::eFreePos1]);
0609 m_z[ipar].push_back(freeParams[Acts::eFreePos2]);
0610 auto p = std::abs(1 / freeParams[Acts::eFreeQOverP]);
0611 m_px[ipar].push_back(p * freeParams[Acts::eFreeDir0]);
0612 m_py[ipar].push_back(p * freeParams[Acts::eFreeDir1]);
0613 m_pz[ipar].push_back(p * freeParams[Acts::eFreeDir2]);
0614 m_pT[ipar].push_back(p * std::hypot(freeParams[Acts::eFreeDir0],
0615 freeParams[Acts::eFreeDir1]));
0616 m_eta[ipar].push_back(
0617 Acts::VectorHelpers::eta(freeParams.segment<3>(Acts::eFreeDir0)));
0618
0619 if (!state.hasUncalibratedSourceLink()) {
0620 continue;
0621 }
0622
0623
0624 m_res_eLOC0[ipar].push_back(parameters[Acts::eBoundLoc0] - truthLOC0);
0625 m_res_eLOC1[ipar].push_back(parameters[Acts::eBoundLoc1] - truthLOC1);
0626 float resPhi = Acts::detail::difference_periodic<float>(
0627 parameters[Acts::eBoundPhi], truthPHI,
0628 static_cast<float>(2 * M_PI));
0629 m_res_ePHI[ipar].push_back(resPhi);
0630 m_res_eTHETA[ipar].push_back(parameters[Acts::eBoundTheta] -
0631 truthTHETA);
0632 m_res_eQOP[ipar].push_back(parameters[Acts::eBoundQOverP] - truthQOP);
0633 m_res_eT[ipar].push_back(parameters[Acts::eBoundTime] - truthTIME);
0634
0635
0636 m_pull_eLOC0[ipar].push_back(
0637 (parameters[Acts::eBoundLoc0] - truthLOC0) /
0638 std::sqrt(covariance(Acts::eBoundLoc0, Acts::eBoundLoc0)));
0639 m_pull_eLOC1[ipar].push_back(
0640 (parameters[Acts::eBoundLoc1] - truthLOC1) /
0641 std::sqrt(covariance(Acts::eBoundLoc1, Acts::eBoundLoc1)));
0642 m_pull_ePHI[ipar].push_back(
0643 resPhi / std::sqrt(covariance(Acts::eBoundPhi, Acts::eBoundPhi)));
0644 m_pull_eTHETA[ipar].push_back(
0645 (parameters[Acts::eBoundTheta] - truthTHETA) /
0646 std::sqrt(covariance(Acts::eBoundTheta, Acts::eBoundTheta)));
0647 m_pull_eQOP[ipar].push_back(
0648 (parameters[Acts::eBoundQOverP] - truthQOP) /
0649 std::sqrt(covariance(Acts::eBoundQOverP, Acts::eBoundQOverP)));
0650 double sigmaTime =
0651 std::sqrt(covariance(Acts::eBoundTime, Acts::eBoundTime));
0652 m_pull_eT[ipar].push_back(
0653 sigmaTime == 0.0
0654 ? nan
0655 : (parameters[Acts::eBoundTime] - truthTIME) / sigmaTime);
0656
0657 if (ipar == ePredicted) {
0658
0659 auto H = state.effectiveProjector();
0660 auto V = state.effectiveCalibratedCovariance();
0661 auto resCov = V + H * covariance * H.transpose();
0662 Acts::ActsDynamicVector res(state.calibratedSize());
0663 res.setZero();
0664
0665 res = state.effectiveCalibrated() - H * parameters;
0666
0667 m_res_x_hit.push_back(res[Acts::eBoundLoc0]);
0668 m_err_x_hit.push_back(
0669 std::sqrt(V(Acts::eBoundLoc0, Acts::eBoundLoc0)));
0670 m_pull_x_hit.push_back(
0671 res[Acts::eBoundLoc0] /
0672 std::sqrt(resCov(Acts::eBoundLoc0, Acts::eBoundLoc0)));
0673
0674 if (state.calibratedSize() >= 2) {
0675 m_res_y_hit.push_back(res[Acts::eBoundLoc1]);
0676 m_err_y_hit.push_back(
0677 std::sqrt(V(Acts::eBoundLoc1, Acts::eBoundLoc1)));
0678 m_pull_y_hit.push_back(
0679 res[Acts::eBoundLoc1] /
0680 std::sqrt(resCov(Acts::eBoundLoc1, Acts::eBoundLoc1)));
0681 } else {
0682 m_res_y_hit.push_back(nan);
0683 m_err_y_hit.push_back(nan);
0684 m_pull_y_hit.push_back(nan);
0685 }
0686
0687 m_dim_hit.push_back(state.calibratedSize());
0688 }
0689 }
0690 m_particleId.push_back(std::move(particleIds));
0691 }
0692
0693
0694 m_outputTree->Fill();
0695
0696
0697 m_t_x.clear();
0698 m_t_y.clear();
0699 m_t_z.clear();
0700 m_t_r.clear();
0701 m_t_dx.clear();
0702 m_t_dy.clear();
0703 m_t_dz.clear();
0704 m_t_eLOC0.clear();
0705 m_t_eLOC1.clear();
0706 m_t_ePHI.clear();
0707 m_t_eTHETA.clear();
0708 m_t_eQOP.clear();
0709 m_t_eT.clear();
0710 m_particleId.clear();
0711
0712 m_volumeID.clear();
0713 m_layerID.clear();
0714 m_moduleID.clear();
0715 m_pathLength.clear();
0716 m_lx_hit.clear();
0717 m_ly_hit.clear();
0718 m_x_hit.clear();
0719 m_y_hit.clear();
0720 m_z_hit.clear();
0721 m_res_x_hit.clear();
0722 m_res_y_hit.clear();
0723 m_err_x_hit.clear();
0724 m_err_y_hit.clear();
0725 m_pull_x_hit.clear();
0726 m_pull_y_hit.clear();
0727 m_dim_hit.clear();
0728
0729 for (unsigned int ipar = 0; ipar < eSize; ++ipar) {
0730 m_hasParams[ipar].clear();
0731 m_eLOC0[ipar].clear();
0732 m_eLOC1[ipar].clear();
0733 m_ePHI[ipar].clear();
0734 m_eTHETA[ipar].clear();
0735 m_eQOP[ipar].clear();
0736 m_eT[ipar].clear();
0737 m_res_eLOC0[ipar].clear();
0738 m_res_eLOC1[ipar].clear();
0739 m_res_ePHI[ipar].clear();
0740 m_res_eTHETA[ipar].clear();
0741 m_res_eQOP[ipar].clear();
0742 m_res_eT[ipar].clear();
0743 m_err_eLOC0[ipar].clear();
0744 m_err_eLOC1[ipar].clear();
0745 m_err_ePHI[ipar].clear();
0746 m_err_eTHETA[ipar].clear();
0747 m_err_eQOP[ipar].clear();
0748 m_err_eT[ipar].clear();
0749 m_pull_eLOC0[ipar].clear();
0750 m_pull_eLOC1[ipar].clear();
0751 m_pull_ePHI[ipar].clear();
0752 m_pull_eTHETA[ipar].clear();
0753 m_pull_eQOP[ipar].clear();
0754 m_pull_eT[ipar].clear();
0755 m_x[ipar].clear();
0756 m_y[ipar].clear();
0757 m_z[ipar].clear();
0758 m_px[ipar].clear();
0759 m_py[ipar].clear();
0760 m_pz[ipar].clear();
0761 m_eta[ipar].clear();
0762 m_pT[ipar].clear();
0763 }
0764
0765 m_chi2.clear();
0766 }
0767
0768 return ProcessCode::SUCCESS;
0769 }