diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/RootTrajectoryStatesWriterTool.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/RootTrajectoryStatesWriterTool.h new file mode 100644 index 0000000000000000000000000000000000000000..4d3466a6e166471480b9d7159868e4693adc79bb --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/RootTrajectoryStatesWriterTool.h @@ -0,0 +1,111 @@ +#ifndef FASERACTSKALMANFILTER_ROOTTRAJECTORYSTATESWRITERTOOL_H +#define FASERACTSKALMANFILTER_ROOTTRAJECTORYSTATESWRITERTOOL_H + +#include "AthenaBaseComps/AthAlgTool.h" +#include "Acts/EventData/TrackParameters.hpp" +#include "Acts/Geometry/GeometryContext.hpp" +#include <array> +#include <string> +#include <vector> + + +class TFile; +class TTree; +struct FaserActsRecMultiTrajectory; +using TrajectoriesContainer = std::vector<FaserActsRecMultiTrajectory>; + +class RootTrajectoryStatesWriterTool : public AthAlgTool { +public: + RootTrajectoryStatesWriterTool(const std::string& type, const std::string& name, + const IInterface* parent); + ~RootTrajectoryStatesWriterTool() override = default; + + StatusCode initialize() override; + StatusCode finalize() override; + + StatusCode write(TrajectoriesContainer trajectories, Acts::GeometryContext geoContext, + std::vector<Acts::CurvilinearTrackParameters> traj) const; + +private: + Gaudi::Property<std::string> m_filePath{this, "FilePath", "Trajectories.root", "Output root file"}; + Gaudi::Property<std::string> m_treeName{this, "TreeName", "tree", "Tree name"}; + TFile* m_file; + TTree* m_tree; + + mutable uint32_t m_eventNr{0}; ///< the event number + mutable uint32_t m_multiTrajNr{0}; ///< the multi-trajectory number + mutable unsigned int m_subTrajNr{0}; ///< the multi-trajectory sub-trajectory number + + mutable std::vector<float> m_t_x; ///< Global truth hit position x + mutable std::vector<float> m_t_y; ///< Global truth hit position y + mutable std::vector<float> m_t_z; ///< Global truth hit position z + mutable std::vector<float> m_t_r; ///< Global truth hit position r + mutable std::vector<float> m_t_dx; ///< Truth particle direction x at global hit position + mutable std::vector<float> m_t_dy; ///< Truth particle direction y at global hit position + mutable std::vector<float> m_t_dz; ///< Truth particle direction z at global hit position + + mutable std::vector<float> m_t_eLOC0; ///< truth parameter eBoundLoc0 + mutable std::vector<float> m_t_eLOC1; ///< truth parameter eBoundLoc1 + mutable std::vector<float> m_t_ePHI; ///< truth parameter ePHI + mutable std::vector<float> m_t_eTHETA; ///< truth parameter eTHETA + mutable std::vector<float> m_t_eQOP; ///< truth parameter eQOP + mutable std::vector<float> m_t_eT; ///< truth parameter eT + + mutable unsigned int m_nStates{0}; ///< number of all states + mutable unsigned int m_nMeasurements{0}; ///< number of states with measurements + mutable std::vector<int> m_volumeID; ///< volume identifier + mutable std::vector<int> m_layerID; ///< layer identifier + mutable std::vector<int> m_moduleID; ///< surface identifier + mutable std::vector<float> m_pathLength; ///< path length + mutable std::vector<float> m_lx_hit; ///< uncalibrated measurement local x + mutable std::vector<float> m_ly_hit; ///< uncalibrated measurement local y + mutable std::vector<float> m_x_hit; ///< uncalibrated measurement global x + mutable std::vector<float> m_y_hit; ///< uncalibrated measurement global y + mutable std::vector<float> m_z_hit; ///< uncalibrated measurement global z + mutable std::vector<float> m_res_x_hit; ///< hit residual x + mutable std::vector<float> m_res_y_hit; ///< hit residual y + mutable std::vector<float> m_err_x_hit; ///< hit err x + mutable std::vector<float> m_err_y_hit; ///< hit err y + mutable std::vector<float> m_pull_x_hit; ///< hit pull x + mutable std::vector<float> m_pull_y_hit; ///< hit pull y + mutable std::vector<int> m_dim_hit; ///< dimension of measurement + + mutable std::array<int, 3> m_nParams; ///< number of states which have filtered/predicted/smoothed parameters + mutable std::array<std::vector<bool>, 3> m_hasParams; ///< status of the filtered/predicted/smoothed parameters + mutable std::array<std::vector<float>, 3> m_eLOC0; ///< predicted/filtered/smoothed parameter eLOC0 + mutable std::array<std::vector<float>, 3> m_eLOC1; ///< predicted/filtered/smoothed parameter eLOC1 + mutable std::array<std::vector<float>, 3> m_ePHI; ///< predicted/filtered/smoothed parameter ePHI + mutable std::array<std::vector<float>, 3> m_eTHETA; ///< predicted/filtered/smoothed parameter eTHETA + mutable std::array<std::vector<float>, 3> m_eQOP; ///< predicted/filtered/smoothed parameter eQOP + mutable std::array<std::vector<float>, 3> m_eT; ///< predicted/filtered/smoothed parameter eT + mutable std::array<std::vector<float>, 3> m_res_eLOC0; ///< predicted/filtered/smoothed parameter eLOC0 residual + mutable std::array<std::vector<float>, 3> m_res_eLOC1; ///< predicted/filtered/smoothed parameter eLOC1 residual + mutable std::array<std::vector<float>, 3> m_res_ePHI; ///< predicted/filtered/smoothed parameter ePHI residual + mutable std::array<std::vector<float>, 3> m_res_eTHETA; ///< predicted/filtered/smoothed parameter eTHETA residual + mutable std::array<std::vector<float>, 3> m_res_eQOP; ///< predicted/filtered/smoothed parameter eQOP residual + mutable std::array<std::vector<float>, 3> m_res_eT; ///< predicted/filtered/smoothed parameter eT residual + mutable std::array<std::vector<float>, 3> m_err_eLOC0; ///< predicted/filtered/smoothed parameter eLOC0 error + mutable std::array<std::vector<float>, 3> m_err_eLOC1; ///< predicted/filtered/smoothed parameter eLOC1 error + mutable std::array<std::vector<float>, 3> m_err_ePHI; ///< predicted/filtered/smoothed parameter ePHI error + mutable std::array<std::vector<float>, 3> m_err_eTHETA; ///< predicted/filtered/smoothed parameter eTHETA error + mutable std::array<std::vector<float>, 3> m_err_eQOP; ///< predicted/filtered/smoothed parameter eQOP error + mutable std::array<std::vector<float>, 3> m_err_eT; ///< predicted/filtered/smoothed parameter eT error + mutable std::array<std::vector<float>, 3> m_pull_eLOC0; ///< predicted/filtered/smoothed parameter eLOC0 pull + mutable std::array<std::vector<float>, 3> m_pull_eLOC1; ///< predicted/filtered/smoothed parameter eLOC1 pull + mutable std::array<std::vector<float>, 3> m_pull_ePHI; ///< predicted/filtered/smoothed parameter ePHI pull + mutable std::array<std::vector<float>, 3> m_pull_eTHETA; ///< predicted/filtered/smoothed parameter eTHETA pull + mutable std::array<std::vector<float>, 3> m_pull_eQOP; ///< predicted/filtered/smoothed parameter eQOP pull + mutable std::array<std::vector<float>, 3> m_pull_eT; ///< predicted/filtered/smoothed parameter eT pull + mutable std::array<std::vector<float>, 3> m_x; ///< predicted/filtered/smoothed parameter global x + mutable std::array<std::vector<float>, 3> m_y; ///< predicted/filtered/smoothed parameter global y + mutable std::array<std::vector<float>, 3> m_z; ///< predicted/filtered/smoothed parameter global z + mutable std::array<std::vector<float>, 3> m_px; ///< predicted/filtered/smoothed parameter px + mutable std::array<std::vector<float>, 3> m_py; ///< predicted/filtered/smoothed parameter py + mutable std::array<std::vector<float>, 3> m_pz; ///< predicted/filtered/smoothed parameter pz + mutable std::array<std::vector<float>, 3> m_eta; ///< predicted/filtered/smoothed parameter eta + mutable std::array<std::vector<float>, 3> m_pT; ///< predicted/filtered/smoothed parameter pT + + mutable std::vector<float> m_chi2; ///< chisq from filtering +}; + +#endif // FASERACTSKALMANFILTER_ROOTTRAJECTORYSTATESWRITERTOOL_H diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/RootTrajectoryStatesWriterTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/RootTrajectoryStatesWriterTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..ec5a075c651f1bead4dd623ba63bf710dffccc5e --- /dev/null +++ b/Tracking/Acts/FaserActsKalmanFilter/src/RootTrajectoryStatesWriterTool.cxx @@ -0,0 +1,576 @@ +#include "FaserActsKalmanFilter/RootTrajectoryStatesWriterTool.h" +#include "Acts/EventData/MultiTrajectory.hpp" +#include "Acts/EventData/MultiTrajectoryHelpers.hpp" +#include "Acts/EventData/detail/TransformationBoundToFree.hpp" +#include "Acts/Utilities/Helpers.hpp" +#include "FaserActsKalmanFilter/FaserActsRecMultiTrajectory.h" +#include <TFile.h> +#include <TTree.h> + +using Acts::VectorHelpers::eta; +using Acts::VectorHelpers::perp; +using Acts::VectorHelpers::phi; +using Acts::VectorHelpers::theta; + +RootTrajectoryStatesWriterTool::RootTrajectoryStatesWriterTool( + const std::string& type, const std::string& name, const IInterface* parent) + : AthAlgTool(type, name, parent) {} + +StatusCode RootTrajectoryStatesWriterTool::initialize() { + std::string filePath = m_filePath; + std::string treeName = m_treeName; + m_file = TFile::Open(filePath.c_str(), "RECREATE"); + if (m_file == nullptr) { + ATH_MSG_ERROR("Unable to open output file at " << m_filePath); + return StatusCode::FAILURE; + } + m_file->cd(); + m_tree = new TTree(treeName.c_str(), treeName.c_str()); + if (m_tree == nullptr) { + ATH_MSG_ERROR("Unable to create TTree"); + return StatusCode::FAILURE; + } + + m_tree = new TTree("tree", "tree"); + + m_tree->Branch("event_nr", &m_eventNr); + m_tree->Branch("multiTraj_nr", &m_multiTrajNr); + m_tree->Branch("subTraj_nr", &m_subTrajNr); + + m_tree->Branch("t_x", &m_t_x); + m_tree->Branch("t_y", &m_t_y); + m_tree->Branch("t_z", &m_t_z); + m_tree->Branch("t_r", &m_t_r); + m_tree->Branch("t_dx", &m_t_dx); + m_tree->Branch("t_dy", &m_t_dy); + m_tree->Branch("t_dz", &m_t_dz); + m_tree->Branch("t_eLOC0", &m_t_eLOC0); + m_tree->Branch("t_eLOC1", &m_t_eLOC1); + m_tree->Branch("t_ePHI", &m_t_ePHI); + m_tree->Branch("t_eTHETA", &m_t_eTHETA); + m_tree->Branch("t_eQOP", &m_t_eQOP); + m_tree->Branch("t_eT", &m_t_eT); + + m_tree->Branch("nStates", &m_nStates); + m_tree->Branch("nMeasurements", &m_nMeasurements); + m_tree->Branch("volume_id", &m_volumeID); + m_tree->Branch("layer_id", &m_layerID); + m_tree->Branch("module_id", &m_moduleID); + m_tree->Branch("pathLength", &m_pathLength); + m_tree->Branch("l_x_hit", &m_lx_hit); + m_tree->Branch("l_y_hit", &m_ly_hit); + m_tree->Branch("g_x_hit", &m_x_hit); + m_tree->Branch("g_y_hit", &m_y_hit); + m_tree->Branch("g_z_hit", &m_z_hit); + m_tree->Branch("res_x_hit", &m_res_x_hit); + m_tree->Branch("res_y_hit", &m_res_y_hit); + m_tree->Branch("err_x_hit", &m_err_x_hit); + m_tree->Branch("err_y_hit", &m_err_y_hit); + m_tree->Branch("pull_x_hit", &m_pull_x_hit); + m_tree->Branch("pull_y_hit", &m_pull_y_hit); + m_tree->Branch("dim_hit", &m_dim_hit); + + m_tree->Branch("nPredicted", &m_nParams[0]); + m_tree->Branch("predicted", &m_hasParams[0]); + m_tree->Branch("eLOC0_prt", &m_eLOC0[0]); + m_tree->Branch("eLOC1_prt", &m_eLOC1[0]); + m_tree->Branch("ePHI_prt", &m_ePHI[0]); + m_tree->Branch("eTHETA_prt", &m_eTHETA[0]); + m_tree->Branch("eQOP_prt", &m_eQOP[0]); + m_tree->Branch("eT_prt", &m_eT[0]); + m_tree->Branch("res_eLOC0_prt", &m_res_eLOC0[0]); + m_tree->Branch("res_eLOC1_prt", &m_res_eLOC1[0]); + m_tree->Branch("res_ePHI_prt", &m_res_ePHI[0]); + m_tree->Branch("res_eTHETA_prt", &m_res_eTHETA[0]); + m_tree->Branch("res_eQOP_prt", &m_res_eQOP[0]); + m_tree->Branch("res_eT_prt", &m_res_eT[0]); + m_tree->Branch("err_eLOC0_prt", &m_err_eLOC0[0]); + m_tree->Branch("err_eLOC1_prt", &m_err_eLOC1[0]); + m_tree->Branch("err_ePHI_prt", &m_err_ePHI[0]); + m_tree->Branch("err_eTHETA_prt", &m_err_eTHETA[0]); + m_tree->Branch("err_eQOP_prt", &m_err_eQOP[0]); + m_tree->Branch("err_eT_prt", &m_err_eT[0]); + m_tree->Branch("pull_eLOC0_prt", &m_pull_eLOC0[0]); + m_tree->Branch("pull_eLOC1_prt", &m_pull_eLOC1[0]); + m_tree->Branch("pull_ePHI_prt", &m_pull_ePHI[0]); + m_tree->Branch("pull_eTHETA_prt", &m_pull_eTHETA[0]); + m_tree->Branch("pull_eQOP_prt", &m_pull_eQOP[0]); + m_tree->Branch("pull_eT_prt", &m_pull_eT[0]); + m_tree->Branch("g_x_prt", &m_x[0]); + m_tree->Branch("g_y_prt", &m_y[0]); + m_tree->Branch("g_z_prt", &m_z[0]); + m_tree->Branch("px_prt", &m_px[0]); + m_tree->Branch("py_prt", &m_py[0]); + m_tree->Branch("pz_prt", &m_pz[0]); + m_tree->Branch("eta_prt", &m_eta[0]); + m_tree->Branch("pT_prt", &m_pT[0]); + + m_tree->Branch("nFiltered", &m_nParams[1]); + m_tree->Branch("filtered", &m_hasParams[1]); + m_tree->Branch("eLOC0_flt", &m_eLOC0[1]); + m_tree->Branch("eLOC1_flt", &m_eLOC1[1]); + m_tree->Branch("ePHI_flt", &m_ePHI[1]); + m_tree->Branch("eTHETA_flt", &m_eTHETA[1]); + m_tree->Branch("eQOP_flt", &m_eQOP[1]); + m_tree->Branch("eT_flt", &m_eT[1]); + m_tree->Branch("res_eLOC0_flt", &m_res_eLOC0[1]); + m_tree->Branch("res_eLOC1_flt", &m_res_eLOC1[1]); + m_tree->Branch("res_ePHI_flt", &m_res_ePHI[1]); + m_tree->Branch("res_eTHETA_flt", &m_res_eTHETA[1]); + m_tree->Branch("res_eQOP_flt", &m_res_eQOP[1]); + m_tree->Branch("res_eT_flt", &m_res_eT[1]); + m_tree->Branch("err_eLOC0_flt", &m_err_eLOC0[1]); + m_tree->Branch("err_eLOC1_flt", &m_err_eLOC1[1]); + m_tree->Branch("err_ePHI_flt", &m_err_ePHI[1]); + m_tree->Branch("err_eTHETA_flt", &m_err_eTHETA[1]); + m_tree->Branch("err_eQOP_flt", &m_err_eQOP[1]); + m_tree->Branch("err_eT_flt", &m_err_eT[1]); + m_tree->Branch("pull_eLOC0_flt", &m_pull_eLOC0[1]); + m_tree->Branch("pull_eLOC1_flt", &m_pull_eLOC1[1]); + m_tree->Branch("pull_ePHI_flt", &m_pull_ePHI[1]); + m_tree->Branch("pull_eTHETA_flt", &m_pull_eTHETA[1]); + m_tree->Branch("pull_eQOP_flt", &m_pull_eQOP[1]); + m_tree->Branch("pull_eT_flt", &m_pull_eT[1]); + m_tree->Branch("g_x_flt", &m_x[1]); + m_tree->Branch("g_y_flt", &m_y[1]); + m_tree->Branch("g_z_flt", &m_z[1]); + m_tree->Branch("px_flt", &m_px[1]); + m_tree->Branch("py_flt", &m_py[1]); + m_tree->Branch("pz_flt", &m_pz[1]); + m_tree->Branch("eta_flt", &m_eta[1]); + m_tree->Branch("pT_flt", &m_pT[1]); + + m_tree->Branch("nSmoothed", &m_nParams[2]); + m_tree->Branch("smoothed", &m_hasParams[2]); + m_tree->Branch("eLOC0_smt", &m_eLOC0[2]); + m_tree->Branch("eLOC1_smt", &m_eLOC1[2]); + m_tree->Branch("ePHI_smt", &m_ePHI[2]); + m_tree->Branch("eTHETA_smt", &m_eTHETA[2]); + m_tree->Branch("eQOP_smt", &m_eQOP[2]); + m_tree->Branch("eT_smt", &m_eT[2]); + m_tree->Branch("res_eLOC0_smt", &m_res_eLOC0[2]); + m_tree->Branch("res_eLOC1_smt", &m_res_eLOC1[2]); + m_tree->Branch("res_ePHI_smt", &m_res_ePHI[2]); + m_tree->Branch("res_eTHETA_smt", &m_res_eTHETA[2]); + m_tree->Branch("res_eQOP_smt", &m_res_eQOP[2]); + m_tree->Branch("res_eT_smt", &m_res_eT[2]); + m_tree->Branch("err_eLOC0_smt", &m_err_eLOC0[2]); + m_tree->Branch("err_eLOC1_smt", &m_err_eLOC1[2]); + m_tree->Branch("err_ePHI_smt", &m_err_ePHI[2]); + m_tree->Branch("err_eTHETA_smt", &m_err_eTHETA[2]); + m_tree->Branch("err_eQOP_smt", &m_err_eQOP[2]); + m_tree->Branch("err_eT_smt", &m_err_eT[2]); + m_tree->Branch("pull_eLOC0_smt", &m_pull_eLOC0[2]); + m_tree->Branch("pull_eLOC1_smt", &m_pull_eLOC1[2]); + m_tree->Branch("pull_ePHI_smt", &m_pull_ePHI[2]); + m_tree->Branch("pull_eTHETA_smt", &m_pull_eTHETA[2]); + m_tree->Branch("pull_eQOP_smt", &m_pull_eQOP[2]); + m_tree->Branch("pull_eT_smt", &m_pull_eT[2]); + m_tree->Branch("g_x_smt", &m_x[2]); + m_tree->Branch("g_y_smt", &m_y[2]); + m_tree->Branch("g_z_smt", &m_z[2]); + m_tree->Branch("px_smt", &m_px[2]); + m_tree->Branch("py_smt", &m_py[2]); + m_tree->Branch("pz_smt", &m_pz[2]); + m_tree->Branch("eta_smt", &m_eta[2]); + m_tree->Branch("pT_smt", &m_pT[2]); + + m_tree->Branch("chi2", &m_chi2); + + return StatusCode::SUCCESS; +} + + +StatusCode RootTrajectoryStatesWriterTool::finalize() { + m_file->cd(); + m_tree->Write(); + m_file->Close(); + return StatusCode::SUCCESS; +} + +StatusCode RootTrajectoryStatesWriterTool::write( + TrajectoriesContainer trajectories, Acts::GeometryContext gctx, + std::vector<Acts::CurvilinearTrackParameters> traj) const { + + // Read additional input collections +// const auto& particles = +// ctx.eventStore.get<SimParticleContainer>(m_cfg.inputParticles); +// const auto& simHits = ctx.eventStore.get<SimHitContainer>(m_cfg.inputSimHits); +// const auto& hitParticlesMap = +// ctx.eventStore.get<HitParticlesMap>(m_cfg.inputMeasurementParticlesMap); +// const auto& hitSimHitsMap = +// ctx.eventStore.get<HitSimHitsMap>(m_cfg.inputMeasurementSimHitsMap); + + // Get the event number + EventContext ctx = Gaudi::Hive::currentContext(); + m_eventNr = ctx.eventID().event_number(); + + // Loop over the trajectories + for (size_t itraj = 0; itraj < trajectories.size(); ++itraj) { + const auto& traj = trajectories[itraj]; + + if (traj.empty()) { + ATH_MSG_WARNING("Empty trajectories object " << itraj); + continue; + } + + // The trajectory index + m_multiTrajNr = itraj; + + // The trajectory entry indices and the multiTrajectory + const auto& mj = traj.multiTrajectory(); + const auto& trackTips = traj.tips(); + + // Loop over the entry indices for the subtrajectories + for (unsigned int isubtraj = 0; isubtraj < trackTips.size(); ++isubtraj) { + // The subtrajectory index + m_subTrajNr = isubtraj; + // The entry index for this subtrajectory + const auto& trackTip = trackTips[isubtraj]; + // Collect the trajectory summary info + auto trajState = + Acts::MultiTrajectoryHelpers::trajectoryState(mj, trackTip); + m_nMeasurements = trajState.nMeasurements; + m_nStates = trajState.nStates; + + // Get the majority truth particle to this track + // int truthQ = 1.; + // identifyContributingParticles(hitParticlesMap, traj, trackTip, + // particleHitCounts); + // if (not particleHitCounts.empty()) { + // // Get the barcode of the majority truth particle + // auto barcode = particleHitCounts.front().particleId.value(); + // // Find the truth particle via the barcode + // auto ip = particles.find(barcode); + // if (ip != particles.end()) { + // const auto& particle = *ip; + // ATH_MSG_DEBUG("Find the truth particle with barcode = " << barcode); + // // Get the truth particle charge + // truthQ = particle.charge(); + // } else { + // ATH_MSG_WARNING("Truth particle with barcode = " << barcode + // << " not found!"); + // } + // } + + // Get the trackStates on the trajectory + m_nParams = {0, 0, 0}; + mj.visitBackwards(trackTip, [&](const auto& state) { + // we only fill the track states with non-outlier measurement + auto typeFlags = state.typeFlags(); + if (not typeFlags.test(Acts::TrackStateFlag::MeasurementFlag)) { + return true; + } + + const auto& surface = state.referenceSurface(); + + // get the truth hits corresponding to this trackState + // Use average truth in the case of multiple contributing sim hits + // const auto hitIdx = state.uncalibrated().index(); + // auto indices = makeRange(hitSimHitsMap.equal_range(hitIdx)); + // auto [truthLocal, truthPos4, truthUnitDir] = + // averageSimHits(ctx.geoContext, surface, simHits, indices); + // // momemtum averaging makes even less sense than averaging position and + // // direction. use the first momentum or set q/p to zero + // float truthQOP = 0.0f; + // if (not indices.empty()) { + // // we assume that the indices are within valid ranges so we do not + // // need to check their validity again. + // const auto simHitIdx0 = indices.begin()->second; + // const auto& simHit0 = *simHits.nth(simHitIdx0); + // const auto p = + // simHit0.momentum4Before().template segment<3>(Acts::eMom0).norm(); + // truthQOP = truthQ / p; + // } + + // // fill the truth hit info + // m_t_x.push_back(truthPos4[Acts::ePos0]); + // m_t_y.push_back(truthPos4[Acts::ePos1]); + // m_t_z.push_back(truthPos4[Acts::ePos2]); + // m_t_r.push_back(perp(truthPos4.template segment<3>(Acts::ePos0))); + // m_t_dx.push_back(truthUnitDir[Acts::eMom0]); + // m_t_dy.push_back(truthUnitDir[Acts::eMom1]); + // m_t_dz.push_back(truthUnitDir[Acts::eMom2]); + + // // get the truth track parameter at this track State + // float truthLOC0 = truthLocal[Acts::ePos0]; + // float truthLOC1 = truthLocal[Acts::ePos1]; + // float truthTIME = truthPos4[Acts::eTime]; + // float truthPHI = phi(truthUnitDir); + // float truthTHETA = theta(truthUnitDir); + + // // fill the truth track parameter at this track State + // m_t_eLOC0.push_back(truthLOC0); + // m_t_eLOC1.push_back(truthLOC1); + // m_t_ePHI.push_back(truthPHI); + // m_t_eTHETA.push_back(truthTHETA); + // m_t_eQOP.push_back(truthQOP); + // m_t_eT.push_back(truthTIME); + + // get the geometry ID + auto geoID = surface.geometryId(); + m_volumeID.push_back(geoID.volume()); + m_layerID.push_back(geoID.layer()); + m_moduleID.push_back(geoID.sensitive()); + + // get the path length + m_pathLength.push_back(state.pathLength()); + + // expand the local measurements into the full bound space + Acts::BoundVector meas = + state.projector().transpose() * state.calibrated(); + // extract local and global position + Acts::Vector2 local(meas[Acts::eBoundLoc0], meas[Acts::eBoundLoc1]); + Acts::Vector3 mom(1, 1, 1); + Acts::Vector3 global = + surface.localToGlobal(gctx, local, mom); + + // fill the measurement info + m_lx_hit.push_back(local[Acts::ePos0]); + m_ly_hit.push_back(local[Acts::ePos1]); + m_x_hit.push_back(global[Acts::ePos0]); + m_y_hit.push_back(global[Acts::ePos1]); + m_z_hit.push_back(global[Acts::ePos2]); + + // status of the fitted track parameters + std::array<bool, 3> hasParams = {false, false, false}; + // optional fitted track parameters + std::optional<std::pair<Acts::BoundVector, Acts::BoundMatrix>> + trackParamsOpt = std::nullopt; + // lambda to get the fitted track parameters + auto getTrackParams = [&](unsigned int ipar) { + if (ipar == 0 && state.hasPredicted()) { + hasParams[0] = true; + m_nParams[0]++; + trackParamsOpt = + std::make_pair(state.predicted(), state.predictedCovariance()); + } else if (ipar == 1 && state.hasFiltered()) { + hasParams[1] = true; + m_nParams[1]++; + trackParamsOpt = + std::make_pair(state.filtered(), state.filteredCovariance()); + } else if (ipar == 2 && state.hasSmoothed()) { + hasParams[2] = true; + m_nParams[2]++; + trackParamsOpt = + std::make_pair(state.smoothed(), state.smoothedCovariance()); + } + }; + + // fill the fitted track parameters + for (unsigned int ipar = 0; ipar < 3; ++ipar) { + // get the fitted track parameters + getTrackParams(ipar); + if (trackParamsOpt) { + const auto& [parameters, covariance] = *trackParamsOpt; + if (ipar == 0) { + // + // local hit residual info + auto H = state.effectiveProjector(); + auto resCov = state.effectiveCalibratedCovariance() + + H * covariance * H.transpose(); + auto res = state.effectiveCalibrated() - H * parameters; + m_res_x_hit.push_back(res[Acts::eBoundLoc0]); + m_res_y_hit.push_back(res[Acts::eBoundLoc1]); + m_err_x_hit.push_back( + sqrt(resCov(Acts::eBoundLoc0, Acts::eBoundLoc0))); + m_err_y_hit.push_back( + sqrt(resCov(Acts::eBoundLoc1, Acts::eBoundLoc1))); + m_pull_x_hit.push_back( + res[Acts::eBoundLoc0] / + sqrt(resCov(Acts::eBoundLoc0, Acts::eBoundLoc0))); + m_pull_y_hit.push_back( + res[Acts::eBoundLoc1] / + sqrt(resCov(Acts::eBoundLoc1, Acts::eBoundLoc1))); + m_dim_hit.push_back(state.calibratedSize()); + } + + // track parameters + m_eLOC0[ipar].push_back(parameters[Acts::eBoundLoc0]); + m_eLOC1[ipar].push_back(parameters[Acts::eBoundLoc1]); + m_ePHI[ipar].push_back(parameters[Acts::eBoundPhi]); + m_eTHETA[ipar].push_back(parameters[Acts::eBoundTheta]); + m_eQOP[ipar].push_back(parameters[Acts::eBoundQOverP]); + m_eT[ipar].push_back(parameters[Acts::eBoundTime]); + + // track parameters residual + // m_res_eLOC0[ipar].push_back(parameters[Acts::eBoundLoc0] - truthLOC0); + // m_res_eLOC1[ipar].push_back(parameters[Acts::eBoundLoc1] - truthLOC1); + // float resPhi = Acts::detail::difference_periodic<float>( + // parameters[Acts::eBoundPhi], truthPHI, static_cast<float>(2 * M_PI)); + // m_res_ePHI[ipar].push_back(resPhi); + // m_res_eTHETA[ipar].push_back(parameters[Acts::eBoundTheta] - truthTHETA); + // m_res_eQOP[ipar].push_back(parameters[Acts::eBoundQOverP] - truthQOP); + // m_res_eT[ipar].push_back(parameters[Acts::eBoundTime] - truthTIME); + + // track parameters error + m_err_eLOC0[ipar].push_back(sqrt(covariance(Acts::eBoundLoc0, Acts::eBoundLoc0))); + m_err_eLOC1[ipar].push_back(sqrt(covariance(Acts::eBoundLoc1, Acts::eBoundLoc1))); + m_err_ePHI[ipar].push_back(sqrt(covariance(Acts::eBoundPhi, Acts::eBoundPhi))); + m_err_eTHETA[ipar].push_back(sqrt(covariance(Acts::eBoundTheta, Acts::eBoundTheta))); + m_err_eQOP[ipar].push_back(sqrt(covariance(Acts::eBoundQOverP, Acts::eBoundQOverP))); + m_err_eT[ipar].push_back(sqrt(covariance(Acts::eBoundTime, Acts::eBoundTime))); + + // track parameters pull + // m_pull_eLOC0[ipar].push_back( + // (parameters[Acts::eBoundLoc0] - truthLOC0) / + // sqrt(covariance(Acts::eBoundLoc0, Acts::eBoundLoc0))); + // m_pull_eLOC1[ipar].push_back( + // (parameters[Acts::eBoundLoc1] - truthLOC1) / + // sqrt(covariance(Acts::eBoundLoc1, Acts::eBoundLoc1))); + // m_pull_ePHI[ipar].push_back( + // resPhi / sqrt(covariance(Acts::eBoundPhi, Acts::eBoundPhi))); + // m_pull_eTHETA[ipar].push_back( + // (parameters[Acts::eBoundTheta] - truthTHETA) / + // sqrt(covariance(Acts::eBoundTheta, Acts::eBoundTheta))); + // m_pull_eQOP[ipar].push_back( + // (parameters[Acts::eBoundQOverP] - truthQOP) / + // sqrt(covariance(Acts::eBoundQOverP, Acts::eBoundQOverP))); + // m_pull_eT[ipar].push_back( + // (parameters[Acts::eBoundTime] - truthTIME) / + // sqrt(covariance(Acts::eBoundTime, Acts::eBoundTime))); + + // further track parameter info + Acts::FreeVector freeParams = + Acts::detail::transformBoundToFreeParameters(surface, gctx, parameters); + m_x[ipar].push_back(freeParams[Acts::eFreePos0]); + m_y[ipar].push_back(freeParams[Acts::eFreePos1]); + m_z[ipar].push_back(freeParams[Acts::eFreePos2]); + auto p = std::abs(1 / freeParams[Acts::eFreeQOverP]); + m_px[ipar].push_back(p * freeParams[Acts::eFreeDir0]); + m_py[ipar].push_back(p * freeParams[Acts::eFreeDir1]); + m_pz[ipar].push_back(p * freeParams[Acts::eFreeDir2]); + m_pT[ipar].push_back(p * std::hypot(freeParams[Acts::eFreeDir0], freeParams[Acts::eFreeDir1])); + m_eta[ipar].push_back(Acts::VectorHelpers::eta(freeParams.segment<3>(Acts::eFreeDir0))); + } else { + if (ipar == 0) { + // push default values if no track parameters + m_res_x_hit.push_back(-99.); + m_res_y_hit.push_back(-99.); + m_err_x_hit.push_back(-99.); + m_err_y_hit.push_back(-99.); + m_pull_x_hit.push_back(-99.); + m_pull_y_hit.push_back(-99.); + m_dim_hit.push_back(-99.); + } + // push default values if no track parameters + m_eLOC0[ipar].push_back(-99.); + m_eLOC1[ipar].push_back(-99.); + m_ePHI[ipar].push_back(-99.); + m_eTHETA[ipar].push_back(-99.); + m_eQOP[ipar].push_back(-99.); + m_eT[ipar].push_back(-99.); + m_res_eLOC0[ipar].push_back(-99.); + m_res_eLOC1[ipar].push_back(-99.); + m_res_ePHI[ipar].push_back(-99.); + m_res_eTHETA[ipar].push_back(-99.); + m_res_eQOP[ipar].push_back(-99.); + m_res_eT[ipar].push_back(-99.); + m_err_eLOC0[ipar].push_back(-99); + m_err_eLOC1[ipar].push_back(-99); + m_err_ePHI[ipar].push_back(-99); + m_err_eTHETA[ipar].push_back(-99); + m_err_eQOP[ipar].push_back(-99); + m_err_eT[ipar].push_back(-99); + m_pull_eLOC0[ipar].push_back(-99.); + m_pull_eLOC1[ipar].push_back(-99.); + m_pull_ePHI[ipar].push_back(-99.); + m_pull_eTHETA[ipar].push_back(-99.); + m_pull_eQOP[ipar].push_back(-99.); + m_pull_eT[ipar].push_back(-99.); + m_x[ipar].push_back(-99.); + m_y[ipar].push_back(-99.); + m_z[ipar].push_back(-99.); + m_px[ipar].push_back(-99.); + m_py[ipar].push_back(-99.); + m_pz[ipar].push_back(-99.); + m_pT[ipar].push_back(-99.); + m_eta[ipar].push_back(-99.); + } + // fill the track parameters status + m_hasParams[ipar].push_back(hasParams[ipar]); + } + + // fill the chi2 + m_chi2.push_back(state.chi2()); + + return true; + }); // all states + + // fill the variables for one track to tree + m_tree->Fill(); + + // now reset + m_t_x.clear(); + m_t_y.clear(); + m_t_z.clear(); + m_t_r.clear(); + m_t_dx.clear(); + m_t_dy.clear(); + m_t_dz.clear(); + m_t_eLOC0.clear(); + m_t_eLOC1.clear(); + m_t_ePHI.clear(); + m_t_eTHETA.clear(); + m_t_eQOP.clear(); + m_t_eT.clear(); + + m_volumeID.clear(); + m_layerID.clear(); + m_moduleID.clear(); + m_pathLength.clear(); + m_lx_hit.clear(); + m_ly_hit.clear(); + m_x_hit.clear(); + m_y_hit.clear(); + m_z_hit.clear(); + m_res_x_hit.clear(); + m_res_y_hit.clear(); + m_err_x_hit.clear(); + m_err_y_hit.clear(); + m_pull_x_hit.clear(); + m_pull_y_hit.clear(); + m_dim_hit.clear(); + + for (unsigned int ipar = 0; ipar < 3; ++ipar) { + m_hasParams[ipar].clear(); + m_eLOC0[ipar].clear(); + m_eLOC1[ipar].clear(); + m_ePHI[ipar].clear(); + m_eTHETA[ipar].clear(); + m_eQOP[ipar].clear(); + m_eT[ipar].clear(); + m_res_eLOC0[ipar].clear(); + m_res_eLOC1[ipar].clear(); + m_res_ePHI[ipar].clear(); + m_res_eTHETA[ipar].clear(); + m_res_eQOP[ipar].clear(); + m_res_eT[ipar].clear(); + m_err_eLOC0[ipar].clear(); + m_err_eLOC1[ipar].clear(); + m_err_ePHI[ipar].clear(); + m_err_eTHETA[ipar].clear(); + m_err_eQOP[ipar].clear(); + m_err_eT[ipar].clear(); + m_pull_eLOC0[ipar].clear(); + m_pull_eLOC1[ipar].clear(); + m_pull_ePHI[ipar].clear(); + m_pull_eTHETA[ipar].clear(); + m_pull_eQOP[ipar].clear(); + m_pull_eT[ipar].clear(); + m_x[ipar].clear(); + m_y[ipar].clear(); + m_z[ipar].clear(); + m_px[ipar].clear(); + m_py[ipar].clear(); + m_pz[ipar].clear(); + m_eta[ipar].clear(); + m_pT[ipar].clear(); + } + + m_chi2.clear(); + } // all subtrajectories + } // all trajectories + + return StatusCode::SUCCESS; +}