From d7b5cf78446ccb64585f509c107d7d9eacfa7d58 Mon Sep 17 00:00:00 2001 From: "zhangyz@ihep.ac.cn" <zhangyz@ihep.ac.cn> Date: Tue, 3 Dec 2024 10:16:42 +0800 Subject: [PATCH 01/12] add use costheta --- .vscode/settings.json | 21 +++++++++++++++++++++ Generator/src/GtGunTool.cpp | 18 ++++++++++++++++-- Generator/src/GtGunTool.h | 2 ++ 3 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..6ad48fa1 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,21 @@ +{ + "files.associations": { + "*.sycl": "cpp", + "*.hpp": "cpp", + "*.h": "cpp", + "*.c": "cpp", + "*.cpp": "cpp", + "array": "cpp", + "bitset": "cpp", + "initializer_list": "cpp", + "list": "cpp", + "random": "cpp", + "type_traits": "cpp", + "vector": "cpp", + "xhash": "cpp", + "xstring": "cpp", + "xtree": "cpp", + "xutility": "cpp", + "cmath": "cpp" + } +} \ No newline at end of file diff --git a/Generator/src/GtGunTool.cpp b/Generator/src/GtGunTool.cpp index ad747984..71206ebf 100644 --- a/Generator/src/GtGunTool.cpp +++ b/Generator/src/GtGunTool.cpp @@ -95,6 +95,19 @@ GtGunTool::initialize() { return StatusCode::FAILURE; } + if (m_usecostheta.value()) { + for (int i=0; i<m_thetamins.value().size(); ++i) { + if ((m_thetamins.value()[i] < -1) || (m_thetamins.value()[i] > 1)) { + error() << "UseCostheta: ThetaMins has values outside the range [-1, 1]." << endmsg; + return StatusCode::FAILURE; + } + if ((m_thetamaxs.value()[i] < -1) || (m_thetamaxs.value()[i] > 1)) { + error() << "UseCostheta: ThetaMaxs has values outside the range [-1, 1]." << endmsg; + return StatusCode::FAILURE; + } + } + } + // Time if (m_times.value().size()==0){ for(int i=0; i<m_particles.value().size(); i++) m_times.value().push_back(0); @@ -246,13 +259,14 @@ GtGunTool::mutate(Gen::GenEvent& event) { double theta = m_thetamins.value()[i]==m_thetamaxs.value()[i] ? m_thetamins.value()[i] : CLHEP::RandFlat::shoot(m_thetamins.value()[i], m_thetamaxs.value()[i]); double phi = m_phimins .value()[i]==m_phimaxs .value()[i] ? m_phimins .value()[i] : CLHEP::RandFlat::shoot(m_phimins .value()[i], m_phimaxs .value()[i]); - double costheta = cos(theta*acos(-1)/180); + + double costheta = (m_usecostheta.value()) ? theta : cos(theta*acos(-1)/180); double phi_ = phi*acos(-1)/180; double sintheta = sqrt(1.-costheta*costheta); double px = p*sintheta*cos(phi_); double py = p*sintheta*sin(phi_); double pz = p*costheta; - std::cout<<"GenGt p="<<p<<", px="<<px<<",py="<<py<<",pz="<<pz<<",theta="<<theta<<",phi="<<phi<<std::endl; + std::cout<<"GenGt p="<<p<<", px="<<px<<",py="<<py<<",pz="<<pz<<",theta="<< (m_usecostheta.value()) ? (acos(theta)/acos(-1)*180) : theta<<",phi="<<phi<<std::endl; mcp.setMomentum(edm4hep::Vector3f(px,py,pz)); // mcp.setMomentumAtEndpoint(); // mcp.setSpin(); diff --git a/Generator/src/GtGunTool.h b/Generator/src/GtGunTool.h index bc1fcd58..ec193bdf 100644 --- a/Generator/src/GtGunTool.h +++ b/Generator/src/GtGunTool.h @@ -57,6 +57,8 @@ private: Gaudi::Property<std::vector<double>> m_phimins{this, "PhiMins"}; Gaudi::Property<std::vector<double>> m_phimaxs{this, "PhiMaxs"}; + Gaudi::Property<bool> m_usecostheta{this, "UseCostheta", false}; + // For time Gaudi::Property<std::vector<double>> m_times{this, "Times"}; -- GitLab From 98e0fcaaf4c546f9266f41839806c93d7394f395 Mon Sep 17 00:00:00 2001 From: "zhangyz@ihep.ac.cn" <zhangyz@ihep.ac.cn> Date: Tue, 3 Dec 2024 10:58:55 +0800 Subject: [PATCH 02/12] add use costheta --- Generator/src/GtGunTool.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Generator/src/GtGunTool.cpp b/Generator/src/GtGunTool.cpp index 71206ebf..198f1a5c 100644 --- a/Generator/src/GtGunTool.cpp +++ b/Generator/src/GtGunTool.cpp @@ -266,7 +266,7 @@ GtGunTool::mutate(Gen::GenEvent& event) { double px = p*sintheta*cos(phi_); double py = p*sintheta*sin(phi_); double pz = p*costheta; - std::cout<<"GenGt p="<<p<<", px="<<px<<",py="<<py<<",pz="<<pz<<",theta="<< (m_usecostheta.value()) ? (acos(theta)/acos(-1)*180) : theta<<",phi="<<phi<<std::endl; + std::cout<<"GenGt p="<<p<<", px="<<px<<",py="<<py<<",pz="<<pz<<",theta="<<theta<<",phi="<<phi<<std::endl; mcp.setMomentum(edm4hep::Vector3f(px,py,pz)); // mcp.setMomentumAtEndpoint(); // mcp.setSpin(); -- GitLab From 4defa6d87a7792341b0b3bdaddf7318ae41234d1 Mon Sep 17 00:00:00 2001 From: "zhangyz@ihep.ac.cn" <zhangyz@ihep.ac.cn> Date: Tue, 3 Dec 2024 11:57:20 +0800 Subject: [PATCH 03/12] add use costheta --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 4dd952a9..9f405dfe 100644 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,6 @@ spack* ./Generator/output/ ./Generator/options/ +.vscode/ InstallArea/ venv -- GitLab From e57d5445b37f11293d2b2d5d593e3e6544416459 Mon Sep 17 00:00:00 2001 From: "zhangyz@ihep.ac.cn" <zhangyz@ihep.ac.cn> Date: Tue, 3 Dec 2024 11:58:04 +0800 Subject: [PATCH 04/12] add use costheta --- .gitignore | 1 - .vscode/settings.json | 21 --------------------- 2 files changed, 22 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.gitignore b/.gitignore index 9f405dfe..4dd952a9 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,5 @@ spack* ./Generator/output/ ./Generator/options/ -.vscode/ InstallArea/ venv diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 6ad48fa1..00000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "files.associations": { - "*.sycl": "cpp", - "*.hpp": "cpp", - "*.h": "cpp", - "*.c": "cpp", - "*.cpp": "cpp", - "array": "cpp", - "bitset": "cpp", - "initializer_list": "cpp", - "list": "cpp", - "random": "cpp", - "type_traits": "cpp", - "vector": "cpp", - "xhash": "cpp", - "xstring": "cpp", - "xtree": "cpp", - "xutility": "cpp", - "cmath": "cpp" - } -} \ No newline at end of file -- GitLab From 0832639dfce3b11618aed65833e57aef19deceed Mon Sep 17 00:00:00 2001 From: "zhangyz@ihep.ac.cn" <zhangyz@ihep.ac.cn> Date: Sun, 8 Dec 2024 12:46:15 +0800 Subject: [PATCH 05/12] add variables --- .vscode/settings.json | 12 ++++++++++++ Generator/src/GtGunTool.cpp | 39 ++++++++++++++++++++++++------------- Generator/src/GtGunTool.h | 3 ++- 3 files changed, 39 insertions(+), 15 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..3ade7b39 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,12 @@ +{ + "files.associations": { + "*.sycl": "cpp", + "*.hpp": "cpp", + "*.h": "cpp", + "*.c": "cpp", + "*.cpp": "cpp", + "chrono": "cpp", + "optional": "cpp", + "system_error": "cpp" + } +} \ No newline at end of file diff --git a/Generator/src/GtGunTool.cpp b/Generator/src/GtGunTool.cpp index 198f1a5c..3c953f1b 100644 --- a/Generator/src/GtGunTool.cpp +++ b/Generator/src/GtGunTool.cpp @@ -73,17 +73,6 @@ GtGunTool::initialize() { } // others should be empty or specify - if (m_thetamins.value().size() - && m_thetamins.value().size() != m_particles.value().size()) { - error() << "Mismatched thetamins and particles." << endmsg; - return StatusCode::FAILURE; - } - if (m_thetamaxs.value().size() - && m_thetamaxs.value().size() != m_particles.value().size()) { - error() << "Mismatched thetamaxs and particles." << endmsg; - return StatusCode::FAILURE; - } - if (m_phimins.value().size() && m_phimins.value().size() != m_particles.value().size()) { error() << "Mismatched phimins and particles." << endmsg; @@ -96,6 +85,14 @@ GtGunTool::initialize() { } if (m_usecostheta.value()) { + if (m_costhetamins.value().size() != m_particles.value().size()) { + error() << "Mismatched CosthetaMins and particles." << endmsg; + return StatusCode::FAILURE; + } + if (m_costhetamaxs.value().size() != m_particles.value().size()) { + error() << "Mismatched CosthetaMaxs and particles." << endmsg; + return StatusCode::FAILURE; + } for (int i=0; i<m_thetamins.value().size(); ++i) { if ((m_thetamins.value()[i] < -1) || (m_thetamins.value()[i] > 1)) { error() << "UseCostheta: ThetaMins has values outside the range [-1, 1]." << endmsg; @@ -106,6 +103,17 @@ GtGunTool::initialize() { return StatusCode::FAILURE; } } + } else { + if (m_thetamins.value().size() + && m_thetamins.value().size() != m_particles.value().size()) { + error() << "Mismatched thetamins and particles." << endmsg; + return StatusCode::FAILURE; + } + if (m_thetamaxs.value().size() + && m_thetamaxs.value().size() != m_particles.value().size()) { + error() << "Mismatched thetamaxs and particles." << endmsg; + return StatusCode::FAILURE; + } } // Time @@ -256,11 +264,14 @@ GtGunTool::mutate(Gen::GenEvent& event) { return false; } - - double theta = m_thetamins.value()[i]==m_thetamaxs.value()[i] ? m_thetamins.value()[i] : CLHEP::RandFlat::shoot(m_thetamins.value()[i], m_thetamaxs.value()[i]); + if (m_usecostheta.value()) { + double costheta = m_costhetamins.value()[i]==m_costhetamaxs.value()[i] ? m_costhetamins.value()[i] : CLHEP::RandFlat::shoot(m_costhetamins.value()[i], m_costhetamaxs.value()[i]); + } else { + double theta = m_thetamins.value()[i]==m_thetamaxs.value()[i] ? m_thetamins.value()[i] : CLHEP::RandFlat::shoot(m_thetamins.value()[i], m_thetamaxs.value()[i]); + double costheta = cos(theta*acos(-1)/180); + } double phi = m_phimins .value()[i]==m_phimaxs .value()[i] ? m_phimins .value()[i] : CLHEP::RandFlat::shoot(m_phimins .value()[i], m_phimaxs .value()[i]); - double costheta = (m_usecostheta.value()) ? theta : cos(theta*acos(-1)/180); double phi_ = phi*acos(-1)/180; double sintheta = sqrt(1.-costheta*costheta); double px = p*sintheta*cos(phi_); diff --git a/Generator/src/GtGunTool.h b/Generator/src/GtGunTool.h index ec193bdf..fb43164e 100644 --- a/Generator/src/GtGunTool.h +++ b/Generator/src/GtGunTool.h @@ -58,7 +58,8 @@ private: Gaudi::Property<std::vector<double>> m_phimaxs{this, "PhiMaxs"}; Gaudi::Property<bool> m_usecostheta{this, "UseCostheta", false}; - + Gaudi::Property<std::vector<double>> m_costhetamins{this, "CosthetaMins"}; + Gaudi::Property<std::vector<double>> m_costhetamaxs{this, "CosthetaMaxs"}; // For time Gaudi::Property<std::vector<double>> m_times{this, "Times"}; -- GitLab From 94ca44c470766a5ab6ec1b2ac610a456584bfc93 Mon Sep 17 00:00:00 2001 From: "zhangyz@ihep.ac.cn" <zhangyz@ihep.ac.cn> Date: Sun, 8 Dec 2024 12:49:48 +0800 Subject: [PATCH 06/12] add variables --- .vscode/settings.json | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 3ade7b39..00000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "files.associations": { - "*.sycl": "cpp", - "*.hpp": "cpp", - "*.h": "cpp", - "*.c": "cpp", - "*.cpp": "cpp", - "chrono": "cpp", - "optional": "cpp", - "system_error": "cpp" - } -} \ No newline at end of file -- GitLab From da5637f74e6f5ab8780897784e2a3b996f765c5a Mon Sep 17 00:00:00 2001 From: "zhangyz@ihep.ac.cn" <zhangyz@ihep.ac.cn> Date: Sun, 8 Dec 2024 12:56:29 +0800 Subject: [PATCH 07/12] add variables --- .vscode/settings.json | 13 +++++++++++++ Generator/src/GtGunTool.cpp | 16 +++++++++++----- 2 files changed, 24 insertions(+), 5 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..257d1d17 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,13 @@ +{ + "files.associations": { + "*.sycl": "cpp", + "*.hpp": "cpp", + "*.h": "cpp", + "*.c": "cpp", + "*.cpp": "cpp", + "cmath": "cpp", + "chrono": "cpp", + "optional": "cpp", + "system_error": "cpp" + } +} \ No newline at end of file diff --git a/Generator/src/GtGunTool.cpp b/Generator/src/GtGunTool.cpp index 3c953f1b..8ab4ce2e 100644 --- a/Generator/src/GtGunTool.cpp +++ b/Generator/src/GtGunTool.cpp @@ -264,20 +264,26 @@ GtGunTool::mutate(Gen::GenEvent& event) { return false; } + double costheta = 0; + double theta = 0; if (m_usecostheta.value()) { - double costheta = m_costhetamins.value()[i]==m_costhetamaxs.value()[i] ? m_costhetamins.value()[i] : CLHEP::RandFlat::shoot(m_costhetamins.value()[i], m_costhetamaxs.value()[i]); + costheta = m_costhetamins.value()[i]==m_costhetamaxs.value()[i] ? m_costhetamins.value()[i] : CLHEP::RandFlat::shoot(m_costhetamins.value()[i], m_costhetamaxs.value()[i]); } else { - double theta = m_thetamins.value()[i]==m_thetamaxs.value()[i] ? m_thetamins.value()[i] : CLHEP::RandFlat::shoot(m_thetamins.value()[i], m_thetamaxs.value()[i]); - double costheta = cos(theta*acos(-1)/180); + theta = m_thetamins.value()[i]==m_thetamaxs.value()[i] ? m_thetamins.value()[i] : CLHEP::RandFlat::shoot(m_thetamins.value()[i], m_thetamaxs.value()[i]); + costheta = cos(theta*acos(-1)/180); } - double phi = m_phimins .value()[i]==m_phimaxs .value()[i] ? m_phimins .value()[i] : CLHEP::RandFlat::shoot(m_phimins .value()[i], m_phimaxs .value()[i]); + double phi = m_phimins.value()[i]==m_phimaxs.value()[i] ? m_phimins.value()[i] : CLHEP::RandFlat::shoot(m_phimins.value()[i], m_phimaxs.value()[i]); double phi_ = phi*acos(-1)/180; double sintheta = sqrt(1.-costheta*costheta); double px = p*sintheta*cos(phi_); double py = p*sintheta*sin(phi_); double pz = p*costheta; - std::cout<<"GenGt p="<<p<<", px="<<px<<",py="<<py<<",pz="<<pz<<",theta="<<theta<<",phi="<<phi<<std::endl; + if(m_usecostheta.value()) { + std::cout<<"GenGt p="<<p<<", px="<<px<<",py="<<py<<",pz="<<pz<<",costheta="<<costheta<<",phi="<<phi<<std::endl; + } else { + std::cout<<"GenGt p="<<p<<", px="<<px<<",py="<<py<<",pz="<<pz<<",theta="<<theta<<",phi="<<phi<<std::endl; + } mcp.setMomentum(edm4hep::Vector3f(px,py,pz)); // mcp.setMomentumAtEndpoint(); // mcp.setSpin(); -- GitLab From 3f36769cd29dd6df3ebebb5756d29bf5ba9d6496 Mon Sep 17 00:00:00 2001 From: "zhangyz@ihep.ac.cn" <zhangyz@ihep.ac.cn> Date: Sun, 8 Dec 2024 12:57:12 +0800 Subject: [PATCH 08/12] add variables --- .vscode/settings.json | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 257d1d17..00000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "files.associations": { - "*.sycl": "cpp", - "*.hpp": "cpp", - "*.h": "cpp", - "*.c": "cpp", - "*.cpp": "cpp", - "cmath": "cpp", - "chrono": "cpp", - "optional": "cpp", - "system_error": "cpp" - } -} \ No newline at end of file -- GitLab From 916bee6c374b5f1e8dca3db32d9dbffa9c4a4082 Mon Sep 17 00:00:00 2001 From: stch-zhangyzh <zhangyzh@shanghaitech.edu.cn> Date: Tue, 21 Jan 2025 13:43:23 +0800 Subject: [PATCH 09/12] fix FTD bug --- .../RecActsTracking/src/RecActsTracking.cpp | 4 ++-- .../RecActsTracking/src/RecActsTracking.h | 21 ++++++++++--------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/Reconstruction/RecActsTracking/src/RecActsTracking.cpp b/Reconstruction/RecActsTracking/src/RecActsTracking.cpp index 40562fee..ba125e91 100644 --- a/Reconstruction/RecActsTracking/src/RecActsTracking.cpp +++ b/Reconstruction/RecActsTracking/src/RecActsTracking.cpp @@ -341,10 +341,10 @@ StatusCode RecActsTracking::execute() Acts::BoundSquareMatrix cov = Acts::BoundSquareMatrix::Zero(); for (std::size_t i = Acts::eBoundLoc0; i < Acts::eBoundSize; ++i) { double sigma = initialSigmas[i]; - sigma += initialSimgaQoverPCoefficients[i] * params[Acts::eBoundQOverP]; + sigma += abs(initialSimgaQoverPCoefficients[i] * params[Acts::eBoundQOverP]); double var = sigma * sigma; if (i == Acts::eBoundTime && !bottomSP->t().has_value()) { var *= noTimeVarInflation; } - var *= initialVarInflation[i]; + var *= initialVarInflation.value()[i]; cov(i, i) = var; } diff --git a/Reconstruction/RecActsTracking/src/RecActsTracking.h b/Reconstruction/RecActsTracking/src/RecActsTracking.h index afc66cd7..f7d44417 100644 --- a/Reconstruction/RecActsTracking/src/RecActsTracking.h +++ b/Reconstruction/RecActsTracking/src/RecActsTracking.h @@ -195,6 +195,7 @@ class RecActsTracking : public GaudiAlgorithm Gaudi::Property<double> SeedImpactMax{this, "SeedImpactMax", 3}; // mm Gaudi::Property<double> SeedRMinMiddle{this, "SeedRMinMiddle", 14}; // mm Gaudi::Property<double> SeedRMaxMiddle{this, "SeedRMaxMiddle", 24}; // mm + Gaudi::Property<std::vector<double>> initialVarInflation{this, "initialVarInflation", {1, 1, 20, 20, 20, 20}}; // CKF config Gaudi::Property<double> CKFchi2Cut{this, "CKFchi2Cut", std::numeric_limits<double>::max()}; @@ -259,20 +260,20 @@ class RecActsTracking : public GaudiAlgorithm // param estimate configuration double noTimeVarInflation = 100.; std::array<double, 6> initialSigmas = { - 25 * Acts::UnitConstants::um, - 100 * Acts::UnitConstants::um, - 0.02 * Acts::UnitConstants::degree, - 0.02 * Acts::UnitConstants::degree, - 0.1 * Acts::UnitConstants::e / Acts::UnitConstants::GeV, - 1400 * Acts::UnitConstants::s}; + 5 * Acts::UnitConstants::um, + 5 * Acts::UnitConstants::um, + 2e-2 * Acts::UnitConstants::degree, + 2e-2 * Acts::UnitConstants::degree, + 1e-1 * Acts::UnitConstants::e / Acts::UnitConstants::GeV, + 1 * Acts::UnitConstants::s}; std::array<double, 6> initialSimgaQoverPCoefficients = { 0 * Acts::UnitConstants::mm / (Acts::UnitConstants::e * Acts::UnitConstants::GeV), 0 * Acts::UnitConstants::mm / (Acts::UnitConstants::e * Acts::UnitConstants::GeV), - 0 * Acts::UnitConstants::degree / (Acts::UnitConstants::e * Acts::UnitConstants::GeV), - 0 * Acts::UnitConstants::degree / (Acts::UnitConstants::e * Acts::UnitConstants::GeV), - 0.1, + 7.1e-2 * Acts::UnitConstants::degree / (Acts::UnitConstants::e * Acts::UnitConstants::GeV), + 2.1e-2 * Acts::UnitConstants::degree / (Acts::UnitConstants::e * Acts::UnitConstants::GeV), + 6.4e-2, 0 * Acts::UnitConstants::ns / (Acts::UnitConstants::e * Acts::UnitConstants::GeV)}; - std::array<double, 6> initialVarInflation = {10., 10., 10., 10., 10., 10.}; + // std::array<double, 6> initialVarInflation = {10., 10., 10., 10., 10., 10.}; Acts::ParticleHypothesis particleHypothesis = Acts::ParticleHypothesis::muon(); std::array<std::string, 8> particleNames = {"muon", "pion", "electron", "kaon", "proton", "photon", "geantino", "chargedgeantino"}; // Acts::ParticleHypothesis particleHypothesis = Acts::ParticleHypothesis::chargedGeantino(); -- GitLab From 2260ed89fc0bb99a066e6e739bd1e71ec5b67952 Mon Sep 17 00:00:00 2001 From: "zhangyz@ihep.ac.cn" <zhangyz@ihep.ac.cn> Date: Thu, 5 Jun 2025 10:11:02 +0800 Subject: [PATCH 10/12] update ACTS for tdr25.5 --- .../RecActsTracking/ActsHelper/CMakeLists.txt | 55 + .../TrackFitting/RefittingCalibrator.hpp | 35 + .../TrackFitting/TrackFitterFunction.hpp | 112 ++ .../ActsHelper/Detectors/TGeoDetector.hpp | 179 ++ .../ActsHelper/EventData/AverageSimHits.hpp | 84 + .../include/ActsHelper/EventData/Cluster.hpp | 20 + .../ActsHelper/EventData/DriftCircle.hpp | 87 + .../EventData/ExtractedSimulationProcess.hpp | 19 + .../EventData/GeometryContainers.hpp | 224 +++ .../include/ActsHelper/EventData/Index.hpp | 53 + .../ActsHelper/EventData/IndexSourceLink.hpp | 86 + .../ActsHelper/EventData/Measurement.hpp | 19 + .../EventData/MeasurementCalibration.hpp | 69 + .../ActsHelper/EventData/MuonSimHit.hpp | 62 + .../ActsHelper/EventData/ProtoTrack.hpp | 16 + .../ActsHelper/EventData/ProtoVertex.hpp | 14 + .../EventData/ScalingCalibrator.hpp | 57 + .../include/ActsHelper/EventData/SimHit.hpp | 18 + .../ActsHelper/EventData/SimParticle.hpp | 67 + .../include/ActsHelper/EventData/SimSeed.hpp | 14 + .../ActsHelper/EventData/SimSpacePoint.hpp | 118 ++ .../ActsHelper/EventData/SimVertex.hpp | 130 ++ .../include/ActsHelper/EventData/Track.hpp | 30 + .../ActsHelper/EventData/Trajectories.hpp | 104 ++ .../ActsHelper/EventData/TruthMatching.hpp | 47 + .../include/ActsHelper/EventData/Vertex.hpp | 12 + .../MagneticField/FieldMapRootIo.hpp | 103 ++ .../MagneticField/FieldMapTextIo.hpp | 105 ++ .../MagneticField/MagneticField.hpp | 29 + .../MagneticField/ScalableBField.hpp | 104 ++ .../Utilities/EventDataTransforms.hpp | 16 + .../include/ActsHelper/Utilities/GroupBy.hpp | 133 ++ .../include/ActsHelper/Utilities/Helpers.hpp | 138 ++ .../include/ActsHelper/Utilities}/Options.hpp | 6 +- .../ActsHelper/Utilities/OptionsFwd.hpp | 11 + .../include/ActsHelper/Utilities/Paths.hpp | 39 + .../include/ActsHelper/Utilities/Range.hpp | 48 + .../include/ActsHelper/Utilities/tbbWrap.hpp | 166 ++ .../Validation/DuplicationPlotTool.hpp | 96 + .../ActsHelper/Validation/EffPlotTool.hpp | 81 + .../Validation/FakeRatePlotTool.hpp | 102 ++ .../ActsHelper/Validation/ResPlotTool.hpp | 122 ++ .../Validation/TrackClassification.hpp | 57 + .../Validation/TrackSummaryPlotTool.hpp | 88 + .../GlobalChiSquareFitterFunction.cpp | 157 ++ .../TrackFitting/GsfFitterFunction.cpp | 220 +++ .../TrackFitting/KalmanFitterFunction.cpp | 182 ++ .../TrackFitting/RefittingCalibrator.cpp | 35 + .../src/Detectors/TGeoDetector.cpp} | 168 +- .../src/EventData/MeasurementCalibration.cpp | 43 + .../src/EventData/ScalingCalibrator.cpp | 174 ++ .../src/MagneticField/FieldMapRootIo.cpp | 117 ++ .../src/MagneticField/FieldMapTextIo.cpp | 99 ++ .../src/Utilities/EventDataTransforms.cpp | 74 + .../ActsHelper/src/Utilities/Helpers.cpp | 101 ++ .../src/Utilities}/Options.cpp | 30 +- .../ActsHelper/src/Utilities/Paths.cpp | 108 ++ .../src/Validation/DuplicationPlotTool.cpp | 105 ++ .../ActsHelper/src/Validation/EffPlotTool.cpp | 66 + .../src/Validation/FakeRatePlotTool.cpp | 120 ++ .../ActsHelper/src/Validation/ResPlotTool.cpp | 249 +++ .../src/Validation/TrackClassification.cpp | 106 ++ .../src/Validation/TrackSummaryPlotTool.cpp | 110 ++ Reconstruction/RecActsTracking/CMakeLists.txt | 40 +- .../RecActsTracking/RecActsSvc/CMakeLists.txt | 34 + .../include/RecActsSvc/IRecActsSvc.h | 98 ++ .../RecActsSvc/src/RecActsSvc.cpp | 251 +++ .../RecActsSvc/src/RecActsSvc.h | 83 + .../RecActsSvc/src/csv2/mio.hpp | 1562 +++++++++++++++++ .../RecActsSvc/src/csv2/parameters.hpp | 50 + .../RecActsSvc/src/csv2/reader.hpp | 306 ++++ .../RecActsSvc/src/csv2/writer.hpp | 38 + .../RecActsTracking/CMakeLists.txt | 46 + .../options/RecActsTracking.py | 143 ++ .../RecActsTracking/src/RecActsReadInput.cpp | 447 +++++ .../RecActsTracking/src/RecActsReadInput.h | 103 ++ .../RecActsTracking/src/RecActsSeeding.cpp | 169 ++ .../RecActsTracking/src/RecActsSeeding.h | 84 + .../src/RecActsTrackFinding.cpp | 451 +++++ .../RecActsTracking/src/RecActsTrackFinding.h | 378 ++++ .../src/RecActsTrackFitting.cpp | 144 ++ .../RecActsTracking/src/RecActsTrackFitting.h | 194 ++ .../src/RecActsTrackParamsEstimation.cpp | 134 ++ .../src/RecActsTrackParamsEstimation.h | 80 + .../src/RecActsTrackReFitting.cpp | 401 +++++ .../src/RecActsTrackReFitting.h | 153 ++ .../RecActsTracking/src/RecActsTruthInput.cpp | 473 +++++ .../RecActsTracking/src/RecActsTruthInput.h | 100 ++ .../src/RecActsTruthTracking.cpp | 796 +++++++++ .../src/RecActsTruthTracking.h | 183 ++ .../options/RecActsTracking.py | 92 - .../RecActsTracking/src/RecActsTracking.cpp | 1208 ------------- .../RecActsTracking/src/RecActsTracking.h | 320 ---- .../RecActsTracking/src/utils/CKFhelper.hpp | 388 ---- .../src/utils/GeometryContainers.hpp | 355 ---- .../src/utils/MagneticField.hpp | 121 -- .../src/utils/SimSpacePoint.hpp | 243 --- 97 files changed, 12157 insertions(+), 2950 deletions(-) create mode 100644 Reconstruction/RecActsTracking/ActsHelper/CMakeLists.txt create mode 100644 Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Algorithms/TrackFitting/RefittingCalibrator.hpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Algorithms/TrackFitting/TrackFitterFunction.hpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Detectors/TGeoDetector.hpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/AverageSimHits.hpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/Cluster.hpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/DriftCircle.hpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/ExtractedSimulationProcess.hpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/GeometryContainers.hpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/Index.hpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/IndexSourceLink.hpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/Measurement.hpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/MeasurementCalibration.hpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/MuonSimHit.hpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/ProtoTrack.hpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/ProtoVertex.hpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/ScalingCalibrator.hpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/SimHit.hpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/SimParticle.hpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/SimSeed.hpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/SimSpacePoint.hpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/SimVertex.hpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/Track.hpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/Trajectories.hpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/TruthMatching.hpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/Vertex.hpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/MagneticField/FieldMapRootIo.hpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/MagneticField/FieldMapTextIo.hpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/MagneticField/MagneticField.hpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/MagneticField/ScalableBField.hpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Utilities/EventDataTransforms.hpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Utilities/GroupBy.hpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Utilities/Helpers.hpp rename Reconstruction/RecActsTracking/{src/utils => ActsHelper/include/ActsHelper/Utilities}/Options.hpp (98%) create mode 100644 Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Utilities/OptionsFwd.hpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Utilities/Paths.hpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Utilities/Range.hpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Utilities/tbbWrap.hpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Validation/DuplicationPlotTool.hpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Validation/EffPlotTool.hpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Validation/FakeRatePlotTool.hpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Validation/ResPlotTool.hpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Validation/TrackClassification.hpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Validation/TrackSummaryPlotTool.hpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/src/Algorithms/TrackFitting/GlobalChiSquareFitterFunction.cpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/src/Algorithms/TrackFitting/GsfFitterFunction.cpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/src/Algorithms/TrackFitting/KalmanFitterFunction.cpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/src/Algorithms/TrackFitting/RefittingCalibrator.cpp rename Reconstruction/RecActsTracking/{src/utils/TGeoDetector.hpp => ActsHelper/src/Detectors/TGeoDetector.cpp} (77%) create mode 100644 Reconstruction/RecActsTracking/ActsHelper/src/EventData/MeasurementCalibration.cpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/src/EventData/ScalingCalibrator.cpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/src/MagneticField/FieldMapRootIo.cpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/src/MagneticField/FieldMapTextIo.cpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/src/Utilities/EventDataTransforms.cpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/src/Utilities/Helpers.cpp rename Reconstruction/RecActsTracking/{src/utils => ActsHelper/src/Utilities}/Options.cpp (82%) create mode 100644 Reconstruction/RecActsTracking/ActsHelper/src/Utilities/Paths.cpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/src/Validation/DuplicationPlotTool.cpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/src/Validation/EffPlotTool.cpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/src/Validation/FakeRatePlotTool.cpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/src/Validation/ResPlotTool.cpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/src/Validation/TrackClassification.cpp create mode 100644 Reconstruction/RecActsTracking/ActsHelper/src/Validation/TrackSummaryPlotTool.cpp create mode 100644 Reconstruction/RecActsTracking/RecActsSvc/CMakeLists.txt create mode 100644 Reconstruction/RecActsTracking/RecActsSvc/include/RecActsSvc/IRecActsSvc.h create mode 100644 Reconstruction/RecActsTracking/RecActsSvc/src/RecActsSvc.cpp create mode 100644 Reconstruction/RecActsTracking/RecActsSvc/src/RecActsSvc.h create mode 100644 Reconstruction/RecActsTracking/RecActsSvc/src/csv2/mio.hpp create mode 100644 Reconstruction/RecActsTracking/RecActsSvc/src/csv2/parameters.hpp create mode 100644 Reconstruction/RecActsTracking/RecActsSvc/src/csv2/reader.hpp create mode 100644 Reconstruction/RecActsTracking/RecActsSvc/src/csv2/writer.hpp create mode 100644 Reconstruction/RecActsTracking/RecActsTracking/CMakeLists.txt create mode 100644 Reconstruction/RecActsTracking/RecActsTracking/options/RecActsTracking.py create mode 100644 Reconstruction/RecActsTracking/RecActsTracking/src/RecActsReadInput.cpp create mode 100644 Reconstruction/RecActsTracking/RecActsTracking/src/RecActsReadInput.h create mode 100644 Reconstruction/RecActsTracking/RecActsTracking/src/RecActsSeeding.cpp create mode 100644 Reconstruction/RecActsTracking/RecActsTracking/src/RecActsSeeding.h create mode 100644 Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTrackFinding.cpp create mode 100644 Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTrackFinding.h create mode 100644 Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTrackFitting.cpp create mode 100644 Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTrackFitting.h create mode 100644 Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTrackParamsEstimation.cpp create mode 100644 Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTrackParamsEstimation.h create mode 100644 Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTrackReFitting.cpp create mode 100644 Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTrackReFitting.h create mode 100644 Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTruthInput.cpp create mode 100644 Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTruthInput.h create mode 100644 Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTruthTracking.cpp create mode 100644 Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTruthTracking.h delete mode 100644 Reconstruction/RecActsTracking/options/RecActsTracking.py delete mode 100644 Reconstruction/RecActsTracking/src/RecActsTracking.cpp delete mode 100644 Reconstruction/RecActsTracking/src/RecActsTracking.h delete mode 100644 Reconstruction/RecActsTracking/src/utils/CKFhelper.hpp delete mode 100644 Reconstruction/RecActsTracking/src/utils/GeometryContainers.hpp delete mode 100644 Reconstruction/RecActsTracking/src/utils/MagneticField.hpp delete mode 100644 Reconstruction/RecActsTracking/src/utils/SimSpacePoint.hpp diff --git a/Reconstruction/RecActsTracking/ActsHelper/CMakeLists.txt b/Reconstruction/RecActsTracking/ActsHelper/CMakeLists.txt new file mode 100644 index 00000000..c6ff43b8 --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/CMakeLists.txt @@ -0,0 +1,55 @@ +find_package(Acts COMPONENTS + Core PluginFpeMonitoring PluginGeant4 PluginJson + PluginTGeo PluginDD4hep PluginEDM4hep Fatras) + +if(NOT Acts_FOUND) + message("Acts package not found. RecActsSvc module requires Acts.") + return() +endif() + +gaudi_add_library(ActsHelperLib + SOURCES + src/Detectors/TGeoDetector.cpp + + src/EventData/MeasurementCalibration.cpp + src/EventData/ScalingCalibrator.cpp + + src/MagneticField/FieldMapRootIo.cpp + src/MagneticField/FieldMapTextIo.cpp + + src/Utilities/EventDataTransforms.cpp + src/Utilities/Paths.cpp + src/Utilities/Options.cpp + src/Utilities/Helpers.cpp + + src/Validation/DuplicationPlotTool.cpp + src/Validation/EffPlotTool.cpp + src/Validation/FakeRatePlotTool.cpp + src/Validation/ResPlotTool.cpp + src/Validation/TrackClassification.cpp + src/Validation/TrackSummaryPlotTool.cpp + + src/Algorithms/TrackFitting/KalmanFitterFunction.cpp + src/Algorithms/TrackFitting/GsfFitterFunction.cpp + src/Algorithms/TrackFitting/GlobalChiSquareFitterFunction.cpp + src/Algorithms/TrackFitting/RefittingCalibrator.cpp + + LINK + EDM4HEP::edm4hep EDM4HEP::edm4hepDict + ActsCore ActsPluginFpeMonitoring ActsPluginGeant4 + ActsPluginJson ActsPluginTGeo ActsPluginDD4hep + ActsPluginEDM4hep ActsFatras +) + +target_include_directories(ActsHelperLib PUBLIC $ENV{ACTS}/include) + +target_include_directories(ActsHelperLib PUBLIC + ${LCIO_INCLUDE_DIRS} + $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}>/include + $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>) + +install(TARGETS ActsHelperLib + EXPORT CEPCSWTargets + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT bin + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT shlib + COMPONENT dev) diff --git a/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Algorithms/TrackFitting/RefittingCalibrator.hpp b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Algorithms/TrackFitting/RefittingCalibrator.hpp new file mode 100644 index 00000000..952e252d --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Algorithms/TrackFitting/RefittingCalibrator.hpp @@ -0,0 +1,35 @@ +#pragma once + +#include "Acts/EventData/MultiTrajectory.hpp" +#include "Acts/EventData/SourceLink.hpp" +#include "Acts/EventData/VectorMultiTrajectory.hpp" +#include "Acts/Geometry/GeometryContext.hpp" +#include "Acts/Geometry/GeometryIdentifier.hpp" +#include "Acts/Surfaces/Surface.hpp" +#include "Acts/Utilities/CalibrationContext.hpp" + +namespace Acts { +class ConstVectorMultiTrajectory; +class VectorMultiTrajectory; +} // namespace Acts + +namespace ActsHelper { + +struct RefittingCalibrator { + using Proxy = Acts::VectorMultiTrajectory::TrackStateProxy; + using ConstProxy = Acts::ConstVectorMultiTrajectory::ConstTrackStateProxy; + + struct RefittingSourceLink { + ConstProxy state; + + Acts::GeometryIdentifier geometryId() const { + return state.referenceSurface().geometryId(); + } + }; + + void calibrate(const Acts::GeometryContext& gctx, + const Acts::CalibrationContext& cctx, + const Acts::SourceLink& sourceLink, Proxy trackState) const; +}; + +} // namespace ActsHelper diff --git a/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Algorithms/TrackFitting/TrackFitterFunction.hpp b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Algorithms/TrackFitting/TrackFitterFunction.hpp new file mode 100644 index 00000000..ce1eb08c --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Algorithms/TrackFitting/TrackFitterFunction.hpp @@ -0,0 +1,112 @@ +#pragma once + +#include "Acts/EventData/SourceLink.hpp" +#include "Acts/EventData/TrackParameters.hpp" +#include "Acts/EventData/VectorMultiTrajectory.hpp" +#include "Acts/EventData/VectorTrackContainer.hpp" +#include "Acts/Geometry/GeometryContext.hpp" +#include "Acts/Geometry/TrackingGeometry.hpp" +#include "Acts/MagneticField/MagneticFieldContext.hpp" +#include "Acts/MagneticField/MagneticFieldProvider.hpp" +#include "Acts/Propagator/Propagator.hpp" +#include "Acts/TrackFitting/BetheHeitlerApprox.hpp" +#include "Acts/TrackFitting/GsfOptions.hpp" +#include "Acts/Utilities/CalibrationContext.hpp" +#include "ActsHelper/EventData/Measurement.hpp" +#include "ActsHelper/EventData/MeasurementCalibration.hpp" +#include "ActsHelper/EventData/Track.hpp" +#include "ActsHelper/Algorithms/TrackFitting/RefittingCalibrator.hpp" + +namespace ActsHelper { + +/// Fit function that takes the above parameters and runs a fit +/// @note This is separated into a virtual interface to keep compilation units +/// small. +class TrackFitterFunction { + public: + using TrackFitterResult = Acts::Result<TrackContainer::TrackProxy>; + + struct GeneralFitterOptions { + std::reference_wrapper<const Acts::GeometryContext> geoContext; + std::reference_wrapper<const Acts::MagneticFieldContext> magFieldContext; + std::reference_wrapper<const Acts::CalibrationContext> calibrationContext; + const Acts::Surface* referenceSurface = nullptr; + Acts::PropagatorPlainOptions propOptions; + }; + + virtual ~TrackFitterFunction() = default; + + virtual TrackFitterResult operator()(const std::vector<Acts::SourceLink>&, + const TrackParameters&, + const GeneralFitterOptions&, + const MeasurementCalibratorAdapter&, + TrackContainer&) const = 0; + + virtual TrackFitterResult operator()(const std::vector<Acts::SourceLink>&, + const TrackParameters&, + const GeneralFitterOptions&, + const RefittingCalibrator&, + const std::vector<const Acts::Surface*>&, + TrackContainer&) const = 0; +}; + +/// Makes a fitter function object for the Kalman Filter +/// +std::shared_ptr<TrackFitterFunction> makeKalmanFitterFunction( + std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry, + std::shared_ptr<const Acts::MagneticFieldProvider> magneticField, + bool multipleScattering = true, bool energyLoss = true, + double reverseFilteringMomThreshold = 0.0, + Acts::FreeToBoundCorrection freeToBoundCorrection = + Acts::FreeToBoundCorrection(), + const Acts::Logger& logger = *Acts::getDefaultLogger("Kalman", + Acts::Logging::INFO)); + +/// This type is used in the Examples framework for the Bethe-Heitler +/// approximation +using BetheHeitlerApprox = Acts::AtlasBetheHeitlerApprox<6, 5>; + +/// Available algorithms for the mixture reduction +enum class MixtureReductionAlgorithm { weightCut, KLDistance }; + +/// Makes a fitter function object for the GSF +/// +/// @param trackingGeometry the trackingGeometry for the propagator +/// @param magneticField the magnetic field for the propagator +/// @param betheHeitlerApprox The object that encapsulates the approximation. +/// @param maxComponents number of maximum components in the track state +/// @param weightCutoff when to drop components +/// @param componentMergeMethod How to merge a mixture to a single set of +/// parameters and covariance +/// @param mixtureReductionAlgorithm How to reduce the number of components +/// in a mixture +/// @param logger a logger instance +std::shared_ptr<TrackFitterFunction> makeGsfFitterFunction( + std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry, + std::shared_ptr<const Acts::MagneticFieldProvider> magneticField, + BetheHeitlerApprox betheHeitlerApprox, std::size_t maxComponents, + double weightCutoff, Acts::ComponentMergeMethod componentMergeMethod, + MixtureReductionAlgorithm mixtureReductionAlgorithm, + const Acts::Logger& logger); + +/// Makes a fitter function object for the Global Chi Square Fitter (GX2F) +/// +/// @param trackingGeometry the trackingGeometry for the propagator +/// @param magneticField the magnetic field for the propagator +/// @param multipleScattering bool +/// @param energyLoss bool +/// @param freeToBoundCorrection bool +/// @param nUpdateMax max number of iterations during the fit +/// @param relChi2changeCutOff Check for convergence (abort condition). Set to 0 to skip. +/// @param logger a logger instance +std::shared_ptr<TrackFitterFunction> makeGlobalChiSquareFitterFunction( + std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry, + std::shared_ptr<const Acts::MagneticFieldProvider> magneticField, + bool multipleScattering = true, bool energyLoss = true, + Acts::FreeToBoundCorrection freeToBoundCorrection = + Acts::FreeToBoundCorrection(), + std::size_t nUpdateMax = 5, double relChi2changeCutOff = 1e-7, + const Acts::Logger& logger = *Acts::getDefaultLogger("Gx2f", + Acts::Logging::INFO)); + +} // namespace ActsHelper diff --git a/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Detectors/TGeoDetector.hpp b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Detectors/TGeoDetector.hpp new file mode 100644 index 00000000..98c9c5d8 --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Detectors/TGeoDetector.hpp @@ -0,0 +1,179 @@ +#ifndef ACTSHELPER_TGEODETECTOR_HPP +#define ACTSHELPER_TGEODETECTOR_HPP + +#include "Acts/Geometry/CylinderVolumeBuilder.hpp" +#include "Acts/Geometry/CylinderVolumeHelper.hpp" +#include "Acts/Geometry/GeometryContext.hpp" +#include "Acts/Geometry/GeometryIdentifier.hpp" +#include "Acts/Geometry/ITrackingVolumeBuilder.hpp" +#include "Acts/Geometry/LayerArrayCreator.hpp" +#include "Acts/Geometry/LayerCreator.hpp" +#include "Acts/Geometry/PassiveLayerBuilder.hpp" +#include "Acts/Geometry/ProtoLayerHelper.hpp" +#include "Acts/Geometry/SurfaceArrayCreator.hpp" +#include "Acts/Geometry/SurfaceBinningMatcher.hpp" +#include "Acts/Geometry/TrackingGeometry.hpp" +#include "Acts/Geometry/TrackingGeometryBuilder.hpp" +#include "Acts/Geometry/TrackingVolumeArrayCreator.hpp" + +#include "Acts/Plugins/TGeo/TGeoCylinderDiscSplitter.hpp" +#include "Acts/Plugins/TGeo/TGeoLayerBuilder.hpp" +#include "Acts/Plugins/Json/JsonMaterialDecorator.hpp" +#include "Acts/Plugins/Json/ActsJson.hpp" + +#include "Acts/Utilities/BinningType.hpp" +#include "Acts/Utilities/Logger.hpp" + +#include <boost/program_options.hpp> +#include <nlohmann/json.hpp> + +#include <cstddef> +#include <map> +#include <memory> +#include <stdexcept> +#include <string> +#include <utility> +#include <vector> +#include <list> + +namespace Acts +{ + class TGeoDetectorElement; + class TrackingGeometry; + class IMaterialDecorator; +} + +/// ---------------------------- +/// pre definitions +/// ---------------------------- + +/// Half open [lower,upper) interval type for a single user option. +/// +/// A missing limit represents an unbounded upper or lower limit. With just +/// one defined limit the interval is just a lower/upper bound; with both +/// limits undefined, the interval is unbounded everywhere and thus contains +/// all possible values. +struct Interval +{ + std::optional<double> lower; + std::optional<double> upper; +}; + +/// Extract an interval from an input of the form 'lower:upper'. +/// +/// An input of the form `lower:` or `:upper` sets just one of the limits. Any +/// other input leads to an unbounded interval. +/// +/// @note The more common range notation uses `lower-upper` but the `-` +/// separator complicates the parsing of negative values. +std::istream& operator>>(std::istream& is, Interval& interval); + +/// Print an interval as `lower:upper`. +std::ostream& operator<<(std::ostream& os, const Interval& interval); + +struct TGeoConfig { + Acts::Logging::Level surfaceLogLevel = Acts::Logging::WARNING; + Acts::Logging::Level layerLogLevel = Acts::Logging::WARNING; + Acts::Logging::Level volumeLogLevel = Acts::Logging::WARNING; + + std::string fileName; + bool buildBeamPipe = false; + double beamPipeRadius{0}; + double beamPipeHalflengthZ{0}; + double beamPipeLayerThickness{0}; + double beamPipeEnvelopeR{1.0}; + double layerEnvelopeR{0.2}; + + double unitScalor = 1.0; + + Acts::TGeoLayerBuilder::ElementFactory elementFactory = + Acts::TGeoLayerBuilder::defaultElementFactory; + + /// Optional geometry identifier hook to be used during closure + std::shared_ptr<const Acts::GeometryIdentifierHook> geometryIdentifierHook = + std::make_shared<Acts::GeometryIdentifierHook>(); + + enum SubVolume : std::size_t { Negative = 0, Central, Positive }; + + template <typename T> + struct LayerTriplet + { + LayerTriplet() = default; + + LayerTriplet(T value) + : negative{value}, central{value}, positive{value} {} + + LayerTriplet(T _negative, T _central, T _positive) + : negative{_negative}, central{_central}, positive{_positive} {} + + T negative; + T central; + T positive; + + T& at(SubVolume i) + { + switch (i) + { + case Negative: return negative; + case Central: return central; + case Positive: return positive; + default: throw std::invalid_argument{"Unknown index"}; + } + } + + const T& at(SubVolume i) const + { + switch (i) + { + case Negative: return negative; + case Central: return central; + case Positive: return positive; + default: throw std::invalid_argument{"Unknown index"}; + } + } + }; + + struct Volume { + std::string name; + LayerTriplet<bool> layers{false}; + LayerTriplet<std::string> subVolumeName; + LayerTriplet<std::vector<std::string>> sensitiveNames; + LayerTriplet<std::string> sensitiveAxes; + LayerTriplet<Interval> rRange; + LayerTriplet<Interval> zRange; + LayerTriplet<double> splitTolR{0}; + LayerTriplet<double> splitTolZ{0}; + LayerTriplet<std::vector<std::pair<int, Acts::BinningType>>> binning0; + LayerTriplet<std::vector<std::pair<int, Acts::BinningType>>> binning1; + + Interval binToleranceR; + Interval binTolerancePhi; + Interval binToleranceZ; + + bool cylinderDiscSplit = false; + unsigned int cylinderNZSegments = 0; + unsigned int cylinderNPhiSegments = 0; + unsigned int discNRSegments = 0; + unsigned int discNPhiSegments = 0; + + bool itkModuleSplit = false; + std::map<std::string, unsigned int> barrelMap; + std::map<std::string, std::vector<std::pair<double, double>>> discMap; + /// pairs of regular expressions to match sensor names and category keys + /// for either the barrelMap or the discMap + /// @TODO in principle vector<pair< > > would be good enough + std::map<std::string, std::string> splitPatterns; + }; + + std::vector<Volume> volumes; +}; + +std::shared_ptr<const Acts::TrackingGeometry> buildTGeoDetector( + const Acts::GeometryContext& context, + std::vector<std::shared_ptr<const Acts::TGeoDetectorElement>>& detElementStore, + const std::string& TGeo_ROOTFilePath, + const std::string& TGeoConfig_jFilePath, + const std::string& MaterialMap_jFilePath, + const Acts::Logger& logger); + +#endif // ACTSHELPER_TGEODETECTOR_HPP \ No newline at end of file diff --git a/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/AverageSimHits.hpp b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/AverageSimHits.hpp new file mode 100644 index 00000000..3511cf15 --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/AverageSimHits.hpp @@ -0,0 +1,84 @@ +#pragma once + +#include "Acts/Definitions/Algebra.hpp" +#include "Acts/Definitions/TrackParametrization.hpp" +#include "Acts/Definitions/Units.hpp" +#include "Acts/Surfaces/Surface.hpp" +#include "Acts/Utilities/Logger.hpp" +#include "ActsHelper/EventData/Index.hpp" +#include "ActsHelper/EventData/SimHit.hpp" +#include "ActsHelper/Utilities/Range.hpp" + +#include <tuple> + +namespace ActsHelper { + +/// A range within a hit-simhits map. +using HitSimHitsRange = Range<IndexMultimap<Index>::const_iterator>; + +/// Create (average) truth representation for selected simulated hits. +/// +/// @param gCtx The geometry context for this +/// @param surface The reference surface of the measurement +/// @param simHits The simulated hits container +/// @param hitSimHitsRange Selection of simulated hits from the container +/// @return a local position, a 4D global position, a direction +/// +/// If more than one simulated hit is selected, the average truth information is +/// returned. +inline std::tuple<Acts::Vector2, Acts::Vector4, Acts::Vector3> averageSimHits( + const Acts::GeometryContext& gCtx, const Acts::Surface& surface, + const SimHitContainer& simHits, const HitSimHitsRange& hitSimHitsRange, + const Acts::Logger& logger) { + using namespace Acts::UnitLiterals; + + Acts::Vector2 avgLocal = Acts::Vector2::Zero(); + Acts::Vector4 avgPos4 = Acts::Vector4::Zero(); + Acts::Vector3 avgDir = Acts::Vector3::Zero(); + + std::size_t n = 0u; + for (auto [_, simHitIdx] : hitSimHitsRange) { + n += 1u; + + // we assume that the indices are within valid ranges so we do not need to + // check their validity again. + const auto& simHit = *simHits.nth(simHitIdx); + + // We use the thickness of the detector element as tolerance, because Geant4 + // treats the Surfaces as volumes and thus it is not ensured, that each hit + // lies exactly on the Acts::Surface + const auto tolerance = + surface.associatedDetectorElement() != nullptr + ? surface.associatedDetectorElement()->thickness() + : Acts::s_onSurfaceTolerance; + + // transforming first to local positions and average that ensures that the + // averaged position is still on the surface. the averaged global position + // might not be on the surface anymore. + auto result = surface.globalToLocal(gCtx, simHit.position(), + simHit.direction(), tolerance); + if (result.ok()) { + avgLocal += result.value(); + } else { + ACTS_WARNING("While averaging simhit, hit " + << simHitIdx << " is not on the corresponding surface " + << surface.geometryId() << "; use [0,0] as local position"); + } + // global position should already be at the intersection. no need to perform + // an additional intersection call. + avgPos4 += simHit.fourPosition(); + avgDir += simHit.direction(); + } + + // only need to average if there are at least two inputs + if (2u <= n) { + double scale = 1.0 / n; + avgLocal *= scale; + avgPos4 *= scale; + avgDir.normalize(); + } + + return {avgLocal, avgPos4, avgDir}; +} + +} // namespace ActsHelper diff --git a/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/Cluster.hpp b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/Cluster.hpp new file mode 100644 index 00000000..9bc1bb7d --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/Cluster.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include "ActsFatras/Digitization/Segmentizer.hpp" + +#include <vector> + +namespace ActsHelper { + +/// Simple struct holding cluster information. +struct Cluster { + using Cell = ActsFatras::Segmentizer::ChannelSegment; + std::size_t sizeLoc0 = 0; + std::size_t sizeLoc1 = 0; + std::vector<Cell> channels; +}; + +/// Clusters have a one-to-one relation with measurements +using ClusterContainer = std::vector<Cluster>; + +} // namespace ActsHelper diff --git a/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/DriftCircle.hpp b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/DriftCircle.hpp new file mode 100644 index 00000000..13491170 --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/DriftCircle.hpp @@ -0,0 +1,87 @@ +#pragma once + +#include "Acts/Definitions/Algebra.hpp" +#include "Acts/Definitions/Common.hpp" +#include "Acts/EventData/SourceLink.hpp" +#include "ActsHelper/EventData/Index.hpp" +#include "ActsHelper/EventData/IndexSourceLink.hpp" + +#include <cmath> +#include <vector> + +#include <boost/container/static_vector.hpp> + +namespace ActsHelper { + +/// representation of a drift circle measurement used for track finding +class DriftCircle { + using Scalar = Acts::ActsScalar; + + public: + /// Construct the drift circle from the drift radius and tube location + /// + /// @param tubePos position of the tube in the station frame + /// @param driftRadius measured drift radius + /// @param driftRadiusError error on drift radius + /// @param stationName station name index + /// @param stationEta station eta index + /// @param stationPhi station phi index + /// @param multilayer multilayer index + /// @param tubeLayer tube layer index + /// @param tube tube index + DriftCircle(const Acts::Vector3&& tubePos, float driftRadius, + float driftRadiusError, int stationName, int stationEta, + int stationPhi, int multilayer, int tubeLayer, int tube) + : m_x(tubePos[Acts::ePos0]), + m_y(tubePos[Acts::ePos1]), + m_z(tubePos[Acts::ePos2]), + m_rho(driftRadius), + m_sigmaRho(driftRadiusError), + m_stationName(stationName), + m_stationEta(stationEta), + m_stationPhi(stationPhi), + m_multilayer(multilayer), + m_tubeLayer(tubeLayer), + m_tube(tube) {} + + constexpr Scalar x() const { return m_x; } + constexpr Scalar y() const { return m_y; } + constexpr Scalar z() const { return m_z; } + constexpr Scalar rDrift() const { return m_rho; } + constexpr Scalar rDriftError() const { return m_sigmaRho; } + constexpr int stationName() const { return m_stationName; } + constexpr int stationEta() const { return m_stationEta; } + constexpr int stationPhi() const { return m_stationPhi; } + constexpr int multilayer() const { return m_multilayer; } + constexpr int tubeLayer() const { return m_tubeLayer; } + constexpr int tube() const { return m_tube; } + + private: + // Global position + Scalar m_x = 0.0f; + Scalar m_y = 0.0f; + Scalar m_z = 0.0f; + Scalar m_rho = 0.0f; + Scalar m_sigmaRho = 0.0f; + int m_stationName = 0; + int m_stationEta = 0; + int m_stationPhi = 0; + int m_multilayer = 0; + int m_tubeLayer = 0; + int m_tube = 0; +}; + +inline bool operator==(const DriftCircle& lhs, const DriftCircle& rhs) { + return (lhs.stationName() == rhs.stationName() && + lhs.stationEta() == rhs.stationEta() && + lhs.stationPhi() == rhs.stationPhi() && + lhs.multilayer() == rhs.multilayer() && + lhs.tubeLayer() == rhs.tubeLayer() && lhs.tube() == rhs.tube() && + std::abs(rhs.rDrift() - lhs.rDrift()) < 1.e-8 && + std::abs(rhs.rDriftError() - lhs.rDriftError()) < 1.e-8); +} + +/// Container of space points. +using DriftCircleContainer = std::vector<DriftCircle>; + +} // namespace ActsHelper diff --git a/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/ExtractedSimulationProcess.hpp b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/ExtractedSimulationProcess.hpp new file mode 100644 index 00000000..23a84167 --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/ExtractedSimulationProcess.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include "ActsHelper/EventData/SimParticle.hpp" + +#include <vector> + +namespace ActsHelper { + +/// Stores the initial properties of a particle, the properties before the +/// interaction and the particle properties after the interaction +struct ExtractedSimulationProcess { + SimParticle initial; + SimParticle before; + std::vector<SimParticle> after; +}; + +using ExtractedSimulationProcessContainer = + std::vector<ExtractedSimulationProcess>; +} // namespace ActsHelper diff --git a/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/GeometryContainers.hpp b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/GeometryContainers.hpp new file mode 100644 index 00000000..a7cdfc02 --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/GeometryContainers.hpp @@ -0,0 +1,224 @@ +#pragma once + +#include "Acts/EventData/SourceLink.hpp" +#include "Acts/Geometry/GeometryIdentifier.hpp" +#include "Acts/Surfaces/Surface.hpp" +#include "ActsHelper/Utilities/GroupBy.hpp" +#include "ActsHelper/Utilities/Range.hpp" + +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <iostream> +#include <utility> + +#include <boost/container/flat_map.hpp> +#include <boost/container/flat_set.hpp> + +namespace ActsHelper { +namespace detail { + +// extract the geometry identifier from a variety of types +struct GeometryIdGetter { + // explicit geometry identifier are just forwarded + constexpr Acts::GeometryIdentifier operator()( + Acts::GeometryIdentifier geometryId) const { + return geometryId; + } + // encoded geometry ids are converted back to geometry identifiers. + constexpr Acts::GeometryIdentifier operator()( + Acts::GeometryIdentifier::Value encoded) const { + return Acts::GeometryIdentifier(encoded); + } + // support elements in map-like structures. + template <typename T> + constexpr Acts::GeometryIdentifier operator()( + const std::pair<Acts::GeometryIdentifier, T>& mapItem) const { + return mapItem.first; + } + // support elements that implement `.geometryId()`. + template <typename T> + inline auto operator()(const T& thing) const + -> decltype(thing.geometryId(), Acts::GeometryIdentifier()) { + return thing.geometryId(); + } + // support reference_wrappers around such types as well + template <typename T> + inline auto operator()(std::reference_wrapper<T> thing) const + -> decltype(thing.get().geometryId(), Acts::GeometryIdentifier()) { + return thing.get().geometryId(); + } +}; + +struct CompareGeometryId { + // indicate that comparisons between keys and full objects are allowed. + using is_transparent = void; + // compare two elements using the automatic key extraction. + template <typename Left, typename Right> + constexpr bool operator()(Left&& lhs, Right&& rhs) const { + return GeometryIdGetter()(lhs) < GeometryIdGetter()(rhs); + } +}; + +} // namespace detail + +/// Store elements that know their detector geometry id, e.g. simulation hits. +/// +/// @tparam T type to be stored, must be compatible with `CompareGeometryId` +/// +/// The container stores an arbitrary number of elements for any geometry +/// id. Elements can be retrieved via the geometry id; elements can be selected +/// for a specific geometry id or for a larger range, e.g. a volume or a layer +/// within the geometry hierarchy using the helper functions below. Elements can +/// also be accessed by index that uniquely identifies each element regardless +/// of geometry id. +template <typename T> +using GeometryIdMultiset = + boost::container::flat_multiset<T, detail::CompareGeometryId>; + +/// Store elements indexed by an geometry id. +/// +/// @tparam T type to be stored +/// +/// The behaviour is the same as for the `GeometryIdMultiset` except that the +/// stored elements do not know their geometry id themself. When iterating +/// the iterator elements behave as for the `std::map`, i.e. +/// +/// for (const auto& entry: elements) { +/// auto id = entry.first; // geometry id +/// const auto& el = entry.second; // stored element +/// } +/// +template <typename T> +using GeometryIdMultimap = + GeometryIdMultiset<std::pair<Acts::GeometryIdentifier, T>>; + +/// Select all elements within the given volume. +template <typename T> +inline Range<typename GeometryIdMultiset<T>::const_iterator> selectVolume( + const GeometryIdMultiset<T>& container, + Acts::GeometryIdentifier::Value volume) { + auto cmp = Acts::GeometryIdentifier().setVolume(volume); + auto beg = std::lower_bound(container.begin(), container.end(), cmp, + detail::CompareGeometryId{}); + // WARNING overflows to volume==0 if the input volume is the last one + cmp = Acts::GeometryIdentifier().setVolume(volume + 1u); + // optimize search by using the lower bound as start point. also handles + // volume overflows since the geo id would be located before the start of + // the upper edge search window. + auto end = + std::lower_bound(beg, container.end(), cmp, detail::CompareGeometryId{}); + return makeRange(beg, end); +} + +/// Select all elements within the given volume. +template <typename T> +inline auto selectVolume(const GeometryIdMultiset<T>& container, + Acts::GeometryIdentifier id) { + return selectVolume(container, id.volume()); +} + +/// Select all elements within the given layer. +template <typename T> +inline Range<typename GeometryIdMultiset<T>::const_iterator> selectLayer( + const GeometryIdMultiset<T>& container, + Acts::GeometryIdentifier::Value volume, + Acts::GeometryIdentifier::Value layer) { + auto cmp = Acts::GeometryIdentifier().setVolume(volume).setLayer(layer); + auto beg = std::lower_bound(container.begin(), container.end(), cmp, + detail::CompareGeometryId{}); + // WARNING resets to layer==0 if the input layer is the last one + cmp = Acts::GeometryIdentifier().setVolume(volume).setLayer(layer + 1u); + // optimize search by using the lower bound as start point. also handles + // volume overflows since the geo id would be located before the start of + // the upper edge search window. + auto end = + std::lower_bound(beg, container.end(), cmp, detail::CompareGeometryId{}); + return makeRange(beg, end); +} + +// Select all elements within the given layer. +template <typename T> +inline auto selectLayer(const GeometryIdMultiset<T>& container, + Acts::GeometryIdentifier id) { + return selectLayer(container, id.volume(), id.layer()); +} + +/// Select all elements for the given module / sensitive surface. +template <typename T> +inline Range<typename GeometryIdMultiset<T>::const_iterator> selectModule( + const GeometryIdMultiset<T>& container, Acts::GeometryIdentifier geoId) { + // module is the lowest level and defines a single geometry id value + return makeRange(container.equal_range(geoId)); +} + +/// Select all elements for the given module / sensitive surface. +template <typename T> +inline auto selectModule(const GeometryIdMultiset<T>& container, + Acts::GeometryIdentifier::Value volume, + Acts::GeometryIdentifier::Value layer, + Acts::GeometryIdentifier::Value module) { + return selectModule( + container, + Acts::GeometryIdentifier().setVolume(volume).setLayer(layer).setSensitive( + module)); +} + +/// Select all elements for the lowest non-zero identifier component. +/// +/// Zero values of lower components are interpreted as wildcard search patterns +/// that select all element at the given geometry hierarchy and below. This only +/// applies to the lower components and not to intermediate zeros. +/// +/// Examples: +/// - volume=2,layer=0,module=3 -> select all elements in the module +/// - volume=1,layer=2,module=0 -> select all elements in the layer +/// - volume=3,layer=0,module=0 -> select all elements in the volume +/// +/// @note An identifier with all components set to zero selects the whole input +/// container. +/// @note Boundary and approach surfaces do not really fit into the geometry +/// hierarchy and must be set to zero for the selection. If they are set on an +/// input identifier, the behaviour of this search method is undefined. +template <typename T> +inline Range<typename GeometryIdMultiset<T>::const_iterator> +selectLowestNonZeroGeometryObject(const GeometryIdMultiset<T>& container, + Acts::GeometryIdentifier geoId) { + assert((geoId.boundary() == 0u) && "Boundary component must be zero"); + assert((geoId.approach() == 0u) && "Approach component must be zero"); + + if (geoId.sensitive() != 0u) { + return selectModule(container, geoId); + } else if (geoId.layer() != 0u) { + return selectLayer(container, geoId); + } else if (geoId.volume() != 0u) { + return selectVolume(container, geoId); + } else { + return makeRange(container.begin(), container.end()); + } +} + +/// Iterate over groups of elements belonging to each module/ sensitive surface. +template <typename T> +inline GroupBy<typename GeometryIdMultiset<T>::const_iterator, + detail::GeometryIdGetter> +groupByModule(const GeometryIdMultiset<T>& container) { + return makeGroupBy(container, detail::GeometryIdGetter()); +} + +/// The accessor for the GeometryIdMultiset container +/// +/// It wraps up a few lookup methods to be used in the Combinatorial Kalman +/// Filter +template <typename T> +struct GeometryIdMultisetAccessor { + using Container = GeometryIdMultiset<T>; + using Key = Acts::GeometryIdentifier; + using Value = typename GeometryIdMultiset<T>::value_type; + using Iterator = typename GeometryIdMultiset<T>::const_iterator; + + // pointer to the container + const Container* container = nullptr; +}; + +} // namespace ActsHelper diff --git a/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/Index.hpp b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/Index.hpp new file mode 100644 index 00000000..598f470b --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/Index.hpp @@ -0,0 +1,53 @@ +#pragma once + +#include <cstdint> + +#include <boost/container/flat_map.hpp> + +namespace ActsHelper { + +/// Index type to reference elements in a container. +/// +/// We do not expect to have more than 2^32 elements in any given container so a +/// fixed sized integer type is sufficient. +using Index = std::uint32_t; + +/// Store elements that are identified by an index, e.g. in another container. +/// +/// Each index can have zero or more associated elements. A typical case could +/// be to store all generating particles for a hit where the hit is identified +/// by its index in the hit container. +template <typename value_t> +using IndexMultimap = boost::container::flat_multimap<Index, value_t>; + +/// Invert the multimap, i.e. from a -> {b...} to b -> {a...}. +/// +/// @note This assumes that the value in the initial multimap is itself a +/// sortable index-like object, as would be the case when mapping e.g. +/// hit ids to particle ids/ barcodes. +template <typename value_t> +inline boost::container::flat_multimap<value_t, Index> invertIndexMultimap( + const IndexMultimap<value_t>& multimap) { + using InverseMultimap = boost::container::flat_multimap<value_t, Index>; + + // switch key-value without enforcing the new ordering (linear copy) + typename InverseMultimap::sequence_type unordered; + unordered.reserve(multimap.size()); + for (auto&& [index, value] : multimap) { + // value is now the key and the index is now the value + unordered.emplace_back(value, index); + } + + // adopting the unordered sequence will reestablish the correct order + InverseMultimap inverse; +#if BOOST_VERSION < 107800 + for (const auto& i : unordered) { + inverse.insert(i); + } +#else + inverse.insert(unordered.begin(), unordered.end()); +#endif + return inverse; +} + +} // namespace ActsHelper diff --git a/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/IndexSourceLink.hpp b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/IndexSourceLink.hpp new file mode 100644 index 00000000..41202c50 --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/IndexSourceLink.hpp @@ -0,0 +1,86 @@ +#pragma once + +#include "Acts/EventData/SourceLink.hpp" +#include "Acts/Geometry/TrackingGeometry.hpp" +#include "Acts/Surfaces/Surface.hpp" +#include "ActsHelper/EventData/GeometryContainers.hpp" +#include "ActsHelper/EventData/Index.hpp" + +#include <cassert> + +namespace ActsHelper { + +/// A source link that stores just an index. +/// +/// This is intentionally kept as barebones as possible. The source link +/// is just a reference and will be copied, moved around, etc. often. +/// Keeping it small and separate from the actual, potentially large, +/// measurement data should result in better overall performance. +/// Using an index instead of e.g. a pointer, means source link and +/// measurement are decoupled and the measurement representation can be +/// easily changed without having to also change the source link. +class IndexSourceLink final { + public: + /// Construct from geometry identifier and index. + constexpr IndexSourceLink(Acts::GeometryIdentifier gid, Index idx) + : m_geometryId(gid), m_index(idx) {} + + // Construct an invalid source link. Must be default constructible to + /// satisfy SourceLinkConcept. + IndexSourceLink() = default; + IndexSourceLink(const IndexSourceLink&) = default; + IndexSourceLink(IndexSourceLink&&) = default; + IndexSourceLink& operator=(const IndexSourceLink&) = default; + IndexSourceLink& operator=(IndexSourceLink&&) = default; + + /// Access the index. + constexpr Index index() const { return m_index; } + + Acts::GeometryIdentifier geometryId() const { return m_geometryId; } + + struct SurfaceAccessor { + const Acts::TrackingGeometry& trackingGeometry; + + const Acts::Surface* operator()(const Acts::SourceLink& sourceLink) const { + const auto& indexSourceLink = sourceLink.get<IndexSourceLink>(); + return trackingGeometry.findSurface(indexSourceLink.geometryId()); + } + }; + + private: + Acts::GeometryIdentifier m_geometryId; + Index m_index = 0; + + friend bool operator==(const IndexSourceLink& lhs, + const IndexSourceLink& rhs) { + return (lhs.geometryId() == rhs.geometryId()) && + (lhs.m_index == rhs.m_index); + } + friend bool operator!=(const IndexSourceLink& lhs, + const IndexSourceLink& rhs) { + return !(lhs == rhs); + } +}; + +/// Container of index source links. +/// +/// Since the source links provide a `.geometryId()` accessor, they can be +/// stored in an ordered geometry container. +using IndexSourceLinkContainer = GeometryIdMultiset<IndexSourceLink>; +/// Accessor for the above source link container +/// +/// It wraps up a few lookup methods to be used in the Combinatorial Kalman +/// Filter +struct IndexSourceLinkAccessor : GeometryIdMultisetAccessor<IndexSourceLink> { + using BaseIterator = GeometryIdMultisetAccessor<IndexSourceLink>::Iterator; + + using Iterator = Acts::SourceLinkAdapterIterator<BaseIterator>; + + // get the range of elements with requested geoId + std::pair<Iterator, Iterator> range(const Acts::Surface& surface) const { + assert(container != nullptr); + auto [begin, end] = container->equal_range(surface.geometryId()); + return {Iterator{begin}, Iterator{end}}; + } +}; +} // namespace ActsHelper diff --git a/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/Measurement.hpp b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/Measurement.hpp new file mode 100644 index 00000000..777d0325 --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/Measurement.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include <Acts/EventData/Measurement.hpp> + +#include <vector> + +namespace ActsHelper { + +/// Variable measurement type that can contain all possible combinations. +using Measurement = ::Acts::BoundVariantMeasurement; + +/// Container of measurements. +/// +/// In contrast to the source links, the measurements themself must not be +/// orderable. The source links stored in the measurements are treated +/// as opaque here and no ordering is enforced on the stored measurements. +using MeasurementContainer = std::vector<Measurement>; + +} // namespace ActsHelper diff --git a/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/MeasurementCalibration.hpp b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/MeasurementCalibration.hpp new file mode 100644 index 00000000..f9d68320 --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/MeasurementCalibration.hpp @@ -0,0 +1,69 @@ +#pragma once + +#include "Acts/EventData/MultiTrajectory.hpp" +#include "Acts/EventData/SourceLink.hpp" +#include "Acts/EventData/VectorMultiTrajectory.hpp" +#include "Acts/Geometry/GeometryContext.hpp" +#include "Acts/Utilities/CalibrationContext.hpp" +#include "ActsHelper/EventData/Cluster.hpp" +#include "ActsHelper/EventData/IndexSourceLink.hpp" +#include <ActsHelper/EventData/Measurement.hpp> + +#include <cassert> + +namespace Acts { +class VectorMultiTrajectory; +} // namespace Acts + +namespace ActsHelper { + +/// Abstract base class for measurement-based calibration +class MeasurementCalibrator { + public: + virtual void calibrate( + const MeasurementContainer& measurements, + const ClusterContainer* clusters, const Acts::GeometryContext& gctx, + const Acts::CalibrationContext& cctx, const Acts::SourceLink& sourceLink, + Acts::VectorMultiTrajectory::TrackStateProxy& trackState) const = 0; + + virtual ~MeasurementCalibrator() = default; + virtual bool needsClusters() const { return false; } +}; + +// Calibrator to convert an index source link to a measurement as-is +class PassThroughCalibrator : public MeasurementCalibrator { + public: + /// Find the measurement corresponding to the source link. + /// + /// @tparam parameters_t Track parameters type + /// @param gctx The geometry context (unused) + /// @param trackState The track state to calibrate + void calibrate( + const MeasurementContainer& measurements, + const ClusterContainer* clusters, const Acts::GeometryContext& gctx, + const Acts::CalibrationContext& cctx, const Acts::SourceLink& sourceLink, + Acts::VectorMultiTrajectory::TrackStateProxy& trackState) const override; +}; + +// Adapter class that wraps a MeasurementCalibrator to conform to the +// core ACTS calibration interface +class MeasurementCalibratorAdapter { + public: + MeasurementCalibratorAdapter(const MeasurementCalibrator& calibrator, + const MeasurementContainer& measurements, + const ClusterContainer* clusters = nullptr); + + MeasurementCalibratorAdapter() = delete; + + void calibrate(const Acts::GeometryContext& gctx, + const Acts::CalibrationContext& cctx, + const Acts::SourceLink& sourceLink, + Acts::VectorMultiTrajectory::TrackStateProxy trackState) const; + + private: + const MeasurementCalibrator& m_calibrator; + const MeasurementContainer& m_measurements; + const ClusterContainer* m_clusters; +}; + +} // namespace ActsHelper diff --git a/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/MuonSimHit.hpp b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/MuonSimHit.hpp new file mode 100644 index 00000000..36d60c7f --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/MuonSimHit.hpp @@ -0,0 +1,62 @@ +#pragma once + +#include "Acts/Definitions/Algebra.hpp" +#include "Acts/Definitions/Common.hpp" +#include "Acts/EventData/SourceLink.hpp" +#include "ActsHelper/EventData/Index.hpp" +#include "ActsHelper/EventData/IndexSourceLink.hpp" + +#include <cmath> +#include <vector> + +#include <boost/container/static_vector.hpp> + +namespace ActsHelper { +using MuonSimHit = SimHit; +/// Container of space points. +using MuonSimHitContainer = std::vector<MuonSimHit>; +constexpr int g_fieldShift = 8; +// field translators +enum class MuonIdentifierFieldMaps { + stationName = 40, + stationEta = 32, + stationPhi = 24, + multilayer = 16, + tubeLayer = 8, + tube = 0, +}; +struct muonMdtIdentifierFields { + int8_t stationName = 0; + int8_t stationEta = 0; + int8_t stationPhi = 0; + int8_t multilayer = 0; + int8_t tubeLayer = 0; + int8_t tube = 0; +}; +muonMdtIdentifierFields splitId(Acts::GeometryIdentifier::Value theID) { + muonMdtIdentifierFields f; + f.tube = theID & 0xFF; + theID = theID >> g_fieldShift; + f.tubeLayer = theID & 0xFF; + theID = theID >> g_fieldShift; + f.multilayer = theID & 0xFF; + theID = theID >> g_fieldShift; + f.stationPhi = theID & 0xFF; + theID = theID >> g_fieldShift; + f.stationEta = theID & 0xFF; + theID = theID >> g_fieldShift; + f.stationName = theID & 0xFF; + return f; +} +Acts::GeometryIdentifier::Value compressId(muonMdtIdentifierFields f) { + Acts::GeometryIdentifier::Value out{0}; + out = out << g_fieldShift | f.stationName; + out = out << g_fieldShift | f.stationEta; + out = out << g_fieldShift | f.stationPhi; + out = out << g_fieldShift | f.multilayer; + out = out << g_fieldShift | f.tubeLayer; + out = out << g_fieldShift | f.tube; + return out; +} + +} // namespace ActsHelper diff --git a/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/ProtoTrack.hpp b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/ProtoTrack.hpp new file mode 100644 index 00000000..f5bc2381 --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/ProtoTrack.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include "ActsHelper/EventData/Index.hpp" + +#include <vector> + +#include <boost/container/small_vector.hpp> + +namespace ActsHelper { + +/// A proto track is a collection of hits identified by their indices. +using ProtoTrack = boost::container::small_vector<Index, 3>; +/// Container of proto tracks. Each proto track is identified by its index. +using ProtoTrackContainer = std::vector<ProtoTrack>; + +} // namespace ActsHelper diff --git a/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/ProtoVertex.hpp b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/ProtoVertex.hpp new file mode 100644 index 00000000..def338da --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/ProtoVertex.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include "ActsHelper/EventData/Index.hpp" + +#include <vector> + +namespace ActsHelper { + +/// A proto vertex is a collection of tracks identified by their indices. +using ProtoVertex = std::vector<Index>; +/// Container of proto vertices. Each proto vertex is identified by its index. +using ProtoVertexContainer = std::vector<ProtoVertex>; + +} // namespace ActsHelper diff --git a/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/ScalingCalibrator.hpp b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/ScalingCalibrator.hpp new file mode 100644 index 00000000..15c2901e --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/ScalingCalibrator.hpp @@ -0,0 +1,57 @@ +#pragma once + +#include <Acts/Geometry/GeometryIdentifier.hpp> +#include <ActsHelper/EventData/MeasurementCalibration.hpp> + +#include <filesystem> + +#include <TFile.h> +#include <TH2D.h> + +namespace ActsHelper { + +class ScalingCalibrator : public MeasurementCalibrator { + public: + struct ConstantTuple { + double x_offset{0}; + double x_scale{1}; + double y_offset{0}; + double y_scale{1}; + }; + + struct MapTuple { + TH2D x_offset; + TH2D x_scale; + TH2D y_offset; + TH2D y_scale; + + ConstantTuple at(std::size_t sizeLoc0, std::size_t sizeLoc1) const { + ConstantTuple ct; + ct.x_offset = + x_offset.GetBinContent(x_offset.FindFixBin(sizeLoc0, sizeLoc1)); + ct.x_scale = + x_scale.GetBinContent(x_scale.FindFixBin(sizeLoc0, sizeLoc1)); + ct.y_offset = + y_offset.GetBinContent(y_offset.FindFixBin(sizeLoc0, sizeLoc1)); + ct.y_scale = + y_scale.GetBinContent(y_scale.FindFixBin(sizeLoc0, sizeLoc1)); + return ct; + } + }; + + ScalingCalibrator(const std::filesystem::path& path); + + void calibrate( + const MeasurementContainer& measurements, + const ClusterContainer* clusters, const Acts::GeometryContext& gctx, + const Acts::CalibrationContext& cctx, const Acts::SourceLink& sourceLink, + Acts::VectorMultiTrajectory::TrackStateProxy& trackState) const override; + + bool needsClusters() const override { return true; } + + private: + std::map<Acts::GeometryIdentifier, MapTuple> m_calib_maps; + std::bitset<3> m_mask; +}; + +} // namespace ActsHelper diff --git a/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/SimHit.hpp b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/SimHit.hpp new file mode 100644 index 00000000..1096acd7 --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/SimHit.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include "ActsHelper/EventData/GeometryContainers.hpp" +#include "ActsHelper/EventData/Index.hpp" +#include "ActsHelper/EventData/SimParticle.hpp" +#include "ActsFatras/EventData/Hit.hpp" + +namespace ActsHelper { + +using SimHit = ::ActsFatras::Hit; +/// Store hits ordered by geometry identifier. +using SimHitContainer = GeometryIdMultiset<SimHit>; + +using HitParticlesMap = IndexMultimap<SimBarcode>; + +using HitSimHitsMap = IndexMultimap<Index>; + +} // namespace ActsHelper diff --git a/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/SimParticle.hpp b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/SimParticle.hpp new file mode 100644 index 00000000..57589faf --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/SimParticle.hpp @@ -0,0 +1,67 @@ +#pragma once + +#include "ActsHelper/Utilities/GroupBy.hpp" +#include "ActsFatras/EventData/Particle.hpp" + +#include <boost/container/flat_set.hpp> + +namespace ActsHelper { +namespace detail { +struct CompareParticleId { + using is_transparent = void; + constexpr bool operator()(const ActsFatras::Particle& lhs, + const ActsFatras::Particle& rhs) const { + return lhs.particleId() < rhs.particleId(); + } + constexpr bool operator()(ActsFatras::Barcode lhs, + const ActsFatras::Particle& rhs) const { + return lhs < rhs.particleId(); + } + constexpr bool operator()(const ActsFatras::Particle& lhs, + ActsFatras::Barcode rhs) const { + return lhs.particleId() < rhs; + } +}; +struct PrimaryVertexIdGetter { + constexpr ActsFatras::Barcode operator()( + const ActsFatras::Particle& particle) const { + return ActsFatras::Barcode(0u).setVertexPrimary( + particle.particleId().vertexPrimary()); + } +}; +struct SecondaryVertexIdGetter { + constexpr ActsFatras::Barcode operator()( + const ActsFatras::Particle& particle) const { + return ActsFatras::Barcode(0u) + .setVertexPrimary(particle.particleId().vertexPrimary()) + .setVertexSecondary(particle.particleId().vertexSecondary()); + } +}; +} // namespace detail + +using SimBarcode = ::ActsFatras::Barcode; +using SimParticle = ::ActsFatras::Particle; +/// Store particles ordered by particle identifier. +using SimBarcodeContainer = ::boost::container::flat_set<SimBarcode>; +using SimParticleContainer = + ::boost::container::flat_set<SimParticle, detail::CompareParticleId>; + +/// Iterate over groups of particles belonging to the same primary vertex. +inline GroupBy<SimParticleContainer::const_iterator, + detail::PrimaryVertexIdGetter> +groupByPrimaryVertex(const SimParticleContainer& container) { + return makeGroupBy(container, detail::PrimaryVertexIdGetter()); +} + +/// Iterate over groups of particles belonging to the same secondary vertex. +/// +/// For each primary vertex, this yields one group of particles belonging +/// directly to the primary vertex (secondary vertex id 0) and a group for +/// each secondary vertex. +inline GroupBy<SimParticleContainer::const_iterator, + detail::SecondaryVertexIdGetter> +groupBySecondaryVertex(const SimParticleContainer& container) { + return makeGroupBy(container, detail::SecondaryVertexIdGetter()); +} + +} // namespace ActsHelper diff --git a/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/SimSeed.hpp b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/SimSeed.hpp new file mode 100644 index 00000000..3d883a22 --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/SimSeed.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include "Acts/Seeding/Seed.hpp" +#include "ActsHelper/EventData/SimSpacePoint.hpp" + +#include <map> +#include <vector> + +namespace ActsHelper { +using SimSeed = Acts::Seed<SimSpacePoint>; +/// Container of sim seed +using SimSeedContainer = std::vector<SimSeed>; + +} // namespace ActsHelper diff --git a/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/SimSpacePoint.hpp b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/SimSpacePoint.hpp new file mode 100644 index 00000000..5f3267b8 --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/SimSpacePoint.hpp @@ -0,0 +1,118 @@ +#pragma once + +#include "Acts/Definitions/Algebra.hpp" +#include "Acts/Definitions/Common.hpp" +#include "Acts/EventData/SourceLink.hpp" +#include "ActsHelper/EventData/Index.hpp" +#include "ActsHelper/EventData/IndexSourceLink.hpp" + +// edm4hep +#include "edm4hep/TrackerHit.h" +#include "edm4hep/SimTrackerHit.h" + +#include <cmath> +#include <vector> + +#include <boost/container/static_vector.hpp> + +namespace ActsHelper { +/// Space point representation of a measurement suitable for track seeding. +class SimSpacePoint { + using Scalar = Acts::ActsScalar; + +public: + SimSpacePoint(float x, float y, float z, float t, + float varianceRho, + float varianceZ, + float varianceT, + boost::container::static_vector<Acts::SourceLink, 2> sourceLinks) + : m_x(x), m_y(y), m_z(z), m_t(t), + m_rho(std::hypot(x, y)), + m_varianceRho(varianceRho), + m_varianceZ(varianceZ), + m_varianceT(varianceT), + m_sourceLinks(sourceLinks){} + + constexpr Scalar x() const { return m_x; } + constexpr Scalar y() const { return m_y; } + constexpr Scalar z() const { return m_z; } + + constexpr std::optional<Scalar> t() const { return m_t; } + constexpr Scalar r() const { return m_rho; } + constexpr Scalar varianceR() const { return m_varianceRho; } + constexpr Scalar varianceZ() const { return m_varianceZ; } + constexpr std::optional<Scalar> varianceT() const { return m_varianceT; } + + // constexpr std::uint64_t cellid() const { return m_cellid; } + // constexpr Acts::GeometryIdentifier geometryId() const { return m_geometryId; } + + const boost::container::static_vector<Acts::SourceLink, 2>& + sourceLinks() const { return m_sourceLinks; } + + constexpr float topHalfStripLength() const { return m_topHalfStripLength; } + constexpr float bottomHalfStripLength() const { return m_bottomHalfStripLength; } + + Acts::Vector3 topStripDirection() const { return m_topStripDirection; } + Acts::Vector3 bottomStripDirection() const { return m_bottomStripDirection; } + Acts::Vector3 stripCenterDistance() const { return m_stripCenterDistance; } + Acts::Vector3 topStripCenterPosition() const { return m_topStripCenterPosition; } + + constexpr bool validDoubleMeasurementDetails() const { + return m_validDoubleMeasurementDetails; + } + +private: + + // Global position + Scalar m_x; + Scalar m_y; + Scalar m_z; + + std::optional<Scalar> m_t; + Scalar m_rho; + // Variance in rho/z of the global coordinates + Scalar m_varianceRho; + Scalar m_varianceZ; + std::optional<Scalar> m_varianceT; + // SourceLinks of the corresponding measurements. A Pixel (strip) SP has one + // (two) sourceLink(s). + boost::container::static_vector<Acts::SourceLink, 2> m_sourceLinks; + + // half of the length of the top strip + float m_topHalfStripLength = 0; + // half of the length of the bottom strip + float m_bottomHalfStripLength = 0; + // direction of the top strip + Acts::Vector3 m_topStripDirection = {0, 0, 0}; + // direction of the bottom strip + Acts::Vector3 m_bottomStripDirection = {0, 0, 0}; + // distance between the center of the two strips + Acts::Vector3 m_stripCenterDistance = {0, 0, 0}; + // position of the center of the bottom strip + Acts::Vector3 m_topStripCenterPosition = {0, 0, 0}; + bool m_validDoubleMeasurementDetails = false; + +}; // SimSpacePoint + +inline bool operator==(const SimSpacePoint& lhs, const SimSpacePoint& rhs) { + // TODO would it be sufficient to check just the index under the assumption + // that the same measurement index always produces the same space point? + // no need to check r since it is fully defined by x/y + + return (std::equal(lhs.sourceLinks().begin(), lhs.sourceLinks().end(), + rhs.sourceLinks().begin(), + [](const auto& lsl, const auto& rsl) { + return lsl.template get<IndexSourceLink>() == + rsl.template get<IndexSourceLink>(); + }) && + (lhs.x() == rhs.x()) && (lhs.y() == rhs.y()) && + (lhs.z() == rhs.z()) && (lhs.t() == rhs.t()) && + (lhs.varianceR() == rhs.varianceR()) && + (lhs.varianceZ() == rhs.varianceZ()) && + (lhs.varianceT() == rhs.varianceT())); +} + +/// Container of space points. +using SimSpacePointContainer = std::vector<SimSpacePoint>; + +} // namespace ActsHelper diff --git a/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/SimVertex.hpp b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/SimVertex.hpp new file mode 100644 index 00000000..8e604f97 --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/SimVertex.hpp @@ -0,0 +1,130 @@ +#pragma once + +#include "Acts/Definitions/Algebra.hpp" +#include "ActsHelper/EventData/SimParticle.hpp" +#include "ActsFatras/EventData/ProcessType.hpp" + +#include <boost/container/flat_set.hpp> + +namespace ActsHelper { + +class SimVertexBarcode { + public: + using Value = SimBarcode::Value; + + constexpr SimVertexBarcode() = default; + constexpr SimVertexBarcode(Value encoded) : m_id(SimBarcode(encoded)) {} + constexpr SimVertexBarcode(SimBarcode vertexId) + : m_id(vertexId.setParticle(0).setSubParticle(0)) { + if (vertexId != vertexId.vertexId()) { + throw std::invalid_argument("SimVertexBarcode: invalid vertexId"); + } + } + + /// Get the encoded value of all index levels. + constexpr Value value() const { return m_id.value(); } + + /// Return the barcode. + constexpr SimBarcode barcode() const { return m_id; } + + /// Return the primary vertex identifier. + constexpr Value vertexPrimary() const { return m_id.vertexPrimary(); } + /// Return the secondary vertex identifier. + constexpr Value vertexSecondary() const { return m_id.vertexSecondary(); } + /// Return the generation identifier. + constexpr Value generation() const { return m_id.generation(); } + + /// Set the primary vertex identifier. + constexpr SimVertexBarcode& setVertexPrimary(Value id) { + return m_id.setVertexPrimary(id), *this; + } + /// Set the secondary vertex identifier. + constexpr SimVertexBarcode& setVertexSecondary(Value id) { + return m_id.setVertexSecondary(id), *this; + } + /// Set the particle identifier. + constexpr SimVertexBarcode& setGeneration(Value id) { + return m_id.setGeneration(id), *this; + } + + private: + /// The vertex ID + /// Note that only primary, secondary and generation should be set + SimBarcode m_id = 0; + + friend constexpr bool operator<(SimVertexBarcode lhs, SimVertexBarcode rhs) { + return lhs.m_id < rhs.m_id; + } + friend constexpr bool operator==(SimVertexBarcode lhs, SimVertexBarcode rhs) { + return lhs.m_id == rhs.m_id; + } + friend constexpr bool operator!=(SimVertexBarcode lhs, SimVertexBarcode rhs) { + return lhs.m_id != rhs.m_id; + } + friend inline std::ostream& operator<<(std::ostream& os, + SimVertexBarcode idx) { + return os << idx.m_id; + } +}; + +/// A simultated vertex e.g. from a physics process. +struct SimVertex { + using Scalar = Acts::ActsScalar; + using Vector4 = Acts::ActsVector<4>; + + /// The vertex ID + SimVertexBarcode id; + /// The vertex four-position + Vector4 position4 = Vector4::Zero(); + /// The vertex process type + ActsFatras::ProcessType process = ActsFatras::ProcessType::eUndefined; + /// The incoming particles into the vertex + SimBarcodeContainer incoming; + /// The outgoing particles from the vertex + SimBarcodeContainer outgoing; + + /// Construct the vertex from a position and optional process type. + /// + /// @param position4_ the vertex four-position + /// @param process_ the process type that generated this vertex + /// + /// Associated particles are left empty by default and must be filled by the + /// user after construction. + SimVertex( + SimVertexBarcode id_, const Vector4& position4_, + ActsFatras::ProcessType process_ = ActsFatras::ProcessType::eUndefined) + : id(id_), position4(position4_), process(process_) {} + // explicitly default rule-of-five. + SimVertex() = default; + SimVertex(const SimVertex&) = default; + SimVertex(SimVertex&&) = default; + SimVertex& operator=(const SimVertex&) = default; + SimVertex& operator=(SimVertex&&) = default; + + constexpr SimVertexBarcode vertexId() const { return id; } + /// The vertex three-position. + auto position() const { return position4.head<3>(); } + /// The vertex time. + Scalar time() const { return position4[3]; } +}; + +namespace detail { +struct CompareVertexId { + using is_transparent = void; + constexpr bool operator()(const SimVertex& lhs, const SimVertex& rhs) const { + return lhs.vertexId() < rhs.vertexId(); + } + constexpr bool operator()(SimVertexBarcode lhs, const SimVertex& rhs) const { + return lhs < rhs.vertexId(); + } + constexpr bool operator()(const SimVertex& lhs, SimVertexBarcode rhs) const { + return lhs.vertexId() < rhs; + } +}; +} // namespace detail + +/// Store vertices ordered by vertex identifier. +using SimVertexContainer = + ::boost::container::flat_set<SimVertex, detail::CompareVertexId>; + +} // namespace ActsHelper diff --git a/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/Track.hpp b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/Track.hpp new file mode 100644 index 00000000..3fd7abaa --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/Track.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include "Acts/EventData/TrackContainer.hpp" +#include "Acts/EventData/TrackParameters.hpp" +#include "Acts/EventData/VectorMultiTrajectory.hpp" +#include "Acts/EventData/VectorTrackContainer.hpp" + +#include <vector> + +namespace ActsHelper { + +/// (Reconstructed) track parameters e.g. close to the vertex. +using TrackParameters = ::Acts::BoundTrackParameters; +/// Container of reconstructed track states for multiple tracks. +using TrackParametersContainer = std::vector<TrackParameters>; + +using TrackContainer = + Acts::TrackContainer<Acts::VectorTrackContainer, + Acts::VectorMultiTrajectory, std::shared_ptr>; + +using ConstTrackContainer = + Acts::TrackContainer<Acts::ConstVectorTrackContainer, + Acts::ConstVectorMultiTrajectory, std::shared_ptr>; + +using TrackIndexType = TrackContainer::IndexType; + +using TrackProxy = TrackContainer::TrackProxy; +using ConstTrackProxy = ConstTrackContainer::ConstTrackProxy; + +} // namespace ActsHelper diff --git a/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/Trajectories.hpp b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/Trajectories.hpp new file mode 100644 index 00000000..9a87aad8 --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/Trajectories.hpp @@ -0,0 +1,104 @@ +#pragma once + +#include "Acts/EventData/MultiTrajectory.hpp" +#include "Acts/EventData/VectorMultiTrajectory.hpp" +#include "Acts/Utilities/ThrowAssert.hpp" +#include "ActsHelper/EventData/IndexSourceLink.hpp" +#include "ActsHelper/EventData/Track.hpp" + +#include <algorithm> +#include <unordered_map> +#include <vector> + +namespace ActsHelper { + +/// Store reconstructed trajectories from track finding/fitting. +/// +/// It contains a MultiTrajectory with a vector of entry indices for +/// individual trajectories, and a map of fitted parameters indexed by the +/// entry index. In case of track fitting, there is at most one trajectory +/// in the MultiTrajectory; In case of track finding, there could be +/// multiple trajectories in the MultiTrajectory. +struct Trajectories final { + public: + /// (Reconstructed) trajectory with multiple states. + using MultiTrajectory = Acts::ConstVectorMultiTrajectory; + /// Fitted parameters identified by indices in the multi trajectory. + using IndexedParameters = + std::unordered_map<Acts::MultiTrajectoryTraits::IndexType, + TrackParameters>; + + /// Default construct an empty object. Required for container compatibility + /// and to signal an error. + Trajectories() = default; + /// Construct from fitted multi trajectory and parameters. + /// + /// @param multiTraj The multi trajectory + /// /// @param tTips Tip indices that identify valid trajectories + /// @param parameters Fitted track parameters indexed by trajectory index + Trajectories(const MultiTrajectory& multiTraj, + const std::vector<Acts::MultiTrajectoryTraits::IndexType>& tTips, + const IndexedParameters& parameters) + : m_multiTrajectory(&multiTraj), + m_trackTips(tTips), + m_trackParameters(parameters) {} + + /// Return true if there exists no valid trajectory. + bool empty() const { return m_trackTips.empty(); } + + /// Access the underlying multi trajectory. + const MultiTrajectory& multiTrajectory() const { + throw_assert(m_multiTrajectory != nullptr, "MultiTrajectory is null"); + return *m_multiTrajectory; + } + + /// Access the tip indices that identify valid trajectories. + const std::vector<Acts::MultiTrajectoryTraits::IndexType>& tips() const { + return m_trackTips; + } + + /// Check if a trajectory exists for the given index. + /// + /// @param entryIndex The trajectory entry index + /// @return Whether there is trajectory with provided entry index + bool hasTrajectory(Acts::MultiTrajectoryTraits::IndexType entryIndex) const { + return (0 < std::count(m_trackTips.begin(), m_trackTips.end(), entryIndex)); + } + + /// Check if fitted track parameters exists for the given index. + /// + /// @param entryIndex The trajectory entry index + /// @return Whether having fitted track parameters or not + bool hasTrackParameters( + Acts::MultiTrajectoryTraits::IndexType entryIndex) const { + return (0 < m_trackParameters.count(entryIndex)); + } + + /// Access the fitted track parameters for the given index. + /// + /// @param entryIndex The trajectory entry index + /// @return The fitted track parameters of the trajectory + const TrackParameters& trackParameters( + Acts::MultiTrajectoryTraits::IndexType entryIndex) const { + auto it = m_trackParameters.find(entryIndex); + if (it == m_trackParameters.end()) { + throw std::runtime_error( + "No fitted track parameters for trajectory with entry index = " + + std::to_string(entryIndex)); + } + return it->second; + } + + private: + // The track container + const MultiTrajectory* m_multiTrajectory{nullptr}; + // The entry indices of trajectories stored in multiTrajectory + std::vector<Acts::MultiTrajectoryTraits::IndexType> m_trackTips = {}; + // The fitted parameters at the provided surface for individual trajectories + IndexedParameters m_trackParameters = {}; +}; + +/// Container for multiple trajectories. +using TrajectoriesContainer = std::vector<Trajectories>; + +} // namespace ActsHelper diff --git a/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/TruthMatching.hpp b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/TruthMatching.hpp new file mode 100644 index 00000000..9ae6d25e --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/TruthMatching.hpp @@ -0,0 +1,47 @@ +#pragma once + +#include "ActsHelper/EventData/ProtoTrack.hpp" +#include "ActsHelper/EventData/SimParticle.hpp" +#include "ActsHelper/EventData/Track.hpp" +#include "ActsHelper/Validation/TrackClassification.hpp" + +#include <cstdint> +#include <map> +#include <optional> +#include <vector> + +namespace ActsHelper { + +enum class TrackMatchClassification { + Unknown = 0, + /// The track is associated to a truth particle + Matched, + /// The track is associated to a truth particle, but the track is not unique + Duplicate, + /// The track cannot be uniquely associated to a truth particle + Fake, +}; + +struct TrackMatchEntry { + TrackMatchClassification classification{TrackMatchClassification::Unknown}; + + std::optional<SimBarcode> particle; + + /// Number of hits on the track that are associated to a particle + /// Sorted by decreasing number of hits + std::vector<ParticleHitCount> contributingParticles; +}; + +struct ParticleMatchEntry { + std::optional<TrackIndexType> track; + std::uint32_t duplicates{}; + std::uint32_t fakes{}; +}; + +using ProtoTrackParticleMatching = std::map<TrackIndexType, TrackMatchEntry>; +using ParticleProtoTrackMatching = std::map<SimBarcode, ParticleMatchEntry>; + +using TrackParticleMatching = std::map<TrackIndexType, TrackMatchEntry>; +using ParticleTrackMatching = std::map<SimBarcode, ParticleMatchEntry>; + +} // namespace ActsHelper diff --git a/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/Vertex.hpp b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/Vertex.hpp new file mode 100644 index 00000000..adc1d442 --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/EventData/Vertex.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include "Acts/Vertexing/Vertex.hpp" + +#include <vector> + +namespace ActsHelper { + +/// Container of vertices. +using VertexContainer = std::vector<Acts::Vertex>; + +} // namespace ActsHelper diff --git a/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/MagneticField/FieldMapRootIo.hpp b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/MagneticField/FieldMapRootIo.hpp new file mode 100644 index 00000000..4fa9a285 --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/MagneticField/FieldMapRootIo.hpp @@ -0,0 +1,103 @@ +#pragma once + +#include "Acts/Definitions/Algebra.hpp" +#include "ActsHelper/MagneticField/MagneticField.hpp" + +#include <array> +#include <cstddef> +#include <functional> +#include <string> + +namespace ActsHelper { + +/// Method to setup the FieldMap +/// @param localToGlobalBin Function mapping the local bins of r,z to the +/// global +/// bin of the map magnetic field value e.g.: we have small grid with the +/// values: r={2,3}, z ={4,5}, the corresponding indices are i(r) and j(z), +/// the +/// globalIndex is M and the field map is: +///|| r | i || z | j || |B(r,z)| || M || +/// ----------------------------------- +///|| 2 | 0 || 4 | 0 || 2.323 || 0 || +///|| 2 | 0 || 5 | 1 || 2.334 || 1 || +///|| 3 | 1 || 4 | 0 || 2.325 || 2 || +///|| 3 | 1 || 5 | 1 || 2.331 || 3 || +/// +/// @code +/// In this case the function would look like: +/// [](std::array<std::size_t, 2> binsRZ, std::array<std::size_t, 2> nBinsRZ) { +/// return (binsRZ.at(0) * nBinsRZ.at(1) + binsRZ.at(1)); +/// } +/// @endcode +/// @param[in] fieldMapFile Path to file containing field map in txt format +/// @param[in] treeName The name of the root tree +/// @param[in] lengthUnit The unit of the grid points +/// @param[in] BFieldUnit The unit of the magnetic field +/// @param[in] firstQuadrant Flag if set to true indicating that only the +/// first +/// quadrant of the grid points and the BField values has been given and +/// that +/// the BFieldMap should be created symmetrically for all quadrants. +/// e.g. we have the grid values r={0,1} with BFieldValues={2,3} on the r +/// axis. +/// If the flag is set to true the r-axis grid values will be set to +/// {-1,0,1} +/// and the BFieldValues will be set to {3,2,3}. +detail::InterpolatedMagneticField2 makeMagneticFieldMapRzFromRoot( + const std::function<std::size_t(std::array<std::size_t, 2> binsRZ, + std::array<std::size_t, 2> nBinsRZ)>& + localToGlobalBin, + const std::string& fieldMapFile, const std::string& treeName, + Acts::ActsScalar lengthUnit, Acts::ActsScalar BFieldUnit, + bool firstQuadrant = false); + +/// Method to setup the FieldMap +/// @param localToGlobalBin Function mapping the local bins of x,y,z to the +/// global bin of the map magnetic field value e.g.: we have small grid with +/// the +/// values: x={2,3}, y={3,4}, z ={4,5}, the corresponding indices are i(x), +/// j(y) +/// and z(k), the globalIndex is M and the field map is: +///|| x | i || y | j || z | k || |B(x,y,z)| || M || +/// -------------------------------------------- +///|| 2 | 0 || 3 | 0 || 4 | 0 || 2.323 || 0 || +///|| 2 | 0 || 3 | 0 || 5 | 1 || 2.334 || 1 || +///|| 2 | 0 || 4 | 1 || 4 | 0 || 2.325 || 2 || +///|| 2 | 0 || 4 | 1 || 5 | 1 || 2.331 || 3 || +///|| 3 | 1 || 3 | 0 || 4 | 0 || 2.323 || 4 || +///|| 3 | 1 || 3 | 0 || 5 | 1 || 2.334 || 5 || +///|| 3 | 1 || 4 | 1 || 4 | 0 || 2.325 || 6 || +///|| 3 | 1 || 4 | 1 || 5 | 1 || 2.331 || 7 || +/// +/// @code +/// In this case the function would look like: +/// [](std::array<std::size_t, 3> binsXYZ, std::array<std::size_t, 3> nBinsXYZ) +/// { +/// return (binsXYZ.at(0) * (nBinsXYZ.at(1) * nBinsXYZ.at(2)) +/// + binsXYZ.at(1) * nBinsXYZ.at(2) +/// + binsXYZ.at(2)); +/// } +/// @endcode +/// @param[in] fieldMapFile Path to file containing field map in txt format +/// @param[in] treeName The name of the root tree +/// @param[in] lengthUnit The unit of the grid points +/// @param[in] BFieldUnit The unit of the magnetic field +/// @param[in] firstOctant Flag if set to true indicating that only the +/// first +/// octant of the grid points and the BField values has been given and that +/// the BFieldMap should be created symmetrically for all quadrants. +/// e.g. we have the grid values z={0,1} with BFieldValues={2,3} on the r +/// axis. +/// If the flag is set to true the z-axis grid values will be set to +/// {-1,0,1} +/// and the BFieldValues will be set to {3,2,3}. +detail::InterpolatedMagneticField3 makeMagneticFieldMapXyzFromRoot( + const std::function<std::size_t(std::array<std::size_t, 3> binsXYZ, + std::array<std::size_t, 3> nBinsXYZ)>& + localToGlobalBin, + const std::string& fieldMapFile, const std::string& treeName, + Acts::ActsScalar lengthUnit, Acts::ActsScalar BFieldUnit, + bool firstOctant = false); + +} // namespace ActsHelper diff --git a/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/MagneticField/FieldMapTextIo.hpp b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/MagneticField/FieldMapTextIo.hpp new file mode 100644 index 00000000..362f8601 --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/MagneticField/FieldMapTextIo.hpp @@ -0,0 +1,105 @@ +#pragma once + +#include "Acts/Definitions/Algebra.hpp" +#include "ActsHelper/MagneticField/MagneticField.hpp" + +#include <array> +#include <cstddef> +#include <functional> +#include <string> + +namespace ActsHelper { + +/// Method to setup the FieldMapper +/// @param localToGlobalBin Function mapping the local bins of r,z to the +/// global +/// bin of the map magnetic field value e.g.: we have small grid with the +/// values: r={2,3}, z ={4,5}, the corresponding indices are i(r) and j(z), +/// the +/// globalIndex is M and the field map is: +///|| r | i || z | j || |B(r,z)| || M || +/// ----------------------------------- +///|| 2 | 0 || 4 | 0 || 2.323 || 0 || +///|| 2 | 0 || 5 | 1 || 2.334 || 1 || +///|| 3 | 1 || 4 | 0 || 2.325 || 2 || +///|| 3 | 1 || 5 | 1 || 2.331 || 3 || +/// +/// @code +/// In this case the function would look like: +/// [](std::array<std::size_t, 2> binsRZ, std::array<std::size_t, 2> nBinsRZ) { +/// return (binsRZ.at(0) * nBinsRZ.at(1) + binsRZ.at(1)); +/// } +/// @endcode +/// @param[in] fieldMapFile Path to file containing field map in txt format +/// @param[in] lengthUnit The unit of the grid points +/// @param[in] BFieldUnit The unit of the magnetic field +/// @note This information is only used as a hint for the required size of +/// the internal vectors. A correct value is not needed, but will help +/// to speed up the field map initialization process. +/// @param[in] firstQuadrant Flag if set to true indicating that only the +/// first +/// quadrant of the grid points and the BField values has been given and +/// that +/// the BFieldMap should be created symmetrically for all quadrants. +/// e.g. we have the grid values r={0,1} with BFieldValues={2,3} on the r +/// axis. +/// If the flag is set to true the r-axis grid values will be set to +/// {-1,0,1} +/// and the BFieldValues will be set to {3,2,3}. +detail::InterpolatedMagneticField2 makeMagneticFieldMapRzFromText( + const std::function<std::size_t(std::array<std::size_t, 2> binsRZ, + std::array<std::size_t, 2> nBinsRZ)>& + localToGlobalBin, + const std::string& fieldMapFile, Acts::ActsScalar lengthUnit, + Acts::ActsScalar BFieldUnit, bool firstQuadrant = false); + +/// Method to setup the FieldMapper +/// @param localToGlobalBin Function mapping the local bins of x,y,z to the +/// global bin of the map magnetic field value e.g.: we have small grid with +/// the +/// values: x={2,3}, y={3,4}, z ={4,5}, the corresponding indices are i(x), +/// j(y) +/// and z(k), the globalIndex is M and the field map is: +///|| x | i || y | j || z | k || |B(x,y,z)| || M || +/// -------------------------------------------- +///|| 2 | 0 || 3 | 0 || 4 | 0 || 2.323 || 0 || +///|| 2 | 0 || 3 | 0 || 5 | 1 || 2.334 || 1 || +///|| 2 | 0 || 4 | 1 || 4 | 0 || 2.325 || 2 || +///|| 2 | 0 || 4 | 1 || 5 | 1 || 2.331 || 3 || +///|| 3 | 1 || 3 | 0 || 4 | 0 || 2.323 || 4 || +///|| 3 | 1 || 3 | 0 || 5 | 1 || 2.334 || 5 || +///|| 3 | 1 || 4 | 1 || 4 | 0 || 2.325 || 6 || +///|| 3 | 1 || 4 | 1 || 5 | 1 || 2.331 || 7 || +/// +/// @code +/// In this case the function would look like: +/// [](std::array<std::size_t, 3> binsXYZ, std::array<std::size_t, 3> nBinsXYZ) +/// { +/// return (binsXYZ.at(0) * (nBinsXYZ.at(1) * nBinsXYZ.at(2)) +/// + binsXYZ.at(1) * nBinsXYZ.at(2) +/// + binsXYZ.at(2)); +/// } +/// @endcode +/// @param[in] fieldMapFile Path to file containing field map in txt format +/// @param[in] lengthUnit The unit of the grid points +/// @param[in] BFieldUnit The unit of the magnetic field +/// @note This information is only used as a hint for the required size of +/// the internal vectors. A correct value is not needed, but will help +/// to speed up the field map initialization process. +/// @param[in] firstOctant Flag if set to true indicating that only the +/// first +/// octant of the grid points and the BField values has been given and that +/// the BFieldMap should be created symmetrically for all quadrants. +/// e.g. we have the grid values z={0,1} with BFieldValues={2,3} on the r +/// axis. +/// If the flag is set to true the z-axis grid values will be set to +/// {-1,0,1} +/// and the BFieldValues will be set to {3,2,3}. +detail::InterpolatedMagneticField3 makeMagneticFieldMapXyzFromText( + const std::function<std::size_t(std::array<std::size_t, 3> binsXYZ, + std::array<std::size_t, 3> nBinsXYZ)>& + localToGlobalBin, + const std::string& fieldMapFile, Acts::ActsScalar lengthUnit, + Acts::ActsScalar BFieldUnit, bool firstOctant = false); + +} // namespace ActsHelper diff --git a/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/MagneticField/MagneticField.hpp b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/MagneticField/MagneticField.hpp new file mode 100644 index 00000000..0a3b3c2c --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/MagneticField/MagneticField.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include "Acts/Definitions/Algebra.hpp" +#include "Acts/MagneticField/ConstantBField.hpp" +#include "Acts/MagneticField/InterpolatedBFieldMap.hpp" +#include "Acts/MagneticField/MagneticFieldProvider.hpp" +#include "Acts/MagneticField/NullBField.hpp" +#include "Acts/Utilities/Grid.hpp" +#include "Acts/Utilities/Result.hpp" +#include "Acts/Utilities/detail/Axis.hpp" +#include "Acts/Utilities/detail/AxisFwd.hpp" +#include "Acts/Utilities/detail/grid_helper.hpp" +#include "ActsHelper/MagneticField/ScalableBField.hpp" + +#include <memory> +#include <variant> +#include <vector> + +namespace ActsHelper::detail { + +using InterpolatedMagneticField2 = Acts::InterpolatedBFieldMap< + Acts::Grid<Acts::Vector2, Acts::detail::EquidistantAxis, + Acts::detail::EquidistantAxis>>; + +using InterpolatedMagneticField3 = Acts::InterpolatedBFieldMap< + Acts::Grid<Acts::Vector3, Acts::detail::EquidistantAxis, + Acts::detail::EquidistantAxis, Acts::detail::EquidistantAxis>>; + +} // namespace ActsHelper::detail diff --git a/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/MagneticField/ScalableBField.hpp b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/MagneticField/ScalableBField.hpp new file mode 100644 index 00000000..33d9649b --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/MagneticField/ScalableBField.hpp @@ -0,0 +1,104 @@ +#pragma once + +#include "Acts/Definitions/Algebra.hpp" +#include "Acts/MagneticField/MagneticFieldContext.hpp" +#include "Acts/MagneticField/MagneticFieldProvider.hpp" + +namespace ActsHelper { + +/// The ScalableBField-specific magnetic field context. +struct ScalableBFieldContext { + Acts::ActsScalar scalor = 1.; +}; + +/// A constant magnetic field that is scaled depending on the event context. +class ScalableBField final : public Acts::MagneticFieldProvider { + public: + struct Cache { + Acts::ActsScalar scalor = 1.; + + /// @brief constructor with context + Cache(const Acts::MagneticFieldContext& mctx) { + scalor = mctx.get<const ScalableBFieldContext>().scalor; + } + }; + + /// @brief construct constant magnetic field from field vector + /// + /// @param [in] B magnetic field vector in global coordinate system + explicit ScalableBField(Acts::Vector3 B) : m_BField(std::move(B)) {} + + /// @brief construct constant magnetic field from components + /// + /// @param [in] Bx magnetic field component in global x-direction + /// @param [in] By magnetic field component in global y-direction + /// @param [in] Bz magnetic field component in global z-direction + ScalableBField(Acts::ActsScalar Bx = 0, Acts::ActsScalar By = 0, + Acts::ActsScalar Bz = 0) + : m_BField(Bx, By, Bz) {} + + /// @brief retrieve magnetic field value + /// + /// @param [in] position global position + /// @param [in] cache Cache object (is ignored) + /// @return magnetic field vector + /// + /// @note The @p position is ignored and only kept as argument to provide + /// a consistent interface with other magnetic field services. + Acts::Result<Acts::Vector3> getField( + const Acts::Vector3& /*position*/, + MagneticFieldProvider::Cache& gCache) const override { + Cache& cache = gCache.as<Cache>(); + return Acts::Result<Acts::Vector3>::success(m_BField * cache.scalor); + } + + /// @brief retrieve magnetic field value & its gradient + /// + /// @param [in] position global position + /// @param [out] derivative gradient of magnetic field vector as (3x3) + /// matrix + /// @param [in] cache Cache object (is ignored) + /// @return magnetic field vector + /// + /// @note The @p position is ignored and only kept as argument to provide + /// a consistent interface with other magnetic field services. + /// @note currently the derivative is not calculated + /// @todo return derivative + Acts::Result<Acts::Vector3> getFieldGradient( + const Acts::Vector3& /*position*/, Acts::ActsMatrix<3, 3>& /*derivative*/, + MagneticFieldProvider::Cache& gCache) const override { + Cache& cache = gCache.as<Cache>(); + return Acts::Result<Acts::Vector3>::success(m_BField * cache.scalor); + } + + Acts::MagneticFieldProvider::Cache makeCache( + const Acts::MagneticFieldContext& mctx) const override { + return Acts::MagneticFieldProvider::Cache(std::in_place_type<Cache>, mctx); + } + + /// @brief check whether given 3D position is inside look-up domain + /// + /// @param [in] position global 3D position + /// @return @c true if position is inside the defined look-up grid, + /// otherwise @c false + /// @note The method will always return true for the constant B-Field + bool isInside(const Acts::Vector3& /*position*/) const { return true; } + + /// @brief update magnetic field vector from components + /// + /// @param [in] Bx magnetic field component in global x-direction + /// @param [in] By magnetic field component in global y-direction + /// @param [in] Bz magnetic field component in global z-direction + void setField(double Bx, double By, double Bz) { m_BField << Bx, By, Bz; } + + /// @brief update magnetic field vector + /// + /// @param [in] B magnetic field vector in global coordinate system + void setField(const Acts::Vector3& B) { m_BField = B; } + + private: + /// magnetic field vector + Acts::Vector3 m_BField; +}; // namespace BField + +} // namespace ActsHelper diff --git a/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Utilities/EventDataTransforms.hpp b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Utilities/EventDataTransforms.hpp new file mode 100644 index 00000000..8992d6ba --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Utilities/EventDataTransforms.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include "ActsHelper/EventData/ProtoTrack.hpp" +#include "ActsHelper/EventData/SimSeed.hpp" + +namespace ActsHelper { + +ProtoTrack seedToPrototrack(const SimSeed &seed); + +const SimSpacePoint *findSpacePointForIndex( + Index index, const SimSpacePointContainer &spacepoints); + +SimSeed prototrackToSeed(const ProtoTrack &track, + const SimSpacePointContainer &spacepoints); + +} // namespace ActsHelper diff --git a/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Utilities/GroupBy.hpp b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Utilities/GroupBy.hpp new file mode 100644 index 00000000..69adff0e --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Utilities/GroupBy.hpp @@ -0,0 +1,133 @@ +#pragma once + +#include "ActsHelper/Utilities/Range.hpp" + +#include <algorithm> +#include <iterator> +#include <utility> + +namespace ActsHelper { + +/// Proxy for iterating over groups of elements within a container. +/// +/// @note Each group will contain at least one element. +/// +/// Consecutive elements with the same key (as defined by the KeyGetter) are +/// placed in one group. The proxy should always be used as part of a +/// range-based for loop. In combination with structured bindings to reduce the +/// boilerplate, the group iteration can be written as +/// +/// for (auto&& [key, elements] : GroupBy<...>(...)) { +/// // do something with just the key +/// ... +/// +/// // iterate over the group elements +/// for (const auto& element : elements) { +/// ... +/// } +/// } +/// +template <typename Iterator, typename KeyGetter> +class GroupBy { + public: + /// The key type that identifies elements within a group. + using Key = std::decay_t<decltype(KeyGetter()(*Iterator()))>; + /// A Group is an iterator range with the associated key. + using Group = std::pair<Key, Range<Iterator>>; + /// Iterator type representing the end of the groups. + /// + /// The end iterator will not be dereferenced in C++17 range-based loops. It + /// can thus be a simpler type without the overhead of the full group iterator + /// below. + using GroupEndIterator = Iterator; + /// Iterator type representing a group of elements. + class GroupIterator { + public: + using iterator_category = std::input_iterator_tag; + using value_type = Group; + using difference_type = std::ptrdiff_t; + using pointer = Group*; + using reference = Group&; + + constexpr GroupIterator(const GroupBy& groupBy, Iterator groupBegin) + : m_groupBy(groupBy), + m_groupBegin(groupBegin), + m_groupEnd(groupBy.findEndOfGroup(groupBegin)) {} + /// Pre-increment operator to advance to the next group. + constexpr GroupIterator& operator++() { + // make the current end the new group beginning + std::swap(m_groupBegin, m_groupEnd); + // find the end of the next group starting from the new beginning + m_groupEnd = m_groupBy.findEndOfGroup(m_groupBegin); + return *this; + } + /// Post-increment operator to advance to the next group. + constexpr GroupIterator operator++(int) { + GroupIterator retval = *this; + ++(*this); + return retval; + } + /// Dereference operator that returns the pointed-to group of elements. + constexpr Group operator*() const { + const Key key = (m_groupBegin != m_groupEnd) + ? m_groupBy.m_keyGetter(*m_groupBegin) + : Key(); + return {key, makeRange(m_groupBegin, m_groupEnd)}; + } + + private: + const GroupBy& m_groupBy; + Iterator m_groupBegin; + Iterator m_groupEnd; + + friend constexpr bool operator==(const GroupIterator& lhs, + const GroupEndIterator& rhs) { + return lhs.m_groupBegin == rhs; + } + friend constexpr bool operator!=(const GroupIterator& lhs, + const GroupEndIterator& rhs) { + return !(lhs == rhs); + } + }; + + /// Construct the group-by proxy for an iterator range. + constexpr GroupBy(Iterator begin, Iterator end, + KeyGetter keyGetter = KeyGetter()) + : m_begin(begin), m_end(end), m_keyGetter(std::move(keyGetter)) {} + constexpr GroupIterator begin() const { + return GroupIterator(*this, m_begin); + } + constexpr GroupEndIterator end() const { return m_end; } + constexpr bool empty() const { return m_begin == m_end; } + + private: + Iterator m_begin; + Iterator m_end; + KeyGetter m_keyGetter; + + /// Find the end of the group that starts at the given position. + /// + /// This uses a linear search from the start position and thus has linear + /// complexity in the group size. It does not assume any ordering of the + /// underlying container and is a cache-friendly access pattern. + constexpr Iterator findEndOfGroup(Iterator start) const { + // check for end so we can safely dereference the start iterator. + if (start == m_end) { + return start; + } + // search the first element that does not share a key with the start. + return std::find_if_not(std::next(start), m_end, + [this, start](const auto& x) { + return m_keyGetter(x) == m_keyGetter(*start); + }); + } +}; + +/// Construct the group-by proxy for a container. +template <typename Container, typename KeyGetter> +auto makeGroupBy(const Container& container, KeyGetter keyGetter) + -> GroupBy<decltype(std::begin(container)), KeyGetter> { + return {std::begin(container), std::end(container), std::move(keyGetter)}; +} + +} // namespace ActsHelper diff --git a/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Utilities/Helpers.hpp b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Utilities/Helpers.hpp new file mode 100644 index 00000000..1f663483 --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Utilities/Helpers.hpp @@ -0,0 +1,138 @@ +#pragma once + +#include <string> +#include <utility> + +#include "TEfficiency.h" +#include "TFitResult.h" +#include "TFitResultPtr.h" +#include "TH1F.h" +#include "TH2F.h" +#include "TProfile.h" +#include "TROOT.h" + +class TEfficiency; +class TH1D; +class TH1F; +class TH2F; +class TProfile; + +namespace ActsHelper::PlotHelpers { +/// @brief Nested binning struct for booking plots +class Binning { + public: + Binning() : m_bins({0.0}) {} + + Binning(std::string title, int bins, double bMin, double bMax) + : m_title(std::move(title)) { + const auto step = (bMax - bMin) / bins; + m_bins.resize(bins + 1); + std::generate(m_bins.begin(), m_bins.end(), [&, v = bMin]() mutable { + auto r = v; + v += step; + return r; + }); + } + + Binning(std::string title, std::vector<double> bins) + : m_title(std::move(title)), m_bins(std::move(bins)) {} + + const auto& title() const { return m_title; } + auto nBins() const { return m_bins.size() - 1; } + const double* data() const { return m_bins.data(); } + auto low() const { return m_bins.front(); } + auto high() const { return m_bins.back(); } + + private: + std::string m_title; + std::vector<double> m_bins; +}; + +/// @brief book a 1D histogram +/// @param histName the name of histogram +/// @param histTitle the title of histogram +/// @param varBinning the binning info of variable +/// @return histogram pointer +TH1F* bookHisto(const char* histName, const char* histTitle, + const Binning& varBinning); + +/// @brief book a 2D histogram +/// @param histName the name of histogram +/// @param histTitle the title of histogram +/// @param varXBinning the binning info of variable at x axis +/// @param varYBinning the binning info of variable at y axis +/// @return histogram pointer +TH2F* bookHisto(const char* histName, const char* histTitle, + const Binning& varXBinning, const Binning& varYBinning); + +/// @brief fill a 1D histogram +/// @param hist histogram to fill +/// @param value value to fill +/// @param weight weight to fill +void fillHisto(TH1F* hist, float value, float weight = 1.0); + +/// @brief fill a 2D histogram +/// @param hist histogram to fill +/// @param xValue x value to fill +/// @param yValue y value to fill +/// @param weight weight to fill +void fillHisto(TH2F* hist, float xValue, float yValue, float weight = 1.0); + +/// @brief extract details, i.e. mean and width of a 1D histogram and fill +/// them into histograms +/// @param inputHist histogram to investigate +/// @param j which bin number of meanHist and widthHist to fill +/// @param meanHist histogram to fill the mean value of inputHist +/// @param widthHist histogram to fill the width value of inputHist +/// +/// @todo write specialized helper class to extract details of hists +void anaHisto(TH1D* inputHist, int j, TH1F* meanHist, TH1F* widthHist); + +/// @brief book a 1D efficiency plot +/// @param effName the name of plot +/// @param effTitle the title of plot +/// @param varBinning the binning info of variable +/// @return TEfficiency pointer +TEfficiency* bookEff(const char* effName, const char* effTitle, + const Binning& varBinning); + +/// @brief book a 2D efficiency plot +/// @param effName the name of plot +/// @param effTitle the title of plot +/// @param varXBinning the binning info of variable at x axis +/// @param varYBinning the binning info of variable at y axis +/// @return TEfficiency pointer +TEfficiency* bookEff(const char* effName, const char* effTitle, + const Binning& varXBinning, const Binning& varYBinning); + +/// @brief fill a 1D efficiency plot +/// @param efficiency plot to fill +/// @param value value to fill +/// @param status bool to denote passed or not +void fillEff(TEfficiency* efficiency, float value, bool status); + +/// @brief fill a 2D efficiency plot +/// @param efficiency plot to fill +/// @param xValue x value to fill +/// @param yValue y value to fill +/// @param status bool to denote passed or not +void fillEff(TEfficiency* efficiency, float xValue, float yValue, bool status); + +/// @brief book a TProfile plot +/// @param profName the name of plot +/// @param profTitle the title of plot +/// @param varXBinning the binning info of variable at x axis +/// @param varYBinning the binning info of variable at y axis +/// @return TProfile pointer +TProfile* bookProf(const char* profName, const char* profTitle, + const Binning& varXBinning, const Binning& varYBinning); + +/// @brief fill a TProfile plot +/// @param profile plot to fill +/// @param xValue xvalue to fill +/// @param yValue yvalue to fill +/// @param weight weight to fill +void fillProf(TProfile* profile, float xValue, float yValue, + float weight = 1.0); + +} // namespace ActsHelper::PlotHelpers diff --git a/Reconstruction/RecActsTracking/src/utils/Options.hpp b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Utilities/Options.hpp similarity index 98% rename from Reconstruction/RecActsTracking/src/utils/Options.hpp rename to Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Utilities/Options.hpp index 897233cb..4278d8d9 100644 --- a/Reconstruction/RecActsTracking/src/utils/Options.hpp +++ b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Utilities/Options.hpp @@ -1,10 +1,12 @@ +#pragma once + #include <array> #include <cstddef> #include <iosfwd> #include <optional> #include <vector> -namespace Options { +namespace ActsHelper::Options { /// @defgroup option-types Additional types for program options /// @@ -156,4 +158,4 @@ inline std::ostream& operator<<(std::ostream& os, return os; } -} // namespace Options +} // namespace ActsHelper::Options diff --git a/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Utilities/OptionsFwd.hpp b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Utilities/OptionsFwd.hpp new file mode 100644 index 00000000..6ae5c0d7 --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Utilities/OptionsFwd.hpp @@ -0,0 +1,11 @@ +#pragma once + +namespace boost::program_options { +class options_description; +class variables_map; +} // namespace boost::program_options + +namespace ActsHelper::Options { +using Description = ::boost::program_options::options_description; +using Variables = ::boost::program_options::variables_map; +} // namespace ActsHelper::Options diff --git a/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Utilities/Paths.hpp b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Utilities/Paths.hpp new file mode 100644 index 00000000..bff1713d --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Utilities/Paths.hpp @@ -0,0 +1,39 @@ +#pragma once + +#include <cstddef> +#include <string> +#include <utility> +#include <vector> + +namespace ActsHelper { + +/// Ensure that the given directory exists and is writable. +/// +/// @return Canonical path to the directory. +/// +/// Will create missing directories and throw on any error. +std::string ensureWritableDirectory(const std::string& dir); + +/// Join dir and name into one path with correct handling of empty dirs. +std::string joinPaths(const std::string& dir, const std::string& name); + +/// Construct a file path of the form `[<dir>/]event<XXXXXXXXX>-<name>`. +/// +/// @params dir output directory, current directory if empty +/// @params name basic filename +/// @params event event number +std::string perEventFilepath(const std::string& dir, const std::string& name, + std::size_t event); + +/// Determine the range of available events in a directory of per-event files. +/// +/// @params dir input directory, current directory if empty +/// @params name base filename +/// @return first and last+1 event number +/// @returns {0, 0} when no matching files could be found +/// +/// Event files must be named `[<dir>/]event<XXXXXXXXX>-<name>` to be considered +std::pair<std::size_t, std::size_t> determineEventFilesRange( + const std::string& dir, const std::string& name); + +} // namespace ActsHelper diff --git a/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Utilities/Range.hpp b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Utilities/Range.hpp new file mode 100644 index 00000000..72ad96f9 --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Utilities/Range.hpp @@ -0,0 +1,48 @@ +#pragma once + +#include <iterator> +#include <utility> + +namespace ActsHelper { + +/// A wrapper around a pair of iterators to simplify range-based loops. +/// +/// Some standard library algorithms return pairs of iterators to identify +/// a sub-range. This wrapper simplifies the iteration and should be used as +/// follows: +/// +/// for (auto x : makeRange(std::equal_range(...)) { +/// ... +/// } +/// +template <typename Iterator> +class Range { + public: + Range(Iterator b, Iterator e) : m_begin(b), m_end(e) {} + Range(Range&&) = default; + Range(const Range&) = default; + ~Range() = default; + Range& operator=(Range&&) = default; + Range& operator=(const Range&) = default; + + Iterator begin() const { return m_begin; } + Iterator end() const { return m_end; } + bool empty() const { return m_begin == m_end; } + std::size_t size() const { return std::distance(m_begin, m_end); } + + private: + Iterator m_begin; + Iterator m_end; +}; + +template <typename Iterator> +Range<Iterator> makeRange(Iterator begin, Iterator end) { + return Range<Iterator>(begin, end); +} + +template <typename Iterator> +Range<Iterator> makeRange(std::pair<Iterator, Iterator> range) { + return Range<Iterator>(range.first, range.second); +} + +} // namespace ActsHelper diff --git a/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Utilities/tbbWrap.hpp b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Utilities/tbbWrap.hpp new file mode 100644 index 00000000..57e98585 --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Utilities/tbbWrap.hpp @@ -0,0 +1,166 @@ +#pragma once + +// uncomment to remove all use of tbb library. +// #define ACTS_EXAMPLES_NO_TBB + +#ifdef ACTS_EXAMPLES_NO_TBB +#define ACTS_EXAMPLES_WITH_TBB(a) +#include <stdexcept> +#else +#define ACTS_EXAMPLES_WITH_TBB(a) a +#include <optional> + +#include <tbb/parallel_for.h> +#include <tbb/queuing_mutex.h> +#include <tbb/task_arena.h> +#endif + +/// Wrapper for most of the tbb functions that we use in Sequencer. +/// +/// It disables the use of tbb if nthreads=1. +/// Note that only a small subset of tbb functions are implemented, and +/// tbb::blocked_range (which doesn't require any thread setup) is still taken +/// from the tbb library. +/// +/// However, if ACTS_EXAMPLES_NO_TBB is defined, then don't use tbb library at +/// all (requires nthreads=1 or -1). This allows the ACTS Examples to be built +/// without the tbb library (and reduces the dependency on ROOT). +/// In this case, we provide our own minimal implementation of +/// tbb::blocked_range. +/// +/// Based on an idea from +/// https://stackoverflow.com/questions/59736661/how-to-completely-switch-off-threading-in-tbb-code + +#ifdef ACTS_EXAMPLES_NO_TBB +namespace ActsHelper::tbb { +namespace task_arena { +constexpr int automatic = -1; +} // namespace task_arena + +template <typename Value> +struct blocked_range { + blocked_range(Value begin_, Value end_) : my_end(end_), my_begin(begin_) {} + Value begin() const { return my_begin; } + Value end() const { return my_end; } + + private: + Value my_end; + Value my_begin; +}; +} // namespace ActsHelper::tbb +#endif + +namespace ActsHelper::tbbWrap { +/// enableTBB keeps a record of whether we are multi-threaded (nthreads!=1) or +/// not. This is set once in task_arena and stored globally. +/// This means that enableTBB(nthreads) itself is not thread-safe. That should +/// be fine because the task_arena is initialised before spawning any threads. +/// If multi-threading is ever enabled, then it is not disabled. +static bool enableTBB(int nthreads = -99) { + static bool setting = false; + if (nthreads != -99) { +#ifdef ACTS_EXAMPLES_NO_TBB + if (nthreads > 1) { + throw std::runtime_error( + "tbb is not available, so can't do multi-threading."); + } +#else + bool newSetting = (nthreads != 1); + if (!setting && newSetting) { + setting = newSetting; + } +#endif + } + return setting; +} + +/// Small wrapper for tbb::task_arena. +/// Note that the tbbWrap::task_arena constructor is not thread-safe. +/// That should be fine because the task_arena is initialised before spawning +/// any threads. +class task_arena { +#ifndef ACTS_EXAMPLES_NO_TBB + std::optional<tbb::task_arena> tbb; +#endif + + public: + task_arena(int nthreads = tbb::task_arena::automatic, + unsigned ACTS_EXAMPLES_WITH_TBB(res) = 1) { + if (enableTBB(nthreads)) { +#ifndef ACTS_EXAMPLES_NO_TBB + tbb.emplace(nthreads, res); +#endif + } + } + + template <typename F> + void execute(const F& f) { +#ifndef ACTS_EXAMPLES_NO_TBB + if (tbb) { + tbb->execute(f); + } else +#endif + { + f(); + } + } +}; + +/// Small wrapper for tbb::parallel_for. +class parallel_for { + public: + template <typename R, typename F> + parallel_for(const R& r, const F& f) { +#ifndef ACTS_EXAMPLES_NO_TBB + if (enableTBB()) { + tbb::parallel_for(r, f); + } else +#endif + { + for (auto i = r.begin(); i != r.end(); ++i) { // use default grainsize=1 + f(R(i, i + 1)); + } + } + } +}; + +/// Small wrapper for tbb::queuing_mutex and tbb::queuing_mutex::scoped_lock. +class queuing_mutex { +#ifndef ACTS_EXAMPLES_NO_TBB + std::optional<tbb::queuing_mutex> tbb; +#endif + + public: + queuing_mutex() { +#ifndef ACTS_EXAMPLES_NO_TBB + if (enableTBB()) { + tbb.emplace(); + } +#endif + } + + class scoped_lock { +#ifndef ACTS_EXAMPLES_NO_TBB + std::optional<tbb::queuing_mutex::scoped_lock> tbb; +#endif + + public: + scoped_lock() { +#ifndef ACTS_EXAMPLES_NO_TBB + if (enableTBB()) { + tbb.emplace(); + } +#endif + } + + scoped_lock(queuing_mutex& ACTS_EXAMPLES_WITH_TBB(m)) { +#ifndef ACTS_EXAMPLES_NO_TBB + if (enableTBB()) { + tbb.emplace(*m.tbb); + } +#endif + } + }; +}; + +} // namespace ActsHelper::tbbWrap diff --git a/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Validation/DuplicationPlotTool.hpp b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Validation/DuplicationPlotTool.hpp new file mode 100644 index 00000000..d5655b74 --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Validation/DuplicationPlotTool.hpp @@ -0,0 +1,96 @@ +#pragma once + +#include "Acts/EventData/TrackParameters.hpp" +#include "Acts/Utilities/Logger.hpp" +#include "ActsHelper/Utilities/Helpers.hpp" +#include "ActsFatras/EventData/Particle.hpp" + +#include <cstddef> +#include <map> +#include <memory> +#include <string> + +class TEfficiency; +class TProfile; +namespace ActsFatras { +class Particle; +} // namespace ActsFatras + +namespace ActsHelper { + +// Tools to make duplication rate and duplication number plots to show tracking +// duplication. +// +// The duplication is investigated for those truth-matched reco tracks. If there +// are a few reco tracks matched to the same truth particle, the reco track with +// the highest matching probability is tagges as 'real' and the others are +// 'duplicated'. +class DuplicationPlotTool { + public: + /// @brief The nested configuration struct + struct Config { + std::map<std::string, PlotHelpers::Binning> varBinning = { + {"Eta", PlotHelpers::Binning("#eta", 40, -4, 4)}, + {"Phi", PlotHelpers::Binning("#phi", 100, -3.15, 3.15)}, + {"Pt", PlotHelpers::Binning("pT [GeV/c]", 40, 0, 100)}, + {"Num", PlotHelpers::Binning("N", 30, -0.5, 29.5)}}; + }; + + /// @brief Nested Cache struct + struct DuplicationPlotCache { + TProfile* nDuplicated_vs_pT; ///< Number of duplicated tracks vs pT + TProfile* nDuplicated_vs_eta; ///< Number of duplicated tracks vs eta + TProfile* nDuplicated_vs_phi; ///< Number of duplicated tracks vs phi + TEfficiency* duplicationRate_vs_pT; ///< Tracking duplication rate vs pT + TEfficiency* duplicationRate_vs_eta; ///< Tracking duplication rate vs eta + TEfficiency* duplicationRate_vs_phi; ///< Tracking duplication rate vs phi + }; + + /// Constructor + /// + /// @param cfg Configuration struct + /// @param lvl Message level declaration + DuplicationPlotTool(const Config& cfg, Acts::Logging::Level lvl); + + /// @brief book the duplication plots + /// + /// @param duplicationPlotCache the cache for duplication plots + void book(DuplicationPlotCache& duplicationPlotCache) const; + + /// @brief fill duplication rate w.r.t. fitted track parameters + /// + /// @param duplicationPlotCache cache object for duplication plots + /// @param fittedParameters fitted track parameters of this track + /// @param status the (truth-matched) reconstructed track is duplicated or not + void fill(DuplicationPlotCache& duplicationPlotCache, + const Acts::BoundTrackParameters& fittedParameters, + bool status) const; + + /// @brief fill number of duplicated tracks for a truth particle seed + /// + /// @param duplicationPlotCache cache object for duplication plots + /// @param truthParticle the truth Particle + /// @param nDuplicatedTracks the number of duplicated tracks + void fill(DuplicationPlotCache& duplicationPlotCache, + const ActsFatras::Particle& truthParticle, + std::size_t nDuplicatedTracks) const; + + /// @brief write the duplication plots to file + /// + /// @param duplicationPlotCache cache object for duplication plots + void write(const DuplicationPlotCache& duplicationPlotCache) const; + + /// @brief delete the duplication plots + /// + /// @param duplicationPlotCache cache object for duplication plots + void clear(DuplicationPlotCache& duplicationPlotCache) const; + + private: + Config m_cfg; ///< The Config class + std::unique_ptr<const Acts::Logger> m_logger; ///< The logging instance + + /// The logger + const Acts::Logger& logger() const { return *m_logger; } +}; + +} // namespace ActsHelper diff --git a/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Validation/EffPlotTool.hpp b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Validation/EffPlotTool.hpp new file mode 100644 index 00000000..47185540 --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Validation/EffPlotTool.hpp @@ -0,0 +1,81 @@ +#pragma once + +#include "Acts/Utilities/Logger.hpp" +#include "ActsHelper/Utilities/Helpers.hpp" +#include "ActsFatras/EventData/Particle.hpp" + +#include <map> +#include <memory> +#include <string> + +class TEfficiency; +namespace ActsFatras { +class Particle; +} // namespace ActsFatras + +namespace ActsHelper { + +// Tools to make efficiency plots to show tracking efficiency. +// For the moment, the efficiency is taken as the fraction of successfully +// smoothed track over all tracks +class EffPlotTool { + public: + /// @brief The nested configuration struct + struct Config { + std::map<std::string, PlotHelpers::Binning> varBinning = { + {"Eta", PlotHelpers::Binning("#eta", 40, -4, 4)}, + {"Phi", PlotHelpers::Binning("#phi", 100, -3.15, 3.15)}, + {"Pt", PlotHelpers::Binning("pT [GeV/c]", 40, 0, 100)}, + {"DeltaR", PlotHelpers::Binning("#Delta R", 100, 0, 0.3)}}; + }; + + /// @brief Nested Cache struct + struct EffPlotCache { + TEfficiency* trackEff_vs_pT{nullptr}; ///< Tracking efficiency vs pT + TEfficiency* trackEff_vs_eta{nullptr}; ///< Tracking efficiency vs eta + TEfficiency* trackEff_vs_phi{nullptr}; ///< Tracking efficiency vs phi + TEfficiency* trackEff_vs_DeltaR{ + nullptr}; ///< Tracking efficiency vs distance to the closest truth + ///< particle + }; + + /// Constructor + /// + /// @param cfg Configuration struct + /// @param lvl Message level declaration + EffPlotTool(const Config& cfg, Acts::Logging::Level lvl); + + /// @brief book the efficiency plots + /// + /// @param effPlotCache the cache for efficiency plots + void book(EffPlotCache& effPlotCache) const; + + /// @brief fill efficiency plots + /// + /// @param effPlotCache cache object for efficiency plots + /// @param truthParticle the truth Particle + /// @param deltaR the distance to the closest truth particle + /// @param status the reconstruction status + void fill(EffPlotCache& effPlotCache, + const ActsFatras::Particle& truthParticle, double deltaR, + bool status) const; + + /// @brief write the efficiency plots to file + /// + /// @param effPlotCache cache object for efficiency plots + void write(const EffPlotCache& effPlotCache) const; + + /// @brief delete the efficiency plots + /// + /// @param effPlotCache cache object for efficiency plots + void clear(EffPlotCache& effPlotCache) const; + + private: + Config m_cfg; ///< The Config class + std::unique_ptr<const Acts::Logger> m_logger; ///< The logging instance + + /// The logger + const Acts::Logger& logger() const { return *m_logger; } +}; + +} // namespace ActsHelper diff --git a/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Validation/FakeRatePlotTool.hpp b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Validation/FakeRatePlotTool.hpp new file mode 100644 index 00000000..b5a27aba --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Validation/FakeRatePlotTool.hpp @@ -0,0 +1,102 @@ +#pragma once + +#include "Acts/EventData/TrackParameters.hpp" +#include "Acts/Utilities/Logger.hpp" +#include "ActsHelper/Utilities/Helpers.hpp" +#include "ActsFatras/EventData/Particle.hpp" + +#include <cstddef> +#include <map> +#include <memory> +#include <string> + +class TEfficiency; +class TH2F; +namespace ActsFatras { +class Particle; +} // namespace ActsFatras + +namespace ActsHelper { + +// Tools to make fake rate plots to show tracking fake rate. +// +// The fake rate is investigated for all reco tracks. A track is 'fake' if it's +// not matched with truth. +class FakeRatePlotTool { + public: + /// @brief The nested configuration struct + struct Config { + std::map<std::string, PlotHelpers::Binning> varBinning = { + {"Eta", PlotHelpers::Binning("#eta", 40, -4, 4)}, + {"Phi", PlotHelpers::Binning("#phi", 100, -3.15, 3.15)}, + {"Pt", PlotHelpers::Binning("pT [GeV/c]", 40, 0, 100)}, + {"Num", PlotHelpers::Binning("N", 30, -0.5, 29.5)}}; + }; + + /// @brief Nested Cache struct + struct FakeRatePlotCache { + TH2F* nReco_vs_pT; ///< Number of reco tracks vs pT scatter plot + TH2F* nTruthMatched_vs_pT; ///< Number of truth-matched reco tracks vs pT + ///< scatter plot + TH2F* nFake_vs_pT; ///< Number of fake (truth-unmatched) tracks vs pT + ///< scatter plot + TH2F* nReco_vs_eta; ///< Number of reco tracks vs eta scatter plot + TH2F* nTruthMatched_vs_eta; ///< Number of truth-matched reco tracks vs eta + ///< scatter plot + TH2F* nFake_vs_eta; ///< Number of fake (truth-unmatched) tracks vs eta + ///< scatter plot + TEfficiency* fakeRate_vs_pT; ///< Tracking fake rate vs pT + TEfficiency* fakeRate_vs_eta; ///< Tracking fake rate vs eta + TEfficiency* fakeRate_vs_phi; ///< Tracking fake rate vs phi + }; + + /// Constructor + /// + /// @param cfg Configuration struct + /// @param lvl Message level declaration + FakeRatePlotTool(const Config& cfg, Acts::Logging::Level lvl); + + /// @brief book the fake rate plots + /// + /// @param fakeRatePlotCache the cache for fake rate plots + void book(FakeRatePlotCache& fakeRatePlotCache) const; + + /// @brief fill fake rate w.r.t. fitted track parameters + /// + /// @param fakeRatePlotCache cache object for fake rate plots + /// @param fittedParameters fitted track parameters of this track + /// @param status the reconstructed track is fake or not + void fill(FakeRatePlotCache& fakeRatePlotCache, + const Acts::BoundTrackParameters& fittedParameters, + bool status) const; + + /// @brief fill number of reco/truth-matched/fake tracks for a truth particle + /// seed + /// + /// @param fakeRatePlotCache cache object for fake rate plots + /// @param truthParticle the truth Particle + /// @param nTruthMatchedTracks the number of truth-Matched tracks + /// @param nFakeTracks the number of fake tracks + void fill(FakeRatePlotCache& fakeRatePlotCache, + const ActsFatras::Particle& truthParticle, + std::size_t nTruthMatchedTracks, std::size_t nFakeTracks) const; + + /// @brief write the fake rate plots to file + /// + /// @param fakeRatePlotCache cache object for fake rate plots + void write(const FakeRatePlotCache& fakeRatePlotCache) const; + + /// @brief delete the fake rate plots + /// + /// @param fakeRatePlotCache cache object for fake rate plots + void clear(FakeRatePlotCache& fakeRatePlotCache) const; + + private: + Config m_cfg; ///< The Config class + std::unique_ptr<const Acts::Logger> m_logger; ///< The logging instance + + /// The logger + const Acts::Logger& logger() const { return *m_logger; } +}; + +} // namespace ActsHelper diff --git a/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Validation/ResPlotTool.hpp b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Validation/ResPlotTool.hpp new file mode 100644 index 00000000..8ef6e85a --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Validation/ResPlotTool.hpp @@ -0,0 +1,122 @@ +#pragma once + +#include "Acts/EventData/TrackParameters.hpp" +#include "Acts/Geometry/GeometryContext.hpp" +#include "Acts/Utilities/Logger.hpp" +#include "ActsHelper/Utilities/Helpers.hpp" +#include "ActsFatras/EventData/Particle.hpp" + +#include <map> +#include <memory> +#include <string> +#include <vector> + +class TH1F; +class TH2F; +namespace ActsFatras { +class Particle; +} // namespace ActsFatras + +namespace ActsHelper { + +// Tools to make hists to show residual, i.e. smoothed_parameter - +// truth_parameter, and pull, i.e. (smoothed_parameter - +// truth_parameter)/smoothed_paramter_error, of track parameters at perigee +// surface +class ResPlotTool { + public: + /// @brief Nested configuration struct + struct Config { + /// parameter sets to do plots + std::vector<std::string> paramNames = {"d0", "z0", "phi", + "theta", "qop", "t"}; + + /// Binning info for variables + std::map<std::string, PlotHelpers::Binning> varBinning = { + {"Eta", PlotHelpers::Binning("#eta", 40, -4, 4)}, + {"Pt", PlotHelpers::Binning("pT [GeV/c]", 40, 0, 100)}, + {"Pull", PlotHelpers::Binning("pull", 100, -5, 5)}, + {"Residual_d0", PlotHelpers::Binning("r_{d0} [mm]", 100, -0.5, 0.5)}, + {"Residual_z0", PlotHelpers::Binning("r_{z0} [mm]", 100, -0.5, 0.5)}, + {"Residual_phi", + PlotHelpers::Binning("r_{#phi} [rad]", 100, -0.01, 0.01)}, + {"Residual_theta", + PlotHelpers::Binning("r_{#theta} [rad]", 100, -0.01, 0.01)}, + {"Residual_qop", + PlotHelpers::Binning("r_{q/p} [c/GeV]", 100, -0.1, 0.1)}, + {"Residual_t", PlotHelpers::Binning("r_{t} [s]", 100, -1000, 1000)}}; + }; + + /// @brief Nested Cache struct + struct ResPlotCache { + std::map<std::string, TH1F*> res; ///< Residual distribution + std::map<std::string, TH2F*> res_vs_eta; ///< Residual vs eta scatter plot + std::map<std::string, TH1F*> + resMean_vs_eta; ///< Residual mean vs eta distribution + std::map<std::string, TH1F*> + resWidth_vs_eta; ///< Residual width vs eta distribution + std::map<std::string, TH2F*> res_vs_pT; ///< Residual vs pT scatter plot + std::map<std::string, TH1F*> + resMean_vs_pT; ///< Residual mean vs pT distribution + std::map<std::string, TH1F*> + resWidth_vs_pT; ///< Residual width vs pT distribution + + std::map<std::string, TH1F*> pull; ///< Pull distribution + std::map<std::string, TH2F*> pull_vs_eta; ///< Pull vs eta scatter plot + std::map<std::string, TH1F*> + pullMean_vs_eta; ///< Pull mean vs eta distribution + std::map<std::string, TH1F*> + pullWidth_vs_eta; ///< Pull width vs eta distribution + std::map<std::string, TH2F*> pull_vs_pT; ///< Pull vs pT scatter plot + std::map<std::string, TH1F*> + pullMean_vs_pT; ///< Pull mean vs pT distribution + std::map<std::string, TH1F*> + pullWidth_vs_pT; ///< Pull width vs pT distribution + }; + + /// Constructor + /// + /// @param cfg Configuration struct + /// @param level Message level declaration + ResPlotTool(const Config& cfg, Acts::Logging::Level lvl); + + /// @brief book the histograms + /// + /// @param resPlotCache the cache for residual/pull histograms + void book(ResPlotCache& resPlotCache) const; + + /// @brief fill the histograms + /// + /// @param resPlotCache the cache for residual/pull histograms + /// @param gctx the geometry context + /// @param truthParticle the truth particle + /// @param fittedParamters the fitted parameters at perigee surface + void fill(ResPlotCache& resPlotCache, const Acts::GeometryContext& gctx, + const ActsFatras::Particle& truthParticle, + const Acts::BoundTrackParameters& fittedParamters) const; + + /// @brief extract the details of the residual/pull plots and fill details + /// + /// into separate histograms + /// @param resPlotCache the cache object for residual/pull histograms + void refinement(ResPlotCache& resPlotCache) const; + + /// @brief write the histograms to output file + /// + /// @param resPlotCache the cache object for residual/pull histograms + void write(const ResPlotCache& resPlotCache) const; + + /// @brief delete the histograms + /// + /// @param resPlotCache the cache object for residual/pull histograms + void clear(ResPlotCache& resPlotCache) const; + + private: + Config m_cfg; ///< The config class + std::unique_ptr<const Acts::Logger> m_logger; ///< The logging instance + + /// The logger + const Acts::Logger& logger() const { return *m_logger; } +}; + +} // namespace ActsHelper diff --git a/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Validation/TrackClassification.hpp b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Validation/TrackClassification.hpp new file mode 100644 index 00000000..a1ad8daf --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Validation/TrackClassification.hpp @@ -0,0 +1,57 @@ +#pragma once + +#include "ActsHelper/EventData/Index.hpp" +#include "ActsHelper/EventData/ProtoTrack.hpp" +#include "ActsHelper/EventData/Trajectories.hpp" +#include "ActsFatras/EventData/Barcode.hpp" + +#include <cstddef> +#include <utility> +#include <vector> + +namespace ActsHelper { +struct Trajectories; + +/// Associate a particle to its hit count within a proto track. +struct ParticleHitCount { + ActsFatras::Barcode particleId; + std::size_t hitCount; +}; + +/// Identify all particles that contribute to the proto track. +/// +/// @param[in] hitParticlesMap Map hit indices to contributing particles +/// @param[in] protoTrack The proto track to classify +/// @param[out] particleHitCounts List of contributing particles +/// +/// The list of contributing particles is ordered according to their hit count, +/// i.e. the first element is the majority particle that contributes the most +/// hits to the track. There can be both hits without a generating particle +/// (noise hits) and hits that have more than one generating particle. The sum +/// of the particle hit count must not be identical to the size of the proto +/// track. +void identifyContributingParticles( + const IndexMultimap<ActsFatras::Barcode>& hitParticlesMap, + const ProtoTrack& protoTrack, + std::vector<ParticleHitCount>& particleHitCounts); + +/// Identify all particles that contribute to a trajectory. +/// +/// @param[in] hitParticlesMap Map hit indices to contributing particles +/// @param[in] trajectories The input trajectories to classify +/// @param[in] trajectoryTip Which trajectory in the trajectories to use +/// @param[out] particleHitCounts List of contributing particles +/// +/// See `identifyContributingParticles` for proto tracks for further +/// information. +void identifyContributingParticles( + const IndexMultimap<ActsFatras::Barcode>& hitParticlesMap, + const Trajectories& trajectories, std::size_t trajectoryTip, + std::vector<ParticleHitCount>& particleHitCounts); + +void identifyContributingParticles( + const IndexMultimap<ActsFatras::Barcode>& hitParticlesMap, + const ConstTrackContainer::ConstTrackProxy& track, + std::vector<ParticleHitCount>& particleHitCounts); + +} // namespace ActsHelper diff --git a/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Validation/TrackSummaryPlotTool.hpp b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Validation/TrackSummaryPlotTool.hpp new file mode 100644 index 00000000..e76a7d56 --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/include/ActsHelper/Validation/TrackSummaryPlotTool.hpp @@ -0,0 +1,88 @@ +#pragma once + +#include "Acts/EventData/TrackParameters.hpp" +#include "Acts/Utilities/Logger.hpp" +#include "ActsHelper/Utilities/Helpers.hpp" +#include "ActsFatras/EventData/Particle.hpp" + +#include <cstddef> +#include <map> +#include <memory> +#include <string> + +class TProfile; + +namespace ActsHelper { + +// Tools to make track info plots to show tracking track info. +class TrackSummaryPlotTool { + public: + /// @brief The nested configuration struct + struct Config { + std::map<std::string, PlotHelpers::Binning> varBinning = { + {"Eta", PlotHelpers::Binning("#eta", 40, -4, 4)}, + {"Phi", PlotHelpers::Binning("#phi", 100, -3.15, 3.15)}, + {"Pt", PlotHelpers::Binning("pT [GeV/c]", 40, 0, 100)}, + {"Num", PlotHelpers::Binning("N", 30, -0.5, 29.5)}}; + }; + + /// @brief Nested Cache struct + struct TrackSummaryPlotCache { + TProfile* nStates_vs_eta; ///< Number of total states vs eta + TProfile* + nMeasurements_vs_eta; ///< Number of non-outlier measurements vs eta + TProfile* nHoles_vs_eta; ///< Number of holes vs eta + TProfile* nOutliers_vs_eta; ///< Number of outliers vs eta + TProfile* nSharedHits_vs_eta; ///< Number of Shared Hits vs eta + TProfile* nStates_vs_pt; ///< Number of total states vs pt + TProfile* + nMeasurements_vs_pt; ///< Number of non-outlier measurements vs pt + TProfile* nHoles_vs_pt; ///< Number of holes vs pt + TProfile* nOutliers_vs_pt; ///< Number of outliers vs pt + TProfile* nSharedHits_vs_pt; ///< Number of Shared Hits vs pt + }; + + /// Constructor + /// + /// @param cfg Configuration struct + /// @param lvl Message level declaration + TrackSummaryPlotTool(const Config& cfg, Acts::Logging::Level lvl); + + /// @brief book the track info plots + /// + /// @param trackSummaryPlotCache the cache for track info plots + void book(TrackSummaryPlotCache& trackSummaryPlotCache) const; + + /// @brief fill reco track info w.r.t. fitted track parameters + /// + /// @param trackSummaryPlotCache cache object for track info plots + /// @param fittedParameters fitted track parameters of this track + /// @param nStates number of track states + /// @param nMeasurements number of measurements + /// @param nOutliers number of outliers + /// @param nHoles number of holes + void fill(TrackSummaryPlotCache& trackSummaryPlotCache, + const Acts::BoundTrackParameters& fittedParameters, + std::size_t nStates, std::size_t nMeasurements, + std::size_t Outliers, std::size_t nHoles, + std::size_t nSharedHits) const; + + /// @brief write the track info plots to file + /// + /// @param trackSummaryPlotCache cache object for track info plots + void write(const TrackSummaryPlotCache& trackSummaryPlotCache) const; + + /// @brief delete the track info plots + /// + /// @param trackSummaryPlotCache cache object for track info plots + void clear(TrackSummaryPlotCache& trackSummaryPlotCache) const; + + private: + Config m_cfg; ///< The Config class + std::unique_ptr<const Acts::Logger> m_logger; ///< The logging instance + + /// The logger + const Acts::Logger& logger() const { return *m_logger; } +}; + +} // namespace ActsHelper diff --git a/Reconstruction/RecActsTracking/ActsHelper/src/Algorithms/TrackFitting/GlobalChiSquareFitterFunction.cpp b/Reconstruction/RecActsTracking/ActsHelper/src/Algorithms/TrackFitting/GlobalChiSquareFitterFunction.cpp new file mode 100644 index 00000000..64c3bfbc --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/src/Algorithms/TrackFitting/GlobalChiSquareFitterFunction.cpp @@ -0,0 +1,157 @@ +#include "Acts/Definitions/Direction.hpp" +#include "Acts/Definitions/TrackParametrization.hpp" +#include "Acts/EventData/MultiTrajectory.hpp" +#include "Acts/EventData/TrackContainer.hpp" +#include "Acts/EventData/TrackStatePropMask.hpp" +#include "Acts/EventData/VectorMultiTrajectory.hpp" +#include "Acts/EventData/VectorTrackContainer.hpp" +#include "Acts/EventData/detail/CorrectedTransformationFreeToBound.hpp" +#include "Acts/Geometry/GeometryIdentifier.hpp" +#include "Acts/Propagator/DirectNavigator.hpp" +#include "Acts/Propagator/EigenStepper.hpp" +#include "Acts/Propagator/Navigator.hpp" +#include "Acts/Propagator/Propagator.hpp" +#include "Acts/TrackFitting/GlobalChiSquareFitter.hpp" +#include "Acts/TrackFitting/KalmanFitter.hpp" +#include "Acts/Utilities/Delegate.hpp" +#include "Acts/Utilities/Logger.hpp" +#include "ActsHelper/EventData/IndexSourceLink.hpp" +#include "ActsHelper/EventData/MeasurementCalibration.hpp" +#include "ActsHelper/EventData/Track.hpp" +#include "ActsHelper/Algorithms/TrackFitting/RefittingCalibrator.hpp" +#include "ActsHelper/Algorithms/TrackFitting/TrackFitterFunction.hpp" + +#include <algorithm> +#include <cmath> +#include <functional> +#include <memory> +#include <utility> +#include <vector> + +namespace Acts { +class MagneticFieldProvider; +class SourceLink; +class Surface; +class TrackingGeometry; +} // namespace Acts + +namespace { + +using Stepper = Acts::EigenStepper<>; +using Propagator = Acts::Propagator<Stepper, Acts::Navigator>; +using Fitter = + Acts::Experimental::Gx2Fitter<Propagator, Acts::VectorMultiTrajectory>; +using DirectPropagator = Acts::Propagator<Stepper, Acts::DirectNavigator>; +using DirectFitter = + Acts::KalmanFitter<DirectPropagator, Acts::VectorMultiTrajectory>; + +using TrackContainer = + Acts::TrackContainer<Acts::VectorTrackContainer, + Acts::VectorMultiTrajectory, std::shared_ptr>; + +using namespace ActsHelper; + +struct GlobalChiSquareFitterFunctionImpl final : public TrackFitterFunction { + Fitter fitter; + DirectFitter directFitter; + + bool multipleScattering = false; + bool energyLoss = false; + Acts::FreeToBoundCorrection freeToBoundCorrection; + std::size_t nUpdateMax = 5; + double relChi2changeCutOff = 1e-7; + + IndexSourceLink::SurfaceAccessor m_slSurfaceAccessor; + + GlobalChiSquareFitterFunctionImpl(Fitter&& f, DirectFitter&& df, + const Acts::TrackingGeometry& trkGeo) + : fitter(std::move(f)), + directFitter(std::move(df)), + m_slSurfaceAccessor{trkGeo} {} + + template <typename calibrator_t> + auto makeGx2fOptions(const GeneralFitterOptions& options, + const calibrator_t& calibrator) const { + Acts::Experimental::Gx2FitterExtensions<Acts::VectorMultiTrajectory> + extensions; + extensions.calibrator.connect<&calibrator_t::calibrate>(&calibrator); + + extensions.surfaceAccessor + .connect<&IndexSourceLink::SurfaceAccessor::operator()>( + &m_slSurfaceAccessor); + + const Acts::Experimental::Gx2FitterOptions gx2fOptions( + options.geoContext, options.magFieldContext, options.calibrationContext, + extensions, options.propOptions, &(*options.referenceSurface), + multipleScattering, energyLoss, freeToBoundCorrection, nUpdateMax, + relChi2changeCutOff); + + return gx2fOptions; + } + + TrackFitterResult operator()(const std::vector<Acts::SourceLink>& sourceLinks, + const TrackParameters& initialParameters, + const GeneralFitterOptions& options, + const MeasurementCalibratorAdapter& calibrator, + TrackContainer& tracks) const override { + const auto gx2fOptions = makeGx2fOptions(options, calibrator); + return fitter.fit(sourceLinks.begin(), sourceLinks.end(), initialParameters, + gx2fOptions, tracks); + } + + // We need a placeholder for the directNavigator overload. Otherwise, we would + // have an unimplemented pure virtual method in a final class. + TrackFitterResult operator()( + const std::vector<Acts::SourceLink>& /*sourceLinks*/, + const TrackParameters& /*initialParameters*/, + const GeneralFitterOptions& /*options*/, + const RefittingCalibrator& /*calibrator*/, + const std::vector<const Acts::Surface*>& /*surfaceSequence*/, + TrackContainer& /*tracks*/) const override { + throw std::runtime_error( + "direct navigation with GX2 fitter is not implemented"); + } +}; + +} // namespace + +std::shared_ptr<ActsHelper::TrackFitterFunction> +ActsHelper::makeGlobalChiSquareFitterFunction( + std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry, + std::shared_ptr<const Acts::MagneticFieldProvider> magneticField, + bool multipleScattering, bool energyLoss, + Acts::FreeToBoundCorrection freeToBoundCorrection, std::size_t nUpdateMax, + double relChi2changeCutOff, const Acts::Logger& logger) { + // Stepper should be copied into the fitters + const Stepper stepper(std::move(magneticField)); + + // Standard fitter + const auto& geo = *trackingGeometry; + Acts::Navigator::Config cfg{std::move(trackingGeometry)}; + cfg.resolvePassive = false; + cfg.resolveMaterial = true; + cfg.resolveSensitive = true; + Acts::Navigator navigator(cfg, logger.cloneWithSuffix("Navigator")); + Propagator propagator(stepper, std::move(navigator), + logger.cloneWithSuffix("Propagator")); + Fitter trackFitter(std::move(propagator), logger.cloneWithSuffix("Fitter")); + + // Direct fitter + Acts::DirectNavigator directNavigator{ + logger.cloneWithSuffix("DirectNavigator")}; + DirectPropagator directPropagator(stepper, std::move(directNavigator), + logger.cloneWithSuffix("DirectPropagator")); + DirectFitter directTrackFitter(std::move(directPropagator), + logger.cloneWithSuffix("DirectFitter")); + + // build the fitter function. owns the fitter object. + auto fitterFunction = std::make_shared<GlobalChiSquareFitterFunctionImpl>( + std::move(trackFitter), std::move(directTrackFitter), geo); + fitterFunction->multipleScattering = multipleScattering; + fitterFunction->energyLoss = energyLoss; + fitterFunction->freeToBoundCorrection = freeToBoundCorrection; + fitterFunction->nUpdateMax = nUpdateMax; + fitterFunction->relChi2changeCutOff = relChi2changeCutOff; + + return fitterFunction; +} diff --git a/Reconstruction/RecActsTracking/ActsHelper/src/Algorithms/TrackFitting/GsfFitterFunction.cpp b/Reconstruction/RecActsTracking/ActsHelper/src/Algorithms/TrackFitting/GsfFitterFunction.cpp new file mode 100644 index 00000000..e6a13d44 --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/src/Algorithms/TrackFitting/GsfFitterFunction.cpp @@ -0,0 +1,220 @@ +#include "Acts/Definitions/Common.hpp" +#include "Acts/Definitions/Direction.hpp" +#include "Acts/EventData/MultiTrajectory.hpp" +#include "Acts/EventData/TrackContainer.hpp" +#include "Acts/EventData/TrackParameters.hpp" +#include "Acts/EventData/TrackStatePropMask.hpp" +#include "Acts/EventData/VectorMultiTrajectory.hpp" +#include "Acts/EventData/VectorTrackContainer.hpp" +#include "Acts/Geometry/GeometryIdentifier.hpp" +#include "Acts/Propagator/DirectNavigator.hpp" +#include "Acts/Propagator/MultiEigenStepperLoop.hpp" +#include "Acts/Propagator/Navigator.hpp" +#include "Acts/Propagator/Propagator.hpp" +#include "Acts/TrackFitting/GainMatrixUpdater.hpp" +#include "Acts/TrackFitting/GaussianSumFitter.hpp" +#include "Acts/TrackFitting/GsfMixtureReduction.hpp" +#include "Acts/TrackFitting/GsfOptions.hpp" +#include "Acts/Utilities/Delegate.hpp" +#include "Acts/Utilities/HashedString.hpp" +#include "Acts/Utilities/Intersection.hpp" +#include "Acts/Utilities/Logger.hpp" +#include "Acts/Utilities/Zip.hpp" +#include "ActsHelper/EventData/IndexSourceLink.hpp" +#include "ActsHelper/EventData/MeasurementCalibration.hpp" +#include "ActsHelper/EventData/Track.hpp" +#include "ActsHelper/Algorithms/TrackFitting/RefittingCalibrator.hpp" +#include "ActsHelper/Algorithms/TrackFitting/TrackFitterFunction.hpp" + +#include <algorithm> +#include <array> +#include <cstddef> +#include <map> +#include <memory> +#include <optional> +#include <string> +#include <string_view> +#include <tuple> +#include <utility> +#include <vector> + +namespace Acts { +class MagneticFieldProvider; +class SourceLink; +class Surface; +class TrackingGeometry; +} // namespace Acts + +using namespace ActsHelper; + +namespace { + +using MultiStepper = Acts::MultiEigenStepperLoop<>; +using Propagator = Acts::Propagator<MultiStepper, Acts::Navigator>; +using DirectPropagator = Acts::Propagator<MultiStepper, Acts::DirectNavigator>; + +using Fitter = Acts::GaussianSumFitter<Propagator, BetheHeitlerApprox, + Acts::VectorMultiTrajectory>; +using DirectFitter = + Acts::GaussianSumFitter<DirectPropagator, BetheHeitlerApprox, + Acts::VectorMultiTrajectory>; +using TrackContainer = + Acts::TrackContainer<Acts::VectorTrackContainer, + Acts::VectorMultiTrajectory, std::shared_ptr>; + +struct GsfFitterFunctionImpl final : public ActsHelper::TrackFitterFunction { + Fitter fitter; + DirectFitter directFitter; + + Acts::GainMatrixUpdater updater; + + std::size_t maxComponents = 0; + double weightCutoff = 0; + const double momentumCutoff = 0; // 500_MeV; + bool abortOnError = false; + // default is false, but we set it to true for debugging + bool disableAllMaterialHandling = true; + MixtureReductionAlgorithm reductionAlg = + MixtureReductionAlgorithm::KLDistance; + Acts::ComponentMergeMethod mergeMethod = + Acts::ComponentMergeMethod::eMaxWeight; + + IndexSourceLink::SurfaceAccessor m_slSurfaceAccessor; + + GsfFitterFunctionImpl(Fitter&& f, DirectFitter&& df, + const Acts::TrackingGeometry& trkGeo) + : fitter(std::move(f)), + directFitter(std::move(df)), + m_slSurfaceAccessor{trkGeo} {} + + template <typename calibrator_t> + auto makeGsfOptions(const GeneralFitterOptions& options, + const calibrator_t& calibrator) const { + Acts::GsfExtensions<Acts::VectorMultiTrajectory> extensions; + extensions.updater.connect< + &Acts::GainMatrixUpdater::operator()<Acts::VectorMultiTrajectory>>( + &updater); + + Acts::GsfOptions<Acts::VectorMultiTrajectory> gsfOptions{ + options.geoContext, + options.magFieldContext, + options.calibrationContext, + extensions, + options.propOptions, + &(*options.referenceSurface), + maxComponents, + weightCutoff, + abortOnError, + disableAllMaterialHandling}; + gsfOptions.componentMergeMethod = mergeMethod; + + gsfOptions.extensions.calibrator.connect<&calibrator_t::calibrate>( + &calibrator); + gsfOptions.extensions.surfaceAccessor + .connect<&IndexSourceLink::SurfaceAccessor::operator()>( + &m_slSurfaceAccessor); + switch (reductionAlg) { + case MixtureReductionAlgorithm::weightCut: { + gsfOptions.extensions.mixtureReducer + .connect<&Acts::reduceMixtureLargestWeights>(); + } break; + case MixtureReductionAlgorithm::KLDistance: { + gsfOptions.extensions.mixtureReducer + .connect<&Acts::reduceMixtureWithKLDistance>(); + } break; + } + + return gsfOptions; + } + + TrackFitterResult operator()(const std::vector<Acts::SourceLink>& sourceLinks, + const TrackParameters& initialParameters, + const GeneralFitterOptions& options, + const MeasurementCalibratorAdapter& calibrator, + TrackContainer& tracks) const override { + const auto gsfOptions = makeGsfOptions(options, calibrator); + + using namespace Acts::GsfConstants; + if (!tracks.hasColumn(Acts::hashString(kFinalMultiComponentStateColumn))) { + std::string key(kFinalMultiComponentStateColumn); + tracks.template addColumn<FinalMultiComponentState>(key); + } + + if (!tracks.hasColumn(Acts::hashString(kFwdMaxMaterialXOverX0))) { + tracks.template addColumn<double>(std::string(kFwdMaxMaterialXOverX0)); + } + + if (!tracks.hasColumn(Acts::hashString(kFwdSumMaterialXOverX0))) { + tracks.template addColumn<double>(std::string(kFwdSumMaterialXOverX0)); + } + + return fitter.fit(sourceLinks.begin(), sourceLinks.end(), initialParameters, + gsfOptions, tracks); + } + + TrackFitterResult operator()( + const std::vector<Acts::SourceLink>& sourceLinks, + const TrackParameters& initialParameters, + const GeneralFitterOptions& options, + const RefittingCalibrator& calibrator, + const std::vector<const Acts::Surface*>& surfaceSequence, + TrackContainer& tracks) const override { + const auto gsfOptions = makeGsfOptions(options, calibrator); + + using namespace Acts::GsfConstants; + if (!tracks.hasColumn(Acts::hashString(kFinalMultiComponentStateColumn))) { + std::string key(kFinalMultiComponentStateColumn); + tracks.template addColumn<FinalMultiComponentState>(key); + } + + return directFitter.fit(sourceLinks.begin(), sourceLinks.end(), + initialParameters, gsfOptions, surfaceSequence, + tracks); + } +}; + +} // namespace + +std::shared_ptr<TrackFitterFunction> ActsHelper::makeGsfFitterFunction( + std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry, + std::shared_ptr<const Acts::MagneticFieldProvider> magneticField, + BetheHeitlerApprox betheHeitlerApprox, std::size_t maxComponents, + double weightCutoff, Acts::ComponentMergeMethod componentMergeMethod, + MixtureReductionAlgorithm mixtureReductionAlgorithm, + const Acts::Logger& logger) { + // Standard fitter + MultiStepper stepper(magneticField, logger.cloneWithSuffix("Step")); + const auto& geo = *trackingGeometry; + Acts::Navigator::Config cfg{std::move(trackingGeometry)}; + cfg.resolvePassive = false; + cfg.resolveMaterial = true; + cfg.resolveSensitive = true; + Acts::Navigator navigator(cfg, logger.cloneWithSuffix("Navigator")); + Propagator propagator(std::move(stepper), std::move(navigator), + logger.cloneWithSuffix("Propagator")); + Fitter trackFitter(std::move(propagator), + BetheHeitlerApprox(betheHeitlerApprox), + logger.cloneWithSuffix("GSF")); + + // Direct fitter + MultiStepper directStepper(std::move(magneticField), + logger.cloneWithSuffix("Step")); + Acts::DirectNavigator directNavigator{ + logger.cloneWithSuffix("DirectNavigator")}; + DirectPropagator directPropagator(std::move(directStepper), + std::move(directNavigator), + logger.cloneWithSuffix("DirectPropagator")); + DirectFitter directTrackFitter(std::move(directPropagator), + BetheHeitlerApprox(betheHeitlerApprox), + logger.cloneWithSuffix("DirectGSF")); + + // build the fitter functions. owns the fitter object. + auto fitterFunction = std::make_shared<GsfFitterFunctionImpl>( + std::move(trackFitter), std::move(directTrackFitter), geo); + fitterFunction->maxComponents = maxComponents; + fitterFunction->weightCutoff = weightCutoff; + fitterFunction->mergeMethod = componentMergeMethod; + fitterFunction->reductionAlg = mixtureReductionAlgorithm; + + return fitterFunction; +} diff --git a/Reconstruction/RecActsTracking/ActsHelper/src/Algorithms/TrackFitting/KalmanFitterFunction.cpp b/Reconstruction/RecActsTracking/ActsHelper/src/Algorithms/TrackFitting/KalmanFitterFunction.cpp new file mode 100644 index 00000000..55841eb9 --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/src/Algorithms/TrackFitting/KalmanFitterFunction.cpp @@ -0,0 +1,182 @@ +#include "Acts/Definitions/Direction.hpp" +#include "Acts/Definitions/TrackParametrization.hpp" +#include "Acts/EventData/MultiTrajectory.hpp" +#include "Acts/EventData/TrackContainer.hpp" +#include "Acts/EventData/TrackStatePropMask.hpp" +#include "Acts/EventData/VectorMultiTrajectory.hpp" +#include "Acts/EventData/VectorTrackContainer.hpp" +#include "Acts/EventData/detail/CorrectedTransformationFreeToBound.hpp" +#include "Acts/Geometry/GeometryIdentifier.hpp" +#include "Acts/Propagator/DirectNavigator.hpp" +#include "Acts/Propagator/EigenStepper.hpp" +#include "Acts/Propagator/Navigator.hpp" +#include "Acts/Propagator/Propagator.hpp" +#include "Acts/TrackFitting/GainMatrixSmoother.hpp" +#include "Acts/TrackFitting/GainMatrixUpdater.hpp" +#include "Acts/TrackFitting/KalmanFitter.hpp" +#include "Acts/Utilities/Delegate.hpp" +#include "Acts/Utilities/Logger.hpp" +#include "ActsHelper/EventData/IndexSourceLink.hpp" +#include "ActsHelper/EventData/MeasurementCalibration.hpp" +#include "ActsHelper/EventData/Track.hpp" +#include "ActsHelper/Algorithms/TrackFitting/RefittingCalibrator.hpp" +#include "ActsHelper/Algorithms/TrackFitting/TrackFitterFunction.hpp" + +#include <algorithm> +#include <cmath> +#include <functional> +#include <memory> +#include <utility> +#include <vector> + +namespace Acts { +class MagneticFieldProvider; +class SourceLink; +class Surface; +class TrackingGeometry; +} // namespace Acts + +namespace { + +using Stepper = Acts::EigenStepper<>; +using Propagator = Acts::Propagator<Stepper, Acts::Navigator>; +using Fitter = Acts::KalmanFitter<Propagator, Acts::VectorMultiTrajectory>; +using DirectPropagator = Acts::Propagator<Stepper, Acts::DirectNavigator>; +using DirectFitter = + Acts::KalmanFitter<DirectPropagator, Acts::VectorMultiTrajectory>; + +using TrackContainer = + Acts::TrackContainer<Acts::VectorTrackContainer, + Acts::VectorMultiTrajectory, std::shared_ptr>; + +struct SimpleReverseFilteringLogic { + double momentumThreshold = 0; + + bool doBackwardFiltering( + Acts::VectorMultiTrajectory::ConstTrackStateProxy trackState) const { + auto momentum = fabs(1 / trackState.filtered()[Acts::eBoundQOverP]); + return (momentum <= momentumThreshold); + } +}; + +using namespace ActsHelper; + +struct KalmanFitterFunctionImpl final : public TrackFitterFunction { + Fitter fitter; + DirectFitter directFitter; + + Acts::GainMatrixUpdater kfUpdater; + Acts::GainMatrixSmoother kfSmoother; + SimpleReverseFilteringLogic reverseFilteringLogic; + + bool multipleScattering = false; + bool energyLoss = false; + Acts::FreeToBoundCorrection freeToBoundCorrection; + + IndexSourceLink::SurfaceAccessor slSurfaceAccessor; + + KalmanFitterFunctionImpl(Fitter&& f, DirectFitter&& df, + const Acts::TrackingGeometry& trkGeo) + : fitter(std::move(f)), + directFitter(std::move(df)), + slSurfaceAccessor{trkGeo} {} + + template <typename calibrator_t> + auto makeKfOptions(const GeneralFitterOptions& options, + const calibrator_t& calibrator) const { + Acts::KalmanFitterExtensions<Acts::VectorMultiTrajectory> extensions; + extensions.updater.connect< + &Acts::GainMatrixUpdater::operator()<Acts::VectorMultiTrajectory>>( + &kfUpdater); + extensions.smoother.connect< + &Acts::GainMatrixSmoother::operator()<Acts::VectorMultiTrajectory>>( + &kfSmoother); + extensions.reverseFilteringLogic + .connect<&SimpleReverseFilteringLogic::doBackwardFiltering>( + &reverseFilteringLogic); + + Acts::KalmanFitterOptions<Acts::VectorMultiTrajectory> kfOptions( + options.geoContext, options.magFieldContext, options.calibrationContext, + extensions, options.propOptions, &(*options.referenceSurface)); + + kfOptions.referenceSurfaceStrategy = + Acts::KalmanFitterTargetSurfaceStrategy::first; + kfOptions.multipleScattering = multipleScattering; + kfOptions.energyLoss = energyLoss; + kfOptions.freeToBoundCorrection = freeToBoundCorrection; + kfOptions.extensions.calibrator.connect<&calibrator_t::calibrate>( + &calibrator); + kfOptions.extensions.surfaceAccessor + .connect<&IndexSourceLink::SurfaceAccessor::operator()>( + &slSurfaceAccessor); + + return kfOptions; + } + + TrackFitterResult operator()(const std::vector<Acts::SourceLink>& sourceLinks, + const TrackParameters& initialParameters, + const GeneralFitterOptions& options, + const MeasurementCalibratorAdapter& calibrator, + TrackContainer& tracks) const override { + const auto kfOptions = makeKfOptions(options, calibrator); + return fitter.fit(sourceLinks.begin(), sourceLinks.end(), initialParameters, + kfOptions, tracks); + } + + TrackFitterResult operator()( + const std::vector<Acts::SourceLink>& sourceLinks, + const TrackParameters& initialParameters, + const GeneralFitterOptions& options, + const RefittingCalibrator& calibrator, + const std::vector<const Acts::Surface*>& surfaceSequence, + TrackContainer& tracks) const override { + const auto kfOptions = makeKfOptions(options, calibrator); + return directFitter.fit(sourceLinks.begin(), sourceLinks.end(), + initialParameters, kfOptions, surfaceSequence, + tracks); + } +}; + +} // namespace + +std::shared_ptr<ActsHelper::TrackFitterFunction> +ActsHelper::makeKalmanFitterFunction( + std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry, + std::shared_ptr<const Acts::MagneticFieldProvider> magneticField, + bool multipleScattering, bool energyLoss, + double reverseFilteringMomThreshold, + Acts::FreeToBoundCorrection freeToBoundCorrection, + const Acts::Logger& logger) { + // Stepper should be copied into the fitters + const Stepper stepper(std::move(magneticField)); + + // Standard fitter + const auto& geo = *trackingGeometry; + Acts::Navigator::Config cfg{std::move(trackingGeometry)}; + cfg.resolvePassive = false; + cfg.resolveMaterial = true; + cfg.resolveSensitive = true; + Acts::Navigator navigator(cfg, logger.cloneWithSuffix("Navigator")); + Propagator propagator(stepper, std::move(navigator), + logger.cloneWithSuffix("Propagator")); + Fitter trackFitter(std::move(propagator), logger.cloneWithSuffix("Fitter")); + + // Direct fitter + Acts::DirectNavigator directNavigator{ + logger.cloneWithSuffix("DirectNavigator")}; + DirectPropagator directPropagator(stepper, std::move(directNavigator), + logger.cloneWithSuffix("DirectPropagator")); + DirectFitter directTrackFitter(std::move(directPropagator), + logger.cloneWithSuffix("DirectFitter")); + + // build the fitter function. owns the fitter object. + auto fitterFunction = std::make_shared<KalmanFitterFunctionImpl>( + std::move(trackFitter), std::move(directTrackFitter), geo); + fitterFunction->multipleScattering = multipleScattering; + fitterFunction->energyLoss = energyLoss; + fitterFunction->reverseFilteringLogic.momentumThreshold = + reverseFilteringMomThreshold; + fitterFunction->freeToBoundCorrection = freeToBoundCorrection; + + return fitterFunction; +} diff --git a/Reconstruction/RecActsTracking/ActsHelper/src/Algorithms/TrackFitting/RefittingCalibrator.cpp b/Reconstruction/RecActsTracking/ActsHelper/src/Algorithms/TrackFitting/RefittingCalibrator.cpp new file mode 100644 index 00000000..0ef3e8a2 --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/src/Algorithms/TrackFitting/RefittingCalibrator.cpp @@ -0,0 +1,35 @@ +#include "ActsHelper/Algorithms/TrackFitting/RefittingCalibrator.hpp" + +#include "Acts/Definitions/Algebra.hpp" +#include "Acts/EventData/MeasurementHelpers.hpp" +#include "Acts/EventData/SourceLink.hpp" +#include "Acts/Utilities/CalibrationContext.hpp" + +namespace ActsHelper { + +void RefittingCalibrator::calibrate(const Acts::GeometryContext& /*gctx*/, + const Acts::CalibrationContext& /*cctx*/, + const Acts::SourceLink& sourceLink, + Proxy trackState) const { + const auto sl = sourceLink.get<RefittingSourceLink>(); + + // Reset the original uncalibrated sourcelink on this track state + trackState.setUncalibratedSourceLink(sl.state.getUncalibratedSourceLink()); + + // Here we construct a measurement by extracting the information available + // in the state + Acts::visit_measurement(sl.state.calibratedSize(), [&](auto N) { + using namespace Acts; + constexpr int Size = decltype(N)::value; + + trackState.allocateCalibrated(Size); + trackState.template calibrated<Size>() = + sl.state.template calibrated<Size>(); + trackState.template calibratedCovariance<Size>() = + sl.state.template calibratedCovariance<Size>(); + }); + + trackState.setProjectorBitset(sl.state.projectorBitset()); +} + +} // namespace ActsHelper diff --git a/Reconstruction/RecActsTracking/src/utils/TGeoDetector.hpp b/Reconstruction/RecActsTracking/ActsHelper/src/Detectors/TGeoDetector.cpp similarity index 77% rename from Reconstruction/RecActsTracking/src/utils/TGeoDetector.hpp rename to Reconstruction/RecActsTracking/ActsHelper/src/Detectors/TGeoDetector.cpp index 4163d23b..bc695120 100644 --- a/Reconstruction/RecActsTracking/src/utils/TGeoDetector.hpp +++ b/Reconstruction/RecActsTracking/ActsHelper/src/Detectors/TGeoDetector.cpp @@ -1,168 +1,4 @@ -#include "Acts/Geometry/CylinderVolumeBuilder.hpp" -#include "Acts/Geometry/CylinderVolumeHelper.hpp" -#include "Acts/Geometry/GeometryContext.hpp" -#include "Acts/Geometry/GeometryIdentifier.hpp" -#include "Acts/Geometry/ITrackingVolumeBuilder.hpp" -#include "Acts/Geometry/LayerArrayCreator.hpp" -#include "Acts/Geometry/LayerCreator.hpp" -#include "Acts/Geometry/PassiveLayerBuilder.hpp" -#include "Acts/Geometry/ProtoLayerHelper.hpp" -#include "Acts/Geometry/SurfaceArrayCreator.hpp" -#include "Acts/Geometry/SurfaceBinningMatcher.hpp" -#include "Acts/Geometry/TrackingGeometry.hpp" -#include "Acts/Geometry/TrackingGeometryBuilder.hpp" -#include "Acts/Geometry/TrackingVolumeArrayCreator.hpp" - -#include "Acts/Plugins/TGeo/TGeoCylinderDiscSplitter.hpp" -#include "Acts/Plugins/TGeo/TGeoLayerBuilder.hpp" -#include "Acts/Plugins/Json/JsonMaterialDecorator.hpp" -#include "Acts/Plugins/Json/ActsJson.hpp" - -#include "Acts/Utilities/BinningType.hpp" -#include "Acts/Utilities/Logger.hpp" - -#include <boost/program_options.hpp> -#include <nlohmann/json.hpp> - -#include <cstddef> -#include <map> -#include <memory> -#include <stdexcept> -#include <string> -#include <utility> -#include <vector> - -namespace Acts -{ - class TGeoDetectorElement; - class TrackingGeometry; - class IMaterialDecorator; -} - -/// ---------------------------- -/// pre definitions -/// ---------------------------- - -/// Half open [lower,upper) interval type for a single user option. -/// -/// A missing limit represents an unbounded upper or lower limit. With just -/// one defined limit the interval is just a lower/upper bound; with both -/// limits undefined, the interval is unbounded everywhere and thus contains -/// all possible values. -struct Interval -{ - std::optional<double> lower; - std::optional<double> upper; -}; - -/// Extract an interval from an input of the form 'lower:upper'. -/// -/// An input of the form `lower:` or `:upper` sets just one of the limits. Any -/// other input leads to an unbounded interval. -/// -/// @note The more common range notation uses `lower-upper` but the `-` -/// separator complicates the parsing of negative values. -std::istream& operator>>(std::istream& is, Interval& interval); - -/// Print an interval as `lower:upper`. -std::ostream& operator<<(std::ostream& os, const Interval& interval); - -struct TGeoConfig { - Acts::Logging::Level surfaceLogLevel = Acts::Logging::WARNING; - Acts::Logging::Level layerLogLevel = Acts::Logging::WARNING; - Acts::Logging::Level volumeLogLevel = Acts::Logging::WARNING; - - std::string fileName; - bool buildBeamPipe = false; - double beamPipeRadius{0}; - double beamPipeHalflengthZ{0}; - double beamPipeLayerThickness{0}; - double beamPipeEnvelopeR{1.0}; - double layerEnvelopeR{1.0}; - - double unitScalor = 1.0; - - Acts::TGeoLayerBuilder::ElementFactory elementFactory = - Acts::TGeoLayerBuilder::defaultElementFactory; - - /// Optional geometry identifier hook to be used during closure - std::shared_ptr<const Acts::GeometryIdentifierHook> geometryIdentifierHook = - std::make_shared<Acts::GeometryIdentifierHook>(); - - enum SubVolume : std::size_t { Negative = 0, Central, Positive }; - - template <typename T> - struct LayerTriplet - { - LayerTriplet() = default; - - LayerTriplet(T value) - : negative{value}, central{value}, positive{value} {} - - LayerTriplet(T _negative, T _central, T _positive) - : negative{_negative}, central{_central}, positive{_positive} {} - - T negative; - T central; - T positive; - - T& at(SubVolume i) - { - switch (i) - { - case Negative: return negative; - case Central: return central; - case Positive: return positive; - default: throw std::invalid_argument{"Unknown index"}; - } - } - - const T& at(SubVolume i) const - { - switch (i) - { - case Negative: return negative; - case Central: return central; - case Positive: return positive; - default: throw std::invalid_argument{"Unknown index"}; - } - } - }; - - struct Volume { - std::string name; - LayerTriplet<bool> layers{false}; - LayerTriplet<std::string> subVolumeName; - LayerTriplet<std::vector<std::string>> sensitiveNames; - LayerTriplet<std::string> sensitiveAxes; - LayerTriplet<Interval> rRange; - LayerTriplet<Interval> zRange; - LayerTriplet<double> splitTolR{0}; - LayerTriplet<double> splitTolZ{0}; - LayerTriplet<std::vector<std::pair<int, Acts::BinningType>>> binning0; - LayerTriplet<std::vector<std::pair<int, Acts::BinningType>>> binning1; - - Interval binToleranceR; - Interval binTolerancePhi; - Interval binToleranceZ; - - bool cylinderDiscSplit = false; - unsigned int cylinderNZSegments = 0; - unsigned int cylinderNPhiSegments = 0; - unsigned int discNRSegments = 0; - unsigned int discNPhiSegments = 0; - - bool itkModuleSplit = false; - std::map<std::string, unsigned int> barrelMap; - std::map<std::string, std::vector<std::pair<double, double>>> discMap; - /// pairs of regular expressions to match sensor names and category keys - /// for either the barrelMap or the discMap - /// @TODO in principle vector<pair< > > would be good enough - std::map<std::string, std::string> splitPatterns; - }; - - std::vector<Volume> volumes; -}; +#include "ActsHelper/Detectors/TGeoDetector.hpp" /// ------------------------------------------------------------------------------------------------ /// @note nlohmann::json must define functions *from_json* && *to_json* for json conversion @@ -541,6 +377,8 @@ std::shared_ptr<const Acts::TrackingGeometry> buildTGeoDetector( volumeConfig.volumeName = lbc.configurationName; volumeConfig.buildToRadiusZero = volumeBuilders.empty(); volumeConfig.layerEnvelopeR = {config.layerEnvelopeR, config.layerEnvelopeR}; + volumeConfig.layerEnvelopeZ = 0.2 * Acts::UnitConstants::mm; + auto ringLayoutConfiguration = [&](const std::vector<Acts::TGeoLayerBuilder::LayerConfig>& lConfigs) -> void { diff --git a/Reconstruction/RecActsTracking/ActsHelper/src/EventData/MeasurementCalibration.cpp b/Reconstruction/RecActsTracking/ActsHelper/src/EventData/MeasurementCalibration.cpp new file mode 100644 index 00000000..93de070b --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/src/EventData/MeasurementCalibration.cpp @@ -0,0 +1,43 @@ +#include "Acts/EventData/SourceLink.hpp" +#include "ActsHelper/EventData/IndexSourceLink.hpp" +#include "ActsHelper/EventData/Measurement.hpp" +#include <ActsHelper/EventData/MeasurementCalibration.hpp> + +#include <cassert> +#include <variant> + +namespace Acts { +class VectorMultiTrajectory; +} // namespace Acts + +void ActsHelper::PassThroughCalibrator::calibrate( + const MeasurementContainer& measurements, + const ClusterContainer* /*clusters*/, const Acts::GeometryContext& /*gctx*/, + const Acts::CalibrationContext& /*cctx*/, + const Acts::SourceLink& sourceLink, + Acts::VectorMultiTrajectory::TrackStateProxy& trackState) const { + trackState.setUncalibratedSourceLink(sourceLink); + const IndexSourceLink& idxSourceLink = sourceLink.get<IndexSourceLink>(); + + assert((idxSourceLink.index() < measurements.size()) && + "Source link index is outside the container bounds"); + + std::visit( + [&trackState](const auto& meas) { trackState.setCalibrated(meas); }, + measurements[idxSourceLink.index()]); +} + +ActsHelper::MeasurementCalibratorAdapter::MeasurementCalibratorAdapter( + const MeasurementCalibrator& calibrator, + const MeasurementContainer& measurements, const ClusterContainer* clusters) + : m_calibrator{calibrator}, + m_measurements{measurements}, + m_clusters{clusters} {} + +void ActsHelper::MeasurementCalibratorAdapter::calibrate( + const Acts::GeometryContext& gctx, const Acts::CalibrationContext& cctx, + const Acts::SourceLink& sourceLink, + Acts::VectorMultiTrajectory::TrackStateProxy trackState) const { + return m_calibrator.calibrate(m_measurements, m_clusters, gctx, cctx, + sourceLink, trackState); +} diff --git a/Reconstruction/RecActsTracking/ActsHelper/src/EventData/ScalingCalibrator.cpp b/Reconstruction/RecActsTracking/ActsHelper/src/EventData/ScalingCalibrator.cpp new file mode 100644 index 00000000..34c48a18 --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/src/EventData/ScalingCalibrator.cpp @@ -0,0 +1,174 @@ +#include "Acts/Definitions/Algebra.hpp" +#include "Acts/EventData/Measurement.hpp" +#include "Acts/EventData/MultiTrajectory.hpp" +#include "Acts/EventData/SourceLink.hpp" +#include "Acts/Geometry/GeometryContext.hpp" +#include "Acts/Geometry/GeometryIdentifier.hpp" +#include "Acts/Utilities/CalibrationContext.hpp" +#include "ActsHelper/EventData/Cluster.hpp" +#include "ActsHelper/EventData/IndexSourceLink.hpp" +#include "ActsHelper/EventData/Measurement.hpp" +#include <Acts/Definitions/TrackParametrization.hpp> +#include <ActsHelper/EventData/ScalingCalibrator.hpp> + +#include <algorithm> +#include <array> +#include <bitset> +#include <cassert> +#include <cstring> +#include <filesystem> +#include <map> +#include <regex> +#include <stdexcept> +#include <string> +#include <type_traits> +#include <utility> +#include <variant> +#include <vector> + +#include <TCollection.h> +#include <TFile.h> +#include <TH2.h> +#include <TKey.h> +#include <TList.h> +#include <TString.h> + +namespace Acts { +class VectorMultiTrajectory; +} // namespace Acts + +namespace detail { + +std::pair<Acts::GeometryIdentifier, std::string> parseMapKey( + const std::string& mapkey) { + std::regex reg("^map_([0-9]+)-([0-9]+)-([0-9]+)_([xy]_.*)$"); + std::smatch matches; + + if (std::regex_search(mapkey, matches, reg) && matches.size() == 5) { + std::size_t vol = std::stoull(matches[1].str()); + std::size_t lyr = std::stoull(matches[2].str()); + std::size_t mod = std::stoull(matches[3].str()); + + Acts::GeometryIdentifier geoId; + geoId.setVolume(vol); + geoId.setLayer(lyr); + geoId.setSensitive(mod); + + std::string var(matches[4].str()); + + return std::make_pair(geoId, var); + } else { + throw std::runtime_error("Invalid map key: " + mapkey); + } +} + +std::map<Acts::GeometryIdentifier, ActsHelper::ScalingCalibrator::MapTuple> +readMaps(const std::filesystem::path& path) { + std::map<Acts::GeometryIdentifier, ActsHelper::ScalingCalibrator::MapTuple> + maps; + + TFile ifile(path.c_str(), "READ"); + if (ifile.IsZombie()) { + throw std::runtime_error("Unable to open TFile: " + path.string()); + } + + TList* lst = ifile.GetListOfKeys(); + assert(lst != nullptr); + + for (auto it = lst->begin(); it != lst->end(); ++it) { + TKey* key = static_cast<TKey*>(*it); + if (std::strcmp(key->GetClassName(), "TH2D") == 0) { + auto [geoId, var] = parseMapKey(key->GetName()); + + TH2D hist; + key->Read(&hist); + + if (var == "x_offset") { + maps[geoId].x_offset = hist; + } else if (var == "x_scale") { + maps[geoId].x_scale = hist; + } else if (var == "y_offset") { + maps[geoId].y_offset = hist; + } else if (var == "y_scale") { + maps[geoId].y_scale = hist; + } else { + throw std::runtime_error("Unrecognized var: " + var); + } + } + } + return maps; +} + +std::bitset<3> readMask(const std::filesystem::path& path) { + TFile ifile(path.c_str(), "READ"); + if (ifile.IsZombie()) { + throw std::runtime_error("Unable to open TFile: " + path.string()); + } + + TString* tstr = ifile.Get<TString>("v_mask"); + if (tstr == nullptr) { + throw std::runtime_error("Unable to read mask"); + } + + return std::bitset<3>(std::string{*tstr}); +} + +} // namespace detail + +ActsHelper::ScalingCalibrator::ScalingCalibrator( + const std::filesystem::path& path) + : m_calib_maps{::detail::readMaps(path)}, + m_mask{::detail::readMask(path)} {} + +void ActsHelper::ScalingCalibrator::calibrate( + const MeasurementContainer& measurements, const ClusterContainer* clusters, + const Acts::GeometryContext& /*gctx*/, + const Acts::CalibrationContext& /*cctx*/, + const Acts::SourceLink& sourceLink, + Acts::VectorMultiTrajectory::TrackStateProxy& trackState) const { + trackState.setUncalibratedSourceLink(sourceLink); + const IndexSourceLink& idxSourceLink = sourceLink.get<IndexSourceLink>(); + + assert((idxSourceLink.index() < measurements.size()) && + "Source link index is outside the container bounds"); + + auto geoId = trackState.referenceSurface().geometryId(); + Acts::GeometryIdentifier mgid; + mgid.setVolume(geoId.volume() * + static_cast<Acts::GeometryIdentifier::Value>(m_mask[2])); + mgid.setLayer(geoId.layer() * + static_cast<Acts::GeometryIdentifier::Value>(m_mask[1])); + mgid.setSensitive(geoId.sensitive() * + static_cast<Acts::GeometryIdentifier::Value>(m_mask[0])); + const Cluster& cl = clusters->at(idxSourceLink.index()); + ConstantTuple ct = m_calib_maps.at(mgid).at(cl.sizeLoc0, cl.sizeLoc1); + + std::visit( + [&](const auto& meas) { + auto E = meas.expander(); + auto P = meas.projector(); + + Acts::ActsVector<Acts::eBoundSize> fpar = E * meas.parameters(); + + Acts::ActsSquareMatrix<Acts::eBoundSize> fcov = + E * meas.covariance() * E.transpose(); + + fpar[Acts::eBoundLoc0] += ct.x_offset; + fpar[Acts::eBoundLoc1] += ct.y_offset; + fcov(Acts::eBoundLoc0, Acts::eBoundLoc0) *= ct.x_scale; + fcov(Acts::eBoundLoc1, Acts::eBoundLoc1) *= ct.y_scale; + + constexpr std::size_t kSize = + std::remove_reference_t<decltype(meas)>::size(); + std::array<Acts::BoundIndices, kSize> indices = meas.indices(); + Acts::ActsVector<kSize> cpar = P * fpar; + Acts::ActsSquareMatrix<kSize> ccov = P * fcov * P.transpose(); + + Acts::Measurement<Acts::BoundIndices, kSize> cmeas( + Acts::SourceLink{idxSourceLink}, indices, cpar, ccov); + + trackState.allocateCalibrated(cmeas.size()); + trackState.setCalibrated(cmeas); + }, + (measurements)[idxSourceLink.index()]); +} diff --git a/Reconstruction/RecActsTracking/ActsHelper/src/MagneticField/FieldMapRootIo.cpp b/Reconstruction/RecActsTracking/ActsHelper/src/MagneticField/FieldMapRootIo.cpp new file mode 100644 index 00000000..8fbe91d1 --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/src/MagneticField/FieldMapRootIo.cpp @@ -0,0 +1,117 @@ +#include "ActsHelper/MagneticField/FieldMapRootIo.hpp" + +#include "Acts/MagneticField/BFieldMapUtils.hpp" + +#include <stdexcept> +#include <vector> + +#include <RtypesCore.h> +#include <TFile.h> +#include <TTree.h> + +ActsHelper::detail::InterpolatedMagneticField2 +ActsHelper::makeMagneticFieldMapRzFromRoot( + const std::function<std::size_t(std::array<std::size_t, 2> binsRZ, + std::array<std::size_t, 2> nBinsRZ)>& + localToGlobalBin, + const std::string& fieldMapFile, const std::string& treeName, + Acts::ActsScalar lengthUnit, Acts::ActsScalar BFieldUnit, + bool firstQuadrant) { + /// [1] Read in field map file + // Grid position points in r and z + std::vector<double> rPos; + std::vector<double> zPos; + // components of magnetic field on grid points + std::vector<Acts::Vector2> bField; + // [1] Read in file and fill values + TFile* inputFile = TFile::Open(fieldMapFile.c_str()); + if (inputFile == nullptr) { + throw std::runtime_error("file does not exist"); + } + TTree* tree = inputFile->Get<TTree>(treeName.c_str()); + if (tree == nullptr) { + throw std::runtime_error("object not found in file"); + } + Int_t entries = tree->GetEntries(); + + double r = 0, z = 0; + double Br = 0, Bz = 0; + + tree->SetBranchAddress("r", &r); + tree->SetBranchAddress("z", &z); + + tree->SetBranchAddress("Br", &Br); + tree->SetBranchAddress("Bz", &Bz); + + // reserve size + rPos.reserve(entries); + zPos.reserve(entries); + bField.reserve(entries); + + for (int i = 0; i < entries; i++) { + tree->GetEvent(i); + rPos.push_back(r); + zPos.push_back(z); + bField.push_back(Acts::Vector2(Br, Bz)); + } + delete inputFile; + /// [2] use helper function in core + return Acts::fieldMapRZ(localToGlobalBin, rPos, zPos, bField, lengthUnit, + BFieldUnit, firstQuadrant); +} + +ActsHelper::detail::InterpolatedMagneticField3 +ActsHelper::makeMagneticFieldMapXyzFromRoot( + const std::function<std::size_t(std::array<std::size_t, 3> binsXYZ, + std::array<std::size_t, 3> nBinsXYZ)>& + localToGlobalBin, + const std::string& fieldMapFile, const std::string& treeName, + Acts::ActsScalar lengthUnit, Acts::ActsScalar BFieldUnit, + bool firstOctant) { + /// [1] Read in field map file + // Grid position points in x, y and z + std::vector<double> xPos; + std::vector<double> yPos; + std::vector<double> zPos; + // components of magnetic field on grid points + std::vector<Acts::Vector3> bField; + // [1] Read in file and fill values + TFile* inputFile = TFile::Open(fieldMapFile.c_str()); + if (inputFile == nullptr) { + throw std::runtime_error("file does not exist"); + } + TTree* tree = inputFile->Get<TTree>(treeName.c_str()); + if (tree == nullptr) { + throw std::runtime_error("object not found in file"); + } + Int_t entries = tree->GetEntries(); + + double x = 0, y = 0, z = 0; + double Bx = 0, By = 0, Bz = 0; + + tree->SetBranchAddress("x", &x); + tree->SetBranchAddress("y", &y); + tree->SetBranchAddress("z", &z); + + tree->SetBranchAddress("Bx", &Bx); + tree->SetBranchAddress("By", &By); + tree->SetBranchAddress("Bz", &Bz); + + // reserve size + xPos.reserve(entries); + yPos.reserve(entries); + zPos.reserve(entries); + bField.reserve(entries); + + for (int i = 0; i < entries; i++) { + tree->GetEvent(i); + xPos.push_back(x); + yPos.push_back(y); + zPos.push_back(z); + bField.push_back(Acts::Vector3(Bx, By, Bz)); + } + delete inputFile; + + return Acts::fieldMapXYZ(localToGlobalBin, xPos, yPos, zPos, bField, + lengthUnit, BFieldUnit, firstOctant); +} diff --git a/Reconstruction/RecActsTracking/ActsHelper/src/MagneticField/FieldMapTextIo.cpp b/Reconstruction/RecActsTracking/ActsHelper/src/MagneticField/FieldMapTextIo.cpp new file mode 100644 index 00000000..ffeebf29 --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/src/MagneticField/FieldMapTextIo.cpp @@ -0,0 +1,99 @@ +#include "ActsHelper/MagneticField/FieldMapTextIo.hpp" + +#include "Acts/MagneticField/BFieldMapUtils.hpp" + +#include <fstream> +#include <vector> + +namespace { +constexpr std::size_t kDefaultSize = 1 << 15; +} + +ActsHelper::detail::InterpolatedMagneticField2 +ActsHelper::makeMagneticFieldMapRzFromText( + const std::function<std::size_t(std::array<std::size_t, 2> binsRZ, + std::array<std::size_t, 2> nBinsRZ)>& + localToGlobalBin, + const std::string& fieldMapFile, Acts::ActsScalar lengthUnit, + Acts::ActsScalar BFieldUnit, bool firstQuadrant) { + /// [1] Read in field map file + // Grid position points in r and z + std::vector<double> rPos; + std::vector<double> zPos; + // components of magnetic field on grid points + std::vector<Acts::Vector2> bField; + // reserve estimated size + rPos.reserve(kDefaultSize); + zPos.reserve(kDefaultSize); + bField.reserve(kDefaultSize); + // [1] Read in file and fill values + std::ifstream map_file(fieldMapFile.c_str(), std::ios::in); + std::string line; + double r = 0., z = 0.; + double br = 0., bz = 0.; + while (std::getline(map_file, line)) { + if (line.empty() || line[0] == '%' || line[0] == '#' || + line.find_first_not_of(' ') == std::string::npos) { + continue; + } + + std::istringstream tmp(line); + tmp >> r >> z >> br >> bz; + rPos.push_back(r); + zPos.push_back(z); + bField.push_back(Acts::Vector2(br, bz)); + } + map_file.close(); + rPos.shrink_to_fit(); + zPos.shrink_to_fit(); + bField.shrink_to_fit(); + /// [2] use helper function in core + return Acts::fieldMapRZ(localToGlobalBin, rPos, zPos, bField, lengthUnit, + BFieldUnit, firstQuadrant); +} + +ActsHelper::detail::InterpolatedMagneticField3 +ActsHelper::makeMagneticFieldMapXyzFromText( + const std::function<std::size_t(std::array<std::size_t, 3> binsXYZ, + std::array<std::size_t, 3> nBinsXYZ)>& + localToGlobalBin, + const std::string& fieldMapFile, Acts::ActsScalar lengthUnit, + Acts::ActsScalar BFieldUnit, bool firstOctant) { + /// [1] Read in field map file + // Grid position points in x, y and z + std::vector<double> xPos; + std::vector<double> yPos; + std::vector<double> zPos; + // components of magnetic field on grid points + std::vector<Acts::Vector3> bField; + // reserve estimated size + xPos.reserve(kDefaultSize); + yPos.reserve(kDefaultSize); + zPos.reserve(kDefaultSize); + bField.reserve(kDefaultSize); + // [1] Read in file and fill values + std::ifstream map_file(fieldMapFile.c_str(), std::ios::in); + std::string line; + double x = 0., y = 0., z = 0.; + double bx = 0., by = 0., bz = 0.; + while (std::getline(map_file, line)) { + if (line.empty() || line[0] == '%' || line[0] == '#' || + line.find_first_not_of(' ') == std::string::npos) { + continue; + } + + std::istringstream tmp(line); + tmp >> x >> y >> z >> bx >> by >> bz; + xPos.push_back(x); + yPos.push_back(y); + zPos.push_back(z); + bField.push_back(Acts::Vector3(bx, by, bz)); + } + map_file.close(); + xPos.shrink_to_fit(); + yPos.shrink_to_fit(); + zPos.shrink_to_fit(); + bField.shrink_to_fit(); + return Acts::fieldMapXYZ(localToGlobalBin, xPos, yPos, zPos, bField, + lengthUnit, BFieldUnit, firstOctant); +} diff --git a/Reconstruction/RecActsTracking/ActsHelper/src/Utilities/EventDataTransforms.cpp b/Reconstruction/RecActsTracking/ActsHelper/src/Utilities/EventDataTransforms.cpp new file mode 100644 index 00000000..35b36927 --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/src/Utilities/EventDataTransforms.cpp @@ -0,0 +1,74 @@ +#include "ActsHelper/Utilities/EventDataTransforms.hpp" + +#include "Acts/EventData/SourceLink.hpp" +#include "ActsHelper/EventData/IndexSourceLink.hpp" +#include "ActsHelper/EventData/SimSpacePoint.hpp" + +#include <vector> + +ActsHelper::ProtoTrack ActsHelper::seedToPrototrack( + const ActsHelper::SimSeed& seed) { + ProtoTrack track; + track.reserve(seed.sp().size()); + for (auto spacePointPtr : seed.sp()) { + for (const auto& slink : spacePointPtr->sourceLinks()) { + const auto& islink = slink.get<IndexSourceLink>(); + track.emplace_back(islink.index()); + } + } + return track; +} + +const ActsHelper::SimSpacePoint* ActsHelper::findSpacePointForIndex( + ActsHelper::Index index, const SimSpacePointContainer& spacepoints) { + auto match = [&](const SimSpacePoint& sp) { + const auto& sls = sp.sourceLinks(); + return std::any_of(sls.begin(), sls.end(), [&](const auto& sl) { + return sl.template get<IndexSourceLink>().index() == index; + }); + }; + + auto found = std::find_if(spacepoints.begin(), spacepoints.end(), match); + + if (found == spacepoints.end()) { + return nullptr; + } + + return &(*found); +} + +ActsHelper::SimSeed ActsHelper::prototrackToSeed( + const ActsHelper::ProtoTrack& track, + const ActsHelper::SimSpacePointContainer& spacepoints) { + auto findSpacePoint = [&](ActsHelper::Index index) { + auto found = findSpacePointForIndex(index, spacepoints); + if (found == nullptr) { + throw std::runtime_error("No spacepoint found for source-link index " + + std::to_string(index)); + } + return found; + }; + + const auto s = track.size(); + if (s < 3) { + throw std::runtime_error( + "Cannot convert track with less then 3 spacepoints to seed"); + } + + std::vector<const SimSpacePoint*> ps; + ps.reserve(track.size()); + + std::transform(track.begin(), track.end(), std::back_inserter(ps), + findSpacePoint); + std::sort(ps.begin(), ps.end(), + [](const auto& a, const auto& b) { return a->r() < b->r(); }); + + // Simply use r = m*z + t and solve for r=0 to find z vertex position... + // Probably not the textbook way to do + const auto m = + (ps.back()->r() - ps.front()->r()) / (ps.back()->z() - ps.front()->z()); + const auto t = ps.front()->r() - m * ps.front()->z(); + const auto z_vertex = -t / m; + + return SimSeed(*ps[0], *ps[s / 2], *ps[s - 1], z_vertex); +} diff --git a/Reconstruction/RecActsTracking/ActsHelper/src/Utilities/Helpers.cpp b/Reconstruction/RecActsTracking/ActsHelper/src/Utilities/Helpers.cpp new file mode 100644 index 00000000..024c828f --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/src/Utilities/Helpers.cpp @@ -0,0 +1,101 @@ +#include "ActsHelper/Utilities/Helpers.hpp" + +#include <cassert> + +#include <TAxis.h> +#include <TEfficiency.h> +#include <TFitResult.h> +#include <TFitResultPtr.h> +#include <TH1.h> +#include <TH2.h> +#include <TProfile.h> + +namespace ActsHelper::PlotHelpers { +TH1F* bookHisto(const char* histName, const char* histTitle, + const Binning& varBinning) { + TH1F* hist = + new TH1F(histName, histTitle, varBinning.nBins(), varBinning.data()); + hist->GetXaxis()->SetTitle(varBinning.title().c_str()); + hist->GetYaxis()->SetTitle("Entries"); + hist->Sumw2(); + return hist; +} + +TH2F* bookHisto(const char* histName, const char* histTitle, + const Binning& varXBinning, const Binning& varYBinning) { + TH2F* hist = + new TH2F(histName, histTitle, varXBinning.nBins(), varXBinning.data(), + varYBinning.nBins(), varYBinning.data()); + hist->GetXaxis()->SetTitle(varXBinning.title().c_str()); + hist->GetYaxis()->SetTitle(varYBinning.title().c_str()); + hist->Sumw2(); + return hist; +} + +void fillHisto(TH1F* hist, float value, float weight) { + assert(hist != nullptr); + hist->Fill(value, weight); +} + +void fillHisto(TH2F* hist, float xValue, float yValue, float weight) { + assert(hist != nullptr); + hist->Fill(xValue, yValue, weight); +} + +void anaHisto(TH1D* inputHist, int j, TH1F* meanHist, TH1F* widthHist) { + // evaluate mean and width via the Gauss fit + assert(inputHist != nullptr); + if (inputHist->GetEntries() > 0) { + TFitResultPtr r = inputHist->Fit("gaus", "QS0"); + if ((r.Get() != nullptr) && ((r->Status() % 1000) == 0)) { + // fill the mean and width into 'j'th bin of the meanHist and widthHist, + // respectively + meanHist->SetBinContent(j, r->Parameter(1)); + meanHist->SetBinError(j, r->ParError(1)); + widthHist->SetBinContent(j, r->Parameter(2)); + widthHist->SetBinError(j, r->ParError(2)); + } + } +} + +TEfficiency* bookEff(const char* effName, const char* effTitle, + const Binning& varBinning) { + TEfficiency* efficiency = + new TEfficiency(effName, effTitle, varBinning.nBins(), varBinning.data()); + return efficiency; +} + +TEfficiency* bookEff(const char* effName, const char* effTitle, + const Binning& varXBinning, const Binning& varYBinning) { + TEfficiency* efficiency = new TEfficiency( + effName, effTitle, varXBinning.nBins(), varXBinning.data(), + varYBinning.nBins(), varYBinning.data()); + return efficiency; +} + +void fillEff(TEfficiency* efficiency, float value, bool status) { + assert(efficiency != nullptr); + efficiency->Fill(status, value); +} + +void fillEff(TEfficiency* efficiency, float xValue, float yValue, bool status) { + assert(efficiency != nullptr); + efficiency->Fill(status, xValue, yValue); +} + +TProfile* bookProf(const char* profName, const char* profTitle, + const Binning& varXBinning, const Binning& varYBinning) { + TProfile* prof = + new TProfile(profName, profTitle, varXBinning.nBins(), varXBinning.data(), + varYBinning.low(), varYBinning.high()); + prof->GetXaxis()->SetTitle(varXBinning.title().c_str()); + prof->GetYaxis()->SetTitle(varYBinning.title().c_str()); + return prof; +} + +void fillProf(TProfile* profile, float xValue, float yValue, float weight) { + assert(profile != nullptr); + profile->Fill(xValue, yValue, weight); +} + +} // namespace ActsHelper::PlotHelpers diff --git a/Reconstruction/RecActsTracking/src/utils/Options.cpp b/Reconstruction/RecActsTracking/ActsHelper/src/Utilities/Options.cpp similarity index 82% rename from Reconstruction/RecActsTracking/src/utils/Options.cpp rename to Reconstruction/RecActsTracking/ActsHelper/src/Utilities/Options.cpp index 0ce24a87..515853c4 100644 --- a/Reconstruction/RecActsTracking/src/utils/Options.cpp +++ b/Reconstruction/RecActsTracking/ActsHelper/src/Utilities/Options.cpp @@ -1,12 +1,4 @@ -// This file is part of the Acts project. -// -// Copyright (C) 2020 CERN for the benefit of the Acts project -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#include "Options.hpp" +#include "ActsHelper/Utilities/Options.hpp" #include <algorithm> #include <iostream> @@ -21,8 +13,8 @@ constexpr char s_separator = ':'; // interval -std::istream& Options::operator>>( - std::istream& is, Options::Interval& interval) { +std::istream& ActsHelper::Options::operator>>( + std::istream& is, ActsHelper::Options::Interval& interval) { std::string buf; is >> buf; @@ -51,8 +43,8 @@ std::istream& Options::operator>>( return is; } -std::ostream& Options::operator<<( - std::ostream& os, const Options::Interval& interval) { +std::ostream& ActsHelper::Options::operator<<( + std::ostream& os, const ActsHelper::Options::Interval& interval) { if (!interval.lower.has_value() && !interval.upper.has_value()) { os << "unbounded"; } else { @@ -127,19 +119,19 @@ void print(std::ostream& os, std::size_t size, const value_t* values) { // fixed and variable number of generic values -void Options::detail::parseDoublesFixed(std::istream& is, +void ActsHelper::Options::detail::parseDoublesFixed(std::istream& is, std::size_t size, double* values) { parseFixed(is, size, values, [](const std::string& s) { return std::stod(s); }); } -void Options::detail::parseDoublesVariable( +void ActsHelper::Options::detail::parseDoublesVariable( std::istream& is, std::vector<double>& values) { parseVariable(is, values, [](const std::string& s) { return std::stod(s); }); } -void Options::detail::printDoubles(std::ostream& os, +void ActsHelper::Options::detail::printDoubles(std::ostream& os, std::size_t size, const double* values) { print(os, size, values); @@ -147,19 +139,19 @@ void Options::detail::printDoubles(std::ostream& os, // fixed and variable number of integers -void Options::detail::parseIntegersFixed(std::istream& is, +void ActsHelper::Options::detail::parseIntegersFixed(std::istream& is, std::size_t size, int* values) { parseFixed(is, size, values, [](const std::string& s) { return std::stoi(s); }); } -void Options::detail::parseIntegersVariable( +void ActsHelper::Options::detail::parseIntegersVariable( std::istream& is, std::vector<int>& values) { parseVariable(is, values, [](const std::string& s) { return std::stoi(s); }); } -void Options::detail::printIntegers(std::ostream& os, +void ActsHelper::Options::detail::printIntegers(std::ostream& os, std::size_t size, const int* values) { print(os, size, values); diff --git a/Reconstruction/RecActsTracking/ActsHelper/src/Utilities/Paths.cpp b/Reconstruction/RecActsTracking/ActsHelper/src/Utilities/Paths.cpp new file mode 100644 index 00000000..b41f4a15 --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/src/Utilities/Paths.cpp @@ -0,0 +1,108 @@ +#include "ActsHelper/Utilities/Paths.hpp" + +#include "Acts/Utilities/Logger.hpp" + +#include <algorithm> +#include <charconv> +#include <cstdint> +#include <cstdio> +#include <filesystem> +#include <map> +#include <regex> +#include <sstream> +#include <stdexcept> +#include <type_traits> +#include <vector> + +std::string ActsHelper::ensureWritableDirectory(const std::string& dir) { + using std::filesystem::current_path; + using std::filesystem::path; + + auto dir_path = dir.empty() ? current_path() : path(dir); + if (exists(dir_path) && !is_directory(dir_path)) { + throw std::runtime_error("'" + dir + + "' already exists but is not a directory"); + } + create_directories(dir_path); + return canonical(dir_path).native(); +} + +std::string ActsHelper::joinPaths(const std::string& dir, + const std::string& name) { + if (dir.empty()) { + return name; + } else { + return dir + '/' + name; + } +} + +std::string ActsHelper::perEventFilepath(const std::string& dir, + const std::string& name, + std::size_t event) { + char prefix[64]; + + snprintf(prefix, sizeof(prefix), "event%09zu-", event); + + if (dir.empty()) { + return prefix + name; + } else { + return dir + '/' + prefix + name; + } +} + +std::pair<std::size_t, std::size_t> ActsHelper::determineEventFilesRange( + const std::string& dir, const std::string& name) { + using std::filesystem::current_path; + using std::filesystem::directory_iterator; + using std::filesystem::path; + + ACTS_LOCAL_LOGGER( + Acts::getDefaultLogger("EventFilesRange", Acts::Logging::INFO)); + + // ensure directory path is valid + auto dir_path = dir.empty() ? current_path() : path(dir); + if (!exists(dir_path)) { + throw std::runtime_error("'" + dir_path.native() + "' does not exists"); + } + if (!is_directory(dir_path)) { + throw std::runtime_error("'" + dir_path.native() + "' is not a directory"); + } + + // invalid default range that allows simple restriction later on + std::size_t eventMin = SIZE_MAX; + std::size_t eventMax = 0; + + // filter matching event files from the directory listing + std::string filename; + std::regex re("^event([0-9]+)-" + name + "$"); + std::cmatch match; + + for (const auto& f : directory_iterator(dir_path)) { + if ((!exists(f.status())) || (!is_regular_file(f.status()))) { + continue; + } + // keep a copy so the match can refer to the underlying const char* + filename = f.path().filename().native(); + if (std::regex_match(filename.c_str(), match, re)) { + ACTS_VERBOSE("Matching file " << filename); + + // first sub_match is the whole string, second should be the event number + std::size_t event = 0; + auto ret = std::from_chars(match[1].first, match[1].second, event); + if (ret.ptr == match[1].first) { + throw std::runtime_error( + "Could not extract event number from filename"); + } + // enlarge available event range + eventMin = std::min(eventMin, event); + eventMax = std::max(eventMax, event); + } + } + ACTS_VERBOSE("Detected event range [" << eventMin << "," << eventMax << "]"); + + // should only occur if no files matched and the initial values persisted. + if (eventMax < eventMin) { + return std::make_pair(0u, 0u); + } + return std::make_pair(eventMin, eventMax + 1); +} diff --git a/Reconstruction/RecActsTracking/ActsHelper/src/Validation/DuplicationPlotTool.cpp b/Reconstruction/RecActsTracking/ActsHelper/src/Validation/DuplicationPlotTool.cpp new file mode 100644 index 00000000..d90241d8 --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/src/Validation/DuplicationPlotTool.cpp @@ -0,0 +1,105 @@ +#include "ActsHelper/Validation/DuplicationPlotTool.hpp" + +#include "Acts/Definitions/Algebra.hpp" +#include "Acts/Utilities/VectorHelpers.hpp" +#include "ActsFatras/EventData/Particle.hpp" + +#include <TEfficiency.h> +#include <TProfile.h> + +using Acts::VectorHelpers::eta; +using Acts::VectorHelpers::perp; +using Acts::VectorHelpers::phi; +using Acts::VectorHelpers::theta; + +ActsHelper::DuplicationPlotTool::DuplicationPlotTool( + const ActsHelper::DuplicationPlotTool::Config& cfg, + Acts::Logging::Level lvl) + : m_cfg(cfg), + m_logger(Acts::getDefaultLogger("DuplicationPlotTool", lvl)) {} + +void ActsHelper::DuplicationPlotTool::book( + DuplicationPlotTool::DuplicationPlotCache& duplicationPlotCache) const { + PlotHelpers::Binning bPt = m_cfg.varBinning.at("Pt"); + PlotHelpers::Binning bEta = m_cfg.varBinning.at("Eta"); + PlotHelpers::Binning bPhi = m_cfg.varBinning.at("Phi"); + PlotHelpers::Binning bNum = m_cfg.varBinning.at("Num"); + ACTS_DEBUG("Initialize the histograms for duplication rate plots"); + + // duplication rate vs pT + duplicationPlotCache.duplicationRate_vs_pT = + PlotHelpers::bookEff("duplicationRate_vs_pT", + "Duplication rate;pT [GeV/c];Duplication rate", bPt); + // duplication rate vs eta + duplicationPlotCache.duplicationRate_vs_eta = PlotHelpers::bookEff( + "duplicationRate_vs_eta", "Duplication rate;#eta;Duplication rate", bEta); + // duplication rate vs phi + duplicationPlotCache.duplicationRate_vs_phi = PlotHelpers::bookEff( + "duplicationRate_vs_phi", "Duplication rate;#phi;Duplication rate", bPhi); + + // duplication number vs pT + duplicationPlotCache.nDuplicated_vs_pT = PlotHelpers::bookProf( + "nDuplicated_vs_pT", "Number of duplicated track candidates", bPt, bNum); + // duplication number vs eta + duplicationPlotCache.nDuplicated_vs_eta = PlotHelpers::bookProf( + "nDuplicated_vs_eta", "Number of duplicated track candidates", bEta, + bNum); + // duplication number vs phi + duplicationPlotCache.nDuplicated_vs_phi = PlotHelpers::bookProf( + "nDuplicated_vs_phi", "Number of duplicated track candidates", bPhi, + bNum); +} + +void ActsHelper::DuplicationPlotTool::clear( + DuplicationPlotCache& duplicationPlotCache) const { + delete duplicationPlotCache.duplicationRate_vs_pT; + delete duplicationPlotCache.duplicationRate_vs_eta; + delete duplicationPlotCache.duplicationRate_vs_phi; + delete duplicationPlotCache.nDuplicated_vs_pT; + delete duplicationPlotCache.nDuplicated_vs_eta; + delete duplicationPlotCache.nDuplicated_vs_phi; +} + +void ActsHelper::DuplicationPlotTool::write( + const DuplicationPlotTool::DuplicationPlotCache& duplicationPlotCache) + const { + ACTS_DEBUG("Write the plots to output file."); + duplicationPlotCache.duplicationRate_vs_pT->Write(); + duplicationPlotCache.duplicationRate_vs_eta->Write(); + duplicationPlotCache.duplicationRate_vs_phi->Write(); + duplicationPlotCache.nDuplicated_vs_pT->Write(); + duplicationPlotCache.nDuplicated_vs_eta->Write(); + duplicationPlotCache.nDuplicated_vs_phi->Write(); +} + +void ActsHelper::DuplicationPlotTool::fill( + DuplicationPlotTool::DuplicationPlotCache& duplicationPlotCache, + const Acts::BoundTrackParameters& fittedParameters, bool status) const { + const auto momentum = fittedParameters.momentum(); + const double fit_phi = phi(momentum); + const double fit_eta = eta(momentum); + const double fit_pT = perp(momentum); + + PlotHelpers::fillEff(duplicationPlotCache.duplicationRate_vs_pT, fit_pT, + status); + PlotHelpers::fillEff(duplicationPlotCache.duplicationRate_vs_eta, fit_eta, + status); + PlotHelpers::fillEff(duplicationPlotCache.duplicationRate_vs_phi, fit_phi, + status); +} + +void ActsHelper::DuplicationPlotTool::fill( + DuplicationPlotTool::DuplicationPlotCache& duplicationPlotCache, + const ActsFatras::Particle& truthParticle, + std::size_t nDuplicatedTracks) const { + const auto t_phi = phi(truthParticle.direction()); + const auto t_eta = eta(truthParticle.direction()); + const auto t_pT = truthParticle.transverseMomentum(); + + PlotHelpers::fillProf(duplicationPlotCache.nDuplicated_vs_pT, t_pT, + nDuplicatedTracks); + PlotHelpers::fillProf(duplicationPlotCache.nDuplicated_vs_eta, t_eta, + nDuplicatedTracks); + PlotHelpers::fillProf(duplicationPlotCache.nDuplicated_vs_phi, t_phi, + nDuplicatedTracks); +} diff --git a/Reconstruction/RecActsTracking/ActsHelper/src/Validation/EffPlotTool.cpp b/Reconstruction/RecActsTracking/ActsHelper/src/Validation/EffPlotTool.cpp new file mode 100644 index 00000000..fd1314ad --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/src/Validation/EffPlotTool.cpp @@ -0,0 +1,66 @@ +#include "ActsHelper/Validation/EffPlotTool.hpp" + +#include "Acts/Utilities/VectorHelpers.hpp" +#include "ActsFatras/EventData/Particle.hpp" + +#include <TEfficiency.h> + +using Acts::VectorHelpers::eta; +using Acts::VectorHelpers::perp; +using Acts::VectorHelpers::phi; + +ActsHelper::EffPlotTool::EffPlotTool( + const ActsHelper::EffPlotTool::Config& cfg, Acts::Logging::Level lvl) + : m_cfg(cfg), m_logger(Acts::getDefaultLogger("EffPlotTool", lvl)) {} + +void ActsHelper::EffPlotTool::book( + EffPlotTool::EffPlotCache& effPlotCache) const { + PlotHelpers::Binning bPhi = m_cfg.varBinning.at("Phi"); + PlotHelpers::Binning bEta = m_cfg.varBinning.at("Eta"); + PlotHelpers::Binning bPt = m_cfg.varBinning.at("Pt"); + PlotHelpers::Binning bDeltaR = m_cfg.varBinning.at("DeltaR"); + ACTS_DEBUG("Initialize the histograms for efficiency plots"); + // efficiency vs pT + effPlotCache.trackEff_vs_pT = PlotHelpers::bookEff( + "trackeff_vs_pT", "Tracking efficiency;Truth pT [GeV/c];Efficiency", bPt); + // efficiency vs eta + effPlotCache.trackEff_vs_eta = PlotHelpers::bookEff( + "trackeff_vs_eta", "Tracking efficiency;Truth #eta;Efficiency", bEta); + // efficiency vs phi + effPlotCache.trackEff_vs_phi = PlotHelpers::bookEff( + "trackeff_vs_phi", "Tracking efficiency;Truth #phi;Efficiency", bPhi); + // efficiancy vs distance to the closest truth particle + effPlotCache.trackEff_vs_DeltaR = PlotHelpers::bookEff( + "trackeff_vs_DeltaR", + "Tracking efficiency;Closest track #Delta R;Efficiency", bDeltaR); +} + +void ActsHelper::EffPlotTool::clear(EffPlotCache& effPlotCache) const { + delete effPlotCache.trackEff_vs_pT; + delete effPlotCache.trackEff_vs_eta; + delete effPlotCache.trackEff_vs_phi; + delete effPlotCache.trackEff_vs_DeltaR; +} + +void ActsHelper::EffPlotTool::write( + const EffPlotTool::EffPlotCache& effPlotCache) const { + ACTS_DEBUG("Write the plots to output file."); + effPlotCache.trackEff_vs_pT->Write(); + effPlotCache.trackEff_vs_eta->Write(); + effPlotCache.trackEff_vs_phi->Write(); + effPlotCache.trackEff_vs_DeltaR->Write(); +} + +void ActsHelper::EffPlotTool::fill(EffPlotTool::EffPlotCache& effPlotCache, + const ActsFatras::Particle& truthParticle, + double deltaR, bool status) const { + const auto t_phi = phi(truthParticle.direction()); + const auto t_eta = eta(truthParticle.direction()); + const auto t_pT = truthParticle.transverseMomentum(); + const auto t_deltaR = deltaR; + + PlotHelpers::fillEff(effPlotCache.trackEff_vs_pT, t_pT, status); + PlotHelpers::fillEff(effPlotCache.trackEff_vs_eta, t_eta, status); + PlotHelpers::fillEff(effPlotCache.trackEff_vs_phi, t_phi, status); + PlotHelpers::fillEff(effPlotCache.trackEff_vs_DeltaR, t_deltaR, status); +} diff --git a/Reconstruction/RecActsTracking/ActsHelper/src/Validation/FakeRatePlotTool.cpp b/Reconstruction/RecActsTracking/ActsHelper/src/Validation/FakeRatePlotTool.cpp new file mode 100644 index 00000000..2a0c0f0d --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/src/Validation/FakeRatePlotTool.cpp @@ -0,0 +1,120 @@ +#include "ActsHelper/Validation/FakeRatePlotTool.hpp" + +#include "Acts/Definitions/Algebra.hpp" +#include "Acts/Utilities/VectorHelpers.hpp" +#include "ActsFatras/EventData/Particle.hpp" + +#include <TEfficiency.h> +#include <TH2.h> + +using Acts::VectorHelpers::eta; +using Acts::VectorHelpers::perp; +using Acts::VectorHelpers::phi; +using Acts::VectorHelpers::theta; + +ActsHelper::FakeRatePlotTool::FakeRatePlotTool( + const ActsHelper::FakeRatePlotTool::Config& cfg, Acts::Logging::Level lvl) + : m_cfg(cfg), m_logger(Acts::getDefaultLogger("FakeRatePlotTool", lvl)) {} + +void ActsHelper::FakeRatePlotTool::book( + FakeRatePlotTool::FakeRatePlotCache& fakeRatePlotCache) const { + PlotHelpers::Binning bPt = m_cfg.varBinning.at("Pt"); + PlotHelpers::Binning bEta = m_cfg.varBinning.at("Eta"); + PlotHelpers::Binning bPhi = m_cfg.varBinning.at("Phi"); + PlotHelpers::Binning bNum = m_cfg.varBinning.at("Num"); + ACTS_DEBUG("Initialize the histograms for fake rate plots"); + + // number of reco tracks vs pT scatter plots + fakeRatePlotCache.nReco_vs_pT = PlotHelpers::bookHisto( + "nRecoTracks_vs_pT", "Number of reconstructed track candidates", bPt, + bNum); + // number of truth-matched tracks vs pT scatter plots + fakeRatePlotCache.nTruthMatched_vs_pT = PlotHelpers::bookHisto( + "nTruthMatchedTracks_vs_pT", "Number of truth-matched track candidates", + bPt, bNum); + // number of fake tracks vs pT scatter plots + fakeRatePlotCache.nFake_vs_pT = PlotHelpers::bookHisto( + "nFakeTracks_vs_pT", "Number of fake track candidates", bPt, bNum); + + // number of reco tracks vs eta scatter plots + fakeRatePlotCache.nReco_vs_eta = PlotHelpers::bookHisto( + "nRecoTracks_vs_eta", "Number of reconstructed track candidates", bEta, + bNum); + // number of truth-matched tracks vs eta scatter plots + fakeRatePlotCache.nTruthMatched_vs_eta = PlotHelpers::bookHisto( + "nTruthMatchedTracks_vs_eta", "Number of truth-matched track candidates", + bEta, bNum); + // number of fake tracks vs eta scatter plots + fakeRatePlotCache.nFake_vs_eta = PlotHelpers::bookHisto( + "nFakeTracks_vs_eta", "Number of fake track candidates", bEta, bNum); + + // fake rate vs pT + fakeRatePlotCache.fakeRate_vs_pT = PlotHelpers::bookEff( + "fakerate_vs_pT", "Tracking fake rate;pT [GeV/c];Fake rate", bPt); + // fake rate vs eta + fakeRatePlotCache.fakeRate_vs_eta = PlotHelpers::bookEff( + "fakerate_vs_eta", "Tracking fake rate;#eta;Fake rate", bEta); + // fake rate vs phi + fakeRatePlotCache.fakeRate_vs_phi = PlotHelpers::bookEff( + "fakerate_vs_phi", "Tracking fake rate;#phi;Fake rate", bPhi); +} + +void ActsHelper::FakeRatePlotTool::clear( + FakeRatePlotCache& fakeRatePlotCache) const { + delete fakeRatePlotCache.nReco_vs_pT; + delete fakeRatePlotCache.nTruthMatched_vs_pT; + delete fakeRatePlotCache.nFake_vs_pT; + delete fakeRatePlotCache.nReco_vs_eta; + delete fakeRatePlotCache.nTruthMatched_vs_eta; + delete fakeRatePlotCache.nFake_vs_eta; + delete fakeRatePlotCache.fakeRate_vs_pT; + delete fakeRatePlotCache.fakeRate_vs_eta; + delete fakeRatePlotCache.fakeRate_vs_phi; +} + +void ActsHelper::FakeRatePlotTool::write( + const FakeRatePlotTool::FakeRatePlotCache& fakeRatePlotCache) const { + ACTS_DEBUG("Write the plots to output file."); + fakeRatePlotCache.nReco_vs_pT->Write(); + fakeRatePlotCache.nTruthMatched_vs_pT->Write(); + fakeRatePlotCache.nFake_vs_pT->Write(); + fakeRatePlotCache.nReco_vs_eta->Write(); + fakeRatePlotCache.nTruthMatched_vs_eta->Write(); + fakeRatePlotCache.nFake_vs_eta->Write(); + fakeRatePlotCache.fakeRate_vs_pT->Write(); + fakeRatePlotCache.fakeRate_vs_eta->Write(); + fakeRatePlotCache.fakeRate_vs_phi->Write(); +} + +void ActsHelper::FakeRatePlotTool::fill( + FakeRatePlotTool::FakeRatePlotCache& fakeRatePlotCache, + const Acts::BoundTrackParameters& fittedParameters, bool status) const { + const auto momentum = fittedParameters.momentum(); + const double fit_phi = phi(momentum); + const double fit_eta = eta(momentum); + const double fit_pT = perp(momentum); + + PlotHelpers::fillEff(fakeRatePlotCache.fakeRate_vs_pT, fit_pT, status); + PlotHelpers::fillEff(fakeRatePlotCache.fakeRate_vs_eta, fit_eta, status); + PlotHelpers::fillEff(fakeRatePlotCache.fakeRate_vs_phi, fit_phi, status); +} + +void ActsHelper::FakeRatePlotTool::fill( + FakeRatePlotTool::FakeRatePlotCache& fakeRatePlotCache, + const ActsFatras::Particle& truthParticle, std::size_t nTruthMatchedTracks, + std::size_t nFakeTracks) const { + const auto t_eta = eta(truthParticle.direction()); + const auto t_pT = truthParticle.transverseMomentum(); + + PlotHelpers::fillHisto(fakeRatePlotCache.nReco_vs_pT, t_pT, + nTruthMatchedTracks + nFakeTracks); + PlotHelpers::fillHisto(fakeRatePlotCache.nTruthMatched_vs_pT, t_pT, + nTruthMatchedTracks); + PlotHelpers::fillHisto(fakeRatePlotCache.nFake_vs_pT, t_pT, nFakeTracks); + + PlotHelpers::fillHisto(fakeRatePlotCache.nReco_vs_eta, t_eta, + nTruthMatchedTracks + nFakeTracks); + PlotHelpers::fillHisto(fakeRatePlotCache.nTruthMatched_vs_eta, t_eta, + nTruthMatchedTracks); + PlotHelpers::fillHisto(fakeRatePlotCache.nFake_vs_eta, t_eta, nFakeTracks); +} diff --git a/Reconstruction/RecActsTracking/ActsHelper/src/Validation/ResPlotTool.cpp b/Reconstruction/RecActsTracking/ActsHelper/src/Validation/ResPlotTool.cpp new file mode 100644 index 00000000..b2bb31e0 --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/src/Validation/ResPlotTool.cpp @@ -0,0 +1,249 @@ +#include "ActsHelper/Validation/ResPlotTool.hpp" + +#include "Acts/Definitions/TrackParametrization.hpp" +#include "Acts/Surfaces/Surface.hpp" +#include "Acts/Utilities/Helpers.hpp" +#include "Acts/Utilities/Result.hpp" +#include "ActsFatras/EventData/Particle.hpp" + +#include <algorithm> +#include <cmath> +#include <optional> +#include <ostream> + +#include <TH1.h> +#include <TH2.h> +#include <TString.h> + +ActsHelper::ResPlotTool::ResPlotTool( + const ActsHelper::ResPlotTool::Config& cfg, Acts::Logging::Level lvl) + : m_cfg(cfg), m_logger(Acts::getDefaultLogger("ResPlotTool", lvl)) {} + +void ActsHelper::ResPlotTool::book( + ResPlotTool::ResPlotCache& resPlotCache) const { + PlotHelpers::Binning bEta = m_cfg.varBinning.at("Eta"); + PlotHelpers::Binning bPt = m_cfg.varBinning.at("Pt"); + PlotHelpers::Binning bPull = m_cfg.varBinning.at("Pull"); + + ACTS_DEBUG("Initialize the histograms for residual and pull plots"); + for (unsigned int parID = 0; parID < Acts::eBoundSize; parID++) { + std::string parName = m_cfg.paramNames.at(parID); + + std::string parResidual = "Residual_" + parName; + // Binning for residual is parameter dependent + PlotHelpers::Binning bResidual = m_cfg.varBinning.at(parResidual); + + // residual distributions + resPlotCache.res[parName] = PlotHelpers::bookHisto( + Form("res_%s", parName.c_str()), + Form("Residual of %s", parName.c_str()), bResidual); + // residual vs eta scatter plots + resPlotCache.res_vs_eta[parName] = PlotHelpers::bookHisto( + Form("res_%s_vs_eta", parName.c_str()), + Form("Residual of %s vs eta", parName.c_str()), bEta, bResidual); + // residual mean in each eta bin + resPlotCache.resMean_vs_eta[parName] = PlotHelpers::bookHisto( + Form("resmean_%s_vs_eta", parName.c_str()), + Form("Residual mean of %s", parName.c_str()), bEta); + // residual width in each eta bin + resPlotCache.resWidth_vs_eta[parName] = PlotHelpers::bookHisto( + Form("reswidth_%s_vs_eta", parName.c_str()), + Form("Residual width of %s", parName.c_str()), bEta); + // residual vs pT scatter plots + resPlotCache.res_vs_pT[parName] = PlotHelpers::bookHisto( + Form("res_%s_vs_pT", parName.c_str()), + Form("Residual of %s vs pT", parName.c_str()), bPt, bResidual); + // residual mean in each pT bin + resPlotCache.resMean_vs_pT[parName] = PlotHelpers::bookHisto( + Form("resmean_%s_vs_pT", parName.c_str()), + Form("Residual mean of %s", parName.c_str()), bPt); + // residual width in each pT bin + resPlotCache.resWidth_vs_pT[parName] = PlotHelpers::bookHisto( + Form("reswidth_%s_vs_pT", parName.c_str()), + Form("Residual width of %s", parName.c_str()), bPt); + + // pull distritutions + resPlotCache.pull[parName] = + PlotHelpers::bookHisto(Form("pull_%s", parName.c_str()), + Form("Pull of %s", parName.c_str()), bPull); + // pull vs eta scatter plots + resPlotCache.pull_vs_eta[parName] = PlotHelpers::bookHisto( + Form("pull_%s_vs_eta", parName.c_str()), + Form("Pull of %s vs eta", parName.c_str()), bEta, bPull); + // pull mean in each eta bin + resPlotCache.pullMean_vs_eta[parName] = + PlotHelpers::bookHisto(Form("pullmean_%s_vs_eta", parName.c_str()), + Form("Pull mean of %s", parName.c_str()), bEta); + // pull width in each eta bin + resPlotCache.pullWidth_vs_eta[parName] = + PlotHelpers::bookHisto(Form("pullwidth_%s_vs_eta", parName.c_str()), + Form("Pull width of %s", parName.c_str()), bEta); + // pull vs pT scatter plots + resPlotCache.pull_vs_pT[parName] = PlotHelpers::bookHisto( + Form("pull_%s_vs_pT", parName.c_str()), + Form("Pull of %s vs pT", parName.c_str()), bPt, bPull); + // pull mean in each pT bin + resPlotCache.pullMean_vs_pT[parName] = + PlotHelpers::bookHisto(Form("pullmean_%s_vs_pT", parName.c_str()), + Form("Pull mean of %s", parName.c_str()), bPt); + // pull width in each pT bin + resPlotCache.pullWidth_vs_pT[parName] = + PlotHelpers::bookHisto(Form("pullwidth_%s_vs_pT", parName.c_str()), + Form("Pull width of %s", parName.c_str()), bPt); + } +} + +void ActsHelper::ResPlotTool::clear(ResPlotCache& resPlotCache) const { + ACTS_DEBUG("Delete the hists."); + for (unsigned int parID = 0; parID < Acts::eBoundSize; parID++) { + std::string parName = m_cfg.paramNames.at(parID); + delete resPlotCache.res.at(parName); + delete resPlotCache.res_vs_eta.at(parName); + delete resPlotCache.resMean_vs_eta.at(parName); + delete resPlotCache.resWidth_vs_eta.at(parName); + delete resPlotCache.res_vs_pT.at(parName); + delete resPlotCache.resMean_vs_pT.at(parName); + delete resPlotCache.resWidth_vs_pT.at(parName); + delete resPlotCache.pull.at(parName); + delete resPlotCache.pull_vs_eta.at(parName); + delete resPlotCache.pullMean_vs_eta.at(parName); + delete resPlotCache.pullWidth_vs_eta.at(parName); + delete resPlotCache.pull_vs_pT.at(parName); + delete resPlotCache.pullMean_vs_pT.at(parName); + delete resPlotCache.pullWidth_vs_pT.at(parName); + } +} + +void ActsHelper::ResPlotTool::write( + const ResPlotTool::ResPlotCache& resPlotCache) const { + ACTS_DEBUG("Write the hists to output file."); + for (unsigned int parID = 0; parID < Acts::eBoundSize; parID++) { + std::string parName = m_cfg.paramNames.at(parID); + resPlotCache.res.at(parName)->Write(); + resPlotCache.res_vs_eta.at(parName)->Write(); + resPlotCache.resMean_vs_eta.at(parName)->Write(); + resPlotCache.resWidth_vs_eta.at(parName)->Write(); + resPlotCache.res_vs_pT.at(parName)->Write(); + resPlotCache.resMean_vs_pT.at(parName)->Write(); + resPlotCache.resWidth_vs_pT.at(parName)->Write(); + resPlotCache.pull.at(parName)->Write(); + resPlotCache.pull_vs_eta.at(parName)->Write(); + resPlotCache.pullMean_vs_eta.at(parName)->Write(); + resPlotCache.pullWidth_vs_eta.at(parName)->Write(); + resPlotCache.pull_vs_pT.at(parName)->Write(); + resPlotCache.pullMean_vs_pT.at(parName)->Write(); + resPlotCache.pullWidth_vs_pT.at(parName)->Write(); + } +} + +void ActsHelper::ResPlotTool::fill( + ResPlotTool::ResPlotCache& resPlotCache, const Acts::GeometryContext& gctx, + const ActsFatras::Particle& truthParticle, + const Acts::BoundTrackParameters& fittedParamters) const { + using ParametersVector = Acts::BoundTrackParameters::ParametersVector; + using Acts::VectorHelpers::eta; + using Acts::VectorHelpers::perp; + using Acts::VectorHelpers::phi; + using Acts::VectorHelpers::theta; + + // get the fitted parameter (at perigee surface) and its error + auto trackParameter = fittedParamters.parameters(); + + // get the perigee surface + auto pSurface = &fittedParamters.referenceSurface(); + + // get the truth position and momentum + ParametersVector truthParameter = ParametersVector::Zero(); + + // get the truth perigee parameter + auto lpResult = pSurface->globalToLocal(gctx, truthParticle.position(), + truthParticle.direction()); + if (lpResult.ok()) { + truthParameter[Acts::BoundIndices::eBoundLoc0] = + lpResult.value()[Acts::BoundIndices::eBoundLoc0]; + truthParameter[Acts::BoundIndices::eBoundLoc1] = + lpResult.value()[Acts::BoundIndices::eBoundLoc1]; + } else { + ACTS_ERROR("Global to local transformation did not succeed."); + } + truthParameter[Acts::BoundIndices::eBoundPhi] = + phi(truthParticle.direction()); + truthParameter[Acts::BoundIndices::eBoundTheta] = + theta(truthParticle.direction()); + truthParameter[Acts::BoundIndices::eBoundQOverP] = + truthParticle.charge() / truthParticle.absoluteMomentum(); + truthParameter[Acts::BoundIndices::eBoundTime] = truthParticle.time(); + + // get the truth eta and pT + const auto truthEta = eta(truthParticle.direction()); + const auto truthPt = truthParticle.transverseMomentum(); + + // fill the histograms for residual and pull + for (unsigned int parID = 0; parID < Acts::eBoundSize; parID++) { + std::string parName = m_cfg.paramNames.at(parID); + float residual = trackParameter[parID] - truthParameter[parID]; + PlotHelpers::fillHisto(resPlotCache.res.at(parName), residual); + PlotHelpers::fillHisto(resPlotCache.res_vs_eta.at(parName), truthEta, + residual); + PlotHelpers::fillHisto(resPlotCache.res_vs_pT.at(parName), truthPt, + residual); + + if (fittedParamters.covariance().has_value()) { + auto covariance = *fittedParamters.covariance(); + if (covariance(parID, parID) > 0) { + float pull = residual / sqrt(covariance(parID, parID)); + PlotHelpers::fillHisto(resPlotCache.pull[parName], pull); + PlotHelpers::fillHisto(resPlotCache.pull_vs_eta.at(parName), truthEta, + pull); + PlotHelpers::fillHisto(resPlotCache.pull_vs_pT.at(parName), truthPt, + pull); + } else { + ACTS_WARNING("Fitted track parameter :" << parName + << " has negative covariance = " + << covariance(parID, parID)); + } + } else { + ACTS_WARNING("Fitted track parameter :" << parName + << " has no covariance"); + } + } +} + +// get the mean and width of residual/pull in each eta/pT bin and fill them into +// histograms +void ActsHelper::ResPlotTool::refinement( + ResPlotTool::ResPlotCache& resPlotCache) const { + PlotHelpers::Binning bEta = m_cfg.varBinning.at("Eta"); + PlotHelpers::Binning bPt = m_cfg.varBinning.at("Pt"); + for (unsigned int parID = 0; parID < Acts::eBoundSize; parID++) { + std::string parName = m_cfg.paramNames.at(parID); + // refine the plots vs eta + for (int j = 1; j <= static_cast<int>(bEta.nBins()); j++) { + TH1D* temp_res = resPlotCache.res_vs_eta.at(parName)->ProjectionY( + Form("%s_projy_bin%d", "Residual_vs_eta_Histo", j), j, j); + PlotHelpers::anaHisto(temp_res, j, + resPlotCache.resMean_vs_eta.at(parName), + resPlotCache.resWidth_vs_eta.at(parName)); + + TH1D* temp_pull = resPlotCache.pull_vs_eta.at(parName)->ProjectionY( + Form("%s_projy_bin%d", "Pull_vs_eta_Histo", j), j, j); + PlotHelpers::anaHisto(temp_pull, j, + resPlotCache.pullMean_vs_eta.at(parName), + resPlotCache.pullWidth_vs_eta.at(parName)); + } + + // refine the plots vs pT + for (int j = 1; j <= static_cast<int>(bPt.nBins()); j++) { + TH1D* temp_res = resPlotCache.res_vs_pT.at(parName)->ProjectionY( + Form("%s_projy_bin%d", "Residual_vs_pT_Histo", j), j, j); + PlotHelpers::anaHisto(temp_res, j, resPlotCache.resMean_vs_pT.at(parName), + resPlotCache.resWidth_vs_pT.at(parName)); + + TH1D* temp_pull = resPlotCache.pull_vs_pT.at(parName)->ProjectionY( + Form("%s_projy_bin%d", "Pull_vs_pT_Histo", j), j, j); + PlotHelpers::anaHisto(temp_pull, j, + resPlotCache.pullMean_vs_pT.at(parName), + resPlotCache.pullWidth_vs_pT.at(parName)); + } + } +} diff --git a/Reconstruction/RecActsTracking/ActsHelper/src/Validation/TrackClassification.cpp b/Reconstruction/RecActsTracking/ActsHelper/src/Validation/TrackClassification.cpp new file mode 100644 index 00000000..4f2efedf --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/src/Validation/TrackClassification.cpp @@ -0,0 +1,106 @@ +#include "ActsHelper/Validation/TrackClassification.hpp" + +#include "Acts/EventData/MultiTrajectory.hpp" +#include "Acts/Utilities/MultiIndex.hpp" +#include "ActsHelper/EventData/IndexSourceLink.hpp" +#include "ActsHelper/EventData/Track.hpp" +#include "ActsHelper/EventData/Trajectories.hpp" +#include "ActsHelper/Utilities/Range.hpp" + +#include <algorithm> +#include <utility> + +namespace { + +/// Increase the hit count for the given particle id by one. +inline void increaseHitCount( + std::vector<ActsHelper::ParticleHitCount>& particleHitCounts, + ActsFatras::Barcode particleId) { + // linear search since there is no ordering + auto it = std::find_if(particleHitCounts.begin(), particleHitCounts.end(), + [=](const ActsHelper::ParticleHitCount& phc) { + return (phc.particleId == particleId); + }); + // either increase count if we saw the particle before or add it + if (it != particleHitCounts.end()) { + it->hitCount += 1u; + } else { + particleHitCounts.push_back({particleId, 1u}); + } +} + +/// Sort hit counts by decreasing values, i.e. majority particle comes first. +inline void sortHitCount( + std::vector<ActsHelper::ParticleHitCount>& particleHitCounts) { + std::sort(particleHitCounts.begin(), particleHitCounts.end(), + [](const ActsHelper::ParticleHitCount& lhs, + const ActsHelper::ParticleHitCount& rhs) { + return (lhs.hitCount > rhs.hitCount); + }); +} + +} // namespace + +void ActsHelper::identifyContributingParticles( + const IndexMultimap<ActsFatras::Barcode>& hitParticlesMap, + const ProtoTrack& protoTrack, + std::vector<ActsHelper::ParticleHitCount>& particleHitCounts) { + particleHitCounts.clear(); + + for (auto hitIndex : protoTrack) { + // register all particles that generated this hit + for (auto hitParticle : makeRange(hitParticlesMap.equal_range(hitIndex))) { + increaseHitCount(particleHitCounts, hitParticle.second); + } + } + sortHitCount(particleHitCounts); +} + +void ActsHelper::identifyContributingParticles( + const IndexMultimap<ActsFatras::Barcode>& hitParticlesMap, + const Trajectories& trajectories, std::size_t tip, + std::vector<ParticleHitCount>& particleHitCounts) { + particleHitCounts.clear(); + + if (!trajectories.hasTrajectory(tip)) { + return; + } + + trajectories.multiTrajectory().visitBackwards(tip, [&](const auto& state) { + // no truth info with non-measurement state + if (!state.typeFlags().test(Acts::TrackStateFlag::MeasurementFlag)) { + return true; + } + // register all particles that generated this hit + IndexSourceLink sl = + state.getUncalibratedSourceLink().template get<IndexSourceLink>(); + auto hitIndex = sl.index(); + for (auto hitParticle : makeRange(hitParticlesMap.equal_range(hitIndex))) { + increaseHitCount(particleHitCounts, hitParticle.second); + } + return true; + }); + sortHitCount(particleHitCounts); +} + +void ActsHelper::identifyContributingParticles( + const IndexMultimap<ActsFatras::Barcode>& hitParticlesMap, + const ConstTrackContainer::ConstTrackProxy& track, + std::vector<ParticleHitCount>& particleHitCounts) { + particleHitCounts.clear(); + + for (const auto& state : track.trackStatesReversed()) { + // no truth info with non-measurement state + if (!state.typeFlags().test(Acts::TrackStateFlag::MeasurementFlag)) { + continue; + } + // register all particles that generated this hit + IndexSourceLink sl = + state.getUncalibratedSourceLink().template get<IndexSourceLink>(); + auto hitIndex = sl.index(); + for (auto hitParticle : makeRange(hitParticlesMap.equal_range(hitIndex))) { + increaseHitCount(particleHitCounts, hitParticle.second); + } + } + sortHitCount(particleHitCounts); +} diff --git a/Reconstruction/RecActsTracking/ActsHelper/src/Validation/TrackSummaryPlotTool.cpp b/Reconstruction/RecActsTracking/ActsHelper/src/Validation/TrackSummaryPlotTool.cpp new file mode 100644 index 00000000..d8d685f6 --- /dev/null +++ b/Reconstruction/RecActsTracking/ActsHelper/src/Validation/TrackSummaryPlotTool.cpp @@ -0,0 +1,110 @@ +#include "ActsHelper/Validation/TrackSummaryPlotTool.hpp" + +#include "Acts/Definitions/Algebra.hpp" +#include "Acts/Utilities/VectorHelpers.hpp" + +#include <TProfile.h> + +ActsHelper::TrackSummaryPlotTool::TrackSummaryPlotTool( + const ActsHelper::TrackSummaryPlotTool::Config& cfg, + Acts::Logging::Level lvl) + : m_cfg(cfg), + m_logger(Acts::getDefaultLogger("TrackSummaryPlotTool", lvl)) {} + +void ActsHelper::TrackSummaryPlotTool::book( + TrackSummaryPlotTool::TrackSummaryPlotCache& trackSummaryPlotCache) const { + PlotHelpers::Binning bEta = m_cfg.varBinning.at("Eta"); + PlotHelpers::Binning bPt = m_cfg.varBinning.at("Pt"); + PlotHelpers::Binning bNum = m_cfg.varBinning.at("Num"); + ACTS_DEBUG("Initialize the histograms for track info plots"); + // number of track states versus eta + trackSummaryPlotCache.nStates_vs_eta = PlotHelpers::bookProf( + "nStates_vs_eta", "Number of total states vs. #eta", bEta, bNum); + // number of measurements versus eta + trackSummaryPlotCache.nMeasurements_vs_eta = PlotHelpers::bookProf( + "nMeasurements_vs_eta", "Number of measurements vs. #eta", bEta, bNum); + // number of holes versus eta + trackSummaryPlotCache.nHoles_vs_eta = PlotHelpers::bookProf( + "nHoles_vs_eta", "Number of holes vs. #eta", bEta, bNum); + // number of outliers versus eta + trackSummaryPlotCache.nOutliers_vs_eta = PlotHelpers::bookProf( + "nOutliers_vs_eta", "Number of outliers vs. #eta", bEta, bNum); + // number of Shared Hits versus eta + trackSummaryPlotCache.nSharedHits_vs_eta = PlotHelpers::bookProf( + "nSharedHits_vs_eta", "Number of Shared Hits vs. #eta", bEta, bNum); + // number of track states versus pt + trackSummaryPlotCache.nStates_vs_pt = PlotHelpers::bookProf( + "nStates_vs_pT", "Number of total states vs. pT", bPt, bNum); + // number of measurements versus pt + trackSummaryPlotCache.nMeasurements_vs_pt = PlotHelpers::bookProf( + "nMeasurements_vs_pT", "Number of measurements vs. pT", bPt, bNum); + // number of holes versus pt + trackSummaryPlotCache.nHoles_vs_pt = PlotHelpers::bookProf( + "nHoles_vs_pT", "Number of holes vs. pT", bPt, bNum); + // number of outliers versus pt + trackSummaryPlotCache.nOutliers_vs_pt = PlotHelpers::bookProf( + "nOutliers_vs_pT", "Number of outliers vs. pT", bPt, bNum); + // number of Shared Hits versus pt + trackSummaryPlotCache.nSharedHits_vs_pt = PlotHelpers::bookProf( + "nSharedHits_vs_pT", "Number of Shared Hits vs. pT", bPt, bNum); +} + +void ActsHelper::TrackSummaryPlotTool::clear( + TrackSummaryPlotCache& trackSummaryPlotCache) const { + delete trackSummaryPlotCache.nStates_vs_eta; + delete trackSummaryPlotCache.nMeasurements_vs_eta; + delete trackSummaryPlotCache.nOutliers_vs_eta; + delete trackSummaryPlotCache.nHoles_vs_eta; + delete trackSummaryPlotCache.nSharedHits_vs_eta; + delete trackSummaryPlotCache.nStates_vs_pt; + delete trackSummaryPlotCache.nMeasurements_vs_pt; + delete trackSummaryPlotCache.nOutliers_vs_pt; + delete trackSummaryPlotCache.nHoles_vs_pt; + delete trackSummaryPlotCache.nSharedHits_vs_pt; +} + +void ActsHelper::TrackSummaryPlotTool::write( + const TrackSummaryPlotTool::TrackSummaryPlotCache& trackSummaryPlotCache) + const { + ACTS_DEBUG("Write the plots to output file."); + trackSummaryPlotCache.nStates_vs_eta->Write(); + trackSummaryPlotCache.nMeasurements_vs_eta->Write(); + trackSummaryPlotCache.nOutliers_vs_eta->Write(); + trackSummaryPlotCache.nHoles_vs_eta->Write(); + trackSummaryPlotCache.nSharedHits_vs_eta->Write(); + trackSummaryPlotCache.nStates_vs_pt->Write(); + trackSummaryPlotCache.nMeasurements_vs_pt->Write(); + trackSummaryPlotCache.nOutliers_vs_pt->Write(); + trackSummaryPlotCache.nHoles_vs_pt->Write(); + trackSummaryPlotCache.nSharedHits_vs_pt->Write(); +} + +void ActsHelper::TrackSummaryPlotTool::fill( + TrackSummaryPlotTool::TrackSummaryPlotCache& trackSummaryPlotCache, + const Acts::BoundTrackParameters& fittedParameters, std::size_t nStates, + std::size_t nMeasurements, std::size_t nOutliers, std::size_t nHoles, + std::size_t nSharedHits) const { + using Acts::VectorHelpers::eta; + using Acts::VectorHelpers::perp; + const auto momentum = fittedParameters.momentum(); + const double fit_eta = eta(momentum); + const double fit_pT = perp(momentum); + + PlotHelpers::fillProf(trackSummaryPlotCache.nStates_vs_eta, fit_eta, nStates); + PlotHelpers::fillProf(trackSummaryPlotCache.nMeasurements_vs_eta, fit_eta, + nMeasurements); + PlotHelpers::fillProf(trackSummaryPlotCache.nOutliers_vs_eta, fit_eta, + nOutliers); + PlotHelpers::fillProf(trackSummaryPlotCache.nHoles_vs_eta, fit_eta, nHoles); + PlotHelpers::fillProf(trackSummaryPlotCache.nSharedHits_vs_eta, fit_eta, + nSharedHits); + + PlotHelpers::fillProf(trackSummaryPlotCache.nStates_vs_pt, fit_pT, nStates); + PlotHelpers::fillProf(trackSummaryPlotCache.nMeasurements_vs_pt, fit_pT, + nMeasurements); + PlotHelpers::fillProf(trackSummaryPlotCache.nOutliers_vs_pt, fit_pT, + nOutliers); + PlotHelpers::fillProf(trackSummaryPlotCache.nHoles_vs_pt, fit_pT, nHoles); + PlotHelpers::fillProf(trackSummaryPlotCache.nSharedHits_vs_pt, fit_pT, + nSharedHits); +} diff --git a/Reconstruction/RecActsTracking/CMakeLists.txt b/Reconstruction/RecActsTracking/CMakeLists.txt index d0c8c9d9..ca889490 100644 --- a/Reconstruction/RecActsTracking/CMakeLists.txt +++ b/Reconstruction/RecActsTracking/CMakeLists.txt @@ -1,37 +1,3 @@ -find_package(Acts COMPONENTS - Core PluginFpeMonitoring PluginGeant4 PluginJson - PluginTGeo PluginDD4hep PluginEDM4hep Fatras) - -if(NOT Acts_FOUND) - message("Acts package not found. RecActsTracking module requires Acts.") - return() -endif() - -gaudi_add_module(RecActsTracking - SOURCES - src/RecActsTracking.cpp - LINK DetInterface - k4FWCore::k4FWCore - Gaudi::GaudiAlgLib Gaudi::GaudiKernel - ${LCIO_LIBRARIES} - ${DD4hep_COMPONENT_LIBRARIES} - EDM4HEP::edm4hep EDM4HEP::edm4hepDict - ${podio_LIBRARIES} podio::podioRootIO - GearSvc ${GEAR_LIBRARIES} - ActsCore ActsPluginFpeMonitoring ActsPluginGeant4 - ActsPluginJson ActsPluginTGeo ActsPluginDD4hep - ActsPluginEDM4hep ActsFatras -) - -target_include_directories(RecActsTracking PUBLIC $ENV{ACTS}/include) - -target_include_directories(RecActsTracking PUBLIC - ${LCIO_INCLUDE_DIRS} - $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}>/include - $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>) - -install(TARGETS RecActsTracking - EXPORT CEPCSWTargets - RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT bin - LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT shlib - COMPONENT dev) +add_subdirectory(ActsHelper) +add_subdirectory(RecActsSvc) +add_subdirectory(RecActsTracking) diff --git a/Reconstruction/RecActsTracking/RecActsSvc/CMakeLists.txt b/Reconstruction/RecActsTracking/RecActsSvc/CMakeLists.txt new file mode 100644 index 00000000..6ae7ffc3 --- /dev/null +++ b/Reconstruction/RecActsTracking/RecActsSvc/CMakeLists.txt @@ -0,0 +1,34 @@ +find_package(Acts COMPONENTS + Core PluginFpeMonitoring PluginGeant4 PluginJson + PluginTGeo PluginDD4hep PluginEDM4hep Fatras) + +if(NOT Acts_FOUND) + message("Acts package not found. RecActsSvc module requires Acts.") + return() +endif() + +gaudi_add_header_only_library(RecActsSvc LINK ActsHelperLib) + +gaudi_add_module(RecActsSvcPlugins + SOURCES + src/RecActsSvc.cpp + LINK RecActsSvc + ActsHelperLib + Gaudi::GaudiKernel + ${DD4hep_COMPONENT_LIBRARIES} + EDM4HEP::edm4hep EDM4HEP::edm4hepDict + ActsCore ActsPluginFpeMonitoring ActsPluginGeant4 + ActsPluginJson ActsPluginTGeo ActsPluginDD4hep + ActsPluginEDM4hep ActsFatras +) + +target_include_directories(RecActsSvcPlugins PUBLIC $ENV{ACTS}/include) + +install(TARGETS RecActsSvc RecActsSvcPlugins + EXPORT CEPCSWTargets + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT bin + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT shlib + COMPONENT dev) + + + diff --git a/Reconstruction/RecActsTracking/RecActsSvc/include/RecActsSvc/IRecActsSvc.h b/Reconstruction/RecActsTracking/RecActsSvc/include/RecActsSvc/IRecActsSvc.h new file mode 100644 index 00000000..86501cfa --- /dev/null +++ b/Reconstruction/RecActsTracking/RecActsSvc/include/RecActsSvc/IRecActsSvc.h @@ -0,0 +1,98 @@ +#ifndef IRECACTSSVC_H +#define IRECACTSSVC_H + +#include "GaudiKernel/IService.h" +#include "GaudiKernel/MsgStream.h" + +#include "ActsHelper/Detectors/TGeoDetector.hpp" + +#include "ActsHelper/EventData/AverageSimHits.hpp" +#include "ActsHelper/EventData/Cluster.hpp" +#include "ActsHelper/EventData/DriftCircle.hpp" +#include "ActsHelper/EventData/ExtractedSimulationProcess.hpp" +#include "ActsHelper/EventData/GeometryContainers.hpp" +#include "ActsHelper/EventData/Index.hpp" +#include "ActsHelper/EventData/IndexSourceLink.hpp" +#include "ActsHelper/EventData/Measurement.hpp" +#include "ActsHelper/EventData/MeasurementCalibration.hpp" +#include "ActsHelper/EventData/ProtoTrack.hpp" +#include "ActsHelper/EventData/ProtoVertex.hpp" +#include "ActsHelper/EventData/ScalingCalibrator.hpp" +#include "ActsHelper/EventData/SimHit.hpp" +#include "ActsHelper/EventData/SimParticle.hpp" +#include "ActsHelper/EventData/SimSeed.hpp" +#include "ActsHelper/EventData/SimSpacePoint.hpp" +#include "ActsHelper/EventData/SimVertex.hpp" +#include "ActsHelper/EventData/Track.hpp" +#include "ActsHelper/EventData/Trajectories.hpp" +#include "ActsHelper/EventData/TruthMatching.hpp" +#include "ActsHelper/EventData/Vertex.hpp" + +#include "ActsHelper/MagneticField/FieldMapRootIo.hpp" +#include "ActsHelper/MagneticField/FieldMapTextIo.hpp" +#include "ActsHelper/MagneticField/MagneticField.hpp" +#include "ActsHelper/MagneticField/ScalableBField.hpp" + +#include "ActsHelper/Utilities/EventDataTransforms.hpp" +#include "ActsHelper/Utilities/GroupBy.hpp" +#include "ActsHelper/Utilities/Helpers.hpp" +#include "ActsHelper/Utilities/Options.hpp" +#include "ActsHelper/Utilities/OptionsFwd.hpp" +#include "ActsHelper/Utilities/Paths.hpp" +#include "ActsHelper/Utilities/Range.hpp" +#include "ActsHelper/Utilities/tbbWrap.hpp" + +#include "ActsHelper/Validation/DuplicationPlotTool.hpp" +#include "ActsHelper/Validation/EffPlotTool.hpp" +#include "ActsHelper/Validation/FakeRatePlotTool.hpp" +#include "ActsHelper/Validation/ResPlotTool.hpp" +#include "ActsHelper/Validation/TrackClassification.hpp" +#include "ActsHelper/Validation/TrackSummaryPlotTool.hpp" + +#include "ActsHelper/Algorithms/TrackFitting/RefittingCalibrator.hpp" +#include "ActsHelper/Algorithms/TrackFitting/TrackFitterFunction.hpp" + +// ACTS context / environment + +class IRecActsSvc : virtual public IInterface { +public: + DeclareInterfaceID(IRecActsSvc, 0, 1); // major/minor version + virtual ~IRecActsSvc() = default; + + // --------------------------------- + // ---- main tracking functions ---- + // --------------------------------- + + // build geometry + virtual StatusCode BuildGeometry() = 0; + + // read input + virtual StatusCode ReadInput(const edm4hep::TrackerHit hit, + uint64_t acts_volume, uint64_t acts_layer, uint64_t acts_sensitive, + bool buildSpacePoint = false, + int moduleType = 0, /* 0: PLANAR, 1: CYLINDER, 2: TPC*/ + double onSurfaceTolerance = 1e-3) = 0; + // finalize + virtual StatusCode Clean() = 0; + virtual StatusCode WriteOutput() = 0; + + // ------------------ + // ---- Get Data ---- + // ------------------ + + virtual std::string GetTGeoFilePath() = 0; + virtual std::string GetTGeoConfigFilePath() = 0; + virtual std::string GetMaterialMapFilePath() = 0; + virtual std::shared_ptr<const Acts::TrackingGeometry> Geometry() = 0; + + virtual std::vector<const ActsHelper::SimSpacePoint*>* SpacePointPtrs() = 0; + virtual ActsHelper::IndexSourceLinkContainer* SourceLinks() = 0; + virtual std::vector<::Acts::BoundVariantMeasurement>* Measurements() = 0; + virtual ActsHelper::SimSeedContainer* Seeds() = 0; + virtual std::vector<ActsHelper::SimSeedContainer>* SelectedSeeds() = 0; + virtual std::vector<std::vector<::Acts::BoundTrackParameters>>* TrackParameters() = 0; + virtual std::vector<std::vector<::Acts::SourceLink>>* TrackSourceLinks() = 0; +}; + + +#endif // IRECACTSSVC_H \ No newline at end of file diff --git a/Reconstruction/RecActsTracking/RecActsSvc/src/RecActsSvc.cpp b/Reconstruction/RecActsTracking/RecActsSvc/src/RecActsSvc.cpp new file mode 100644 index 00000000..8b995fe0 --- /dev/null +++ b/Reconstruction/RecActsTracking/RecActsSvc/src/RecActsSvc.cpp @@ -0,0 +1,251 @@ +#include "RecActsSvc.h" + +DECLARE_COMPONENT(RecActsSvc) + +RecActsSvc::RecActsSvc(const std::string& name, ISvcLocator* svc) + : base_class(name, svc) +{ +} + +RecActsSvc::~RecActsSvc() +{ +} + +StatusCode RecActsSvc::initialize() +{ + m_isGeometryBuilt = false; + if (m_TGeoFilePath.value().empty()){ + error() << "TGeoFilePath is not set!" << endmsg; + return StatusCode::FAILURE; + } + if (m_TGeoConfigFilePath.value().empty()){ + error() << "TGeoConfigFilePath is not set!" << endmsg; + return StatusCode::FAILURE; + } + if (m_MaterialMapFilePath.value().empty()){ + error() << "MaterialMapFilePath is not set!" << endmsg; + return StatusCode::FAILURE; + } + BuildGeometry(); + + return StatusCode::SUCCESS; +} + +StatusCode RecActsSvc::finalize() +{ + return StatusCode::SUCCESS; +} + +StatusCode RecActsSvc::BuildGeometry() +{ + if (m_isGeometryBuilt) { + info() << "ACTS geometry already built!" << endmsg; + return StatusCode::SUCCESS; + } + + if (m_TGeoFilePath.value().empty()){ + error() << "TGeoFilePath is not set!" << endmsg; + return StatusCode::FAILURE; + } + if (m_TGeoConfigFilePath.value().empty()){ + error() << "TGeoConfigFilePath is not set!" << endmsg; + return StatusCode::FAILURE; + } + if (m_MaterialMapFilePath.value().empty()){ + error() << "MaterialMapFilePath is not set!" << endmsg; + return StatusCode::FAILURE; + } + + info() << "Building ACTS geometry ..." << endmsg; + info() << "TGeoFilePath: " << m_TGeoFilePath << endmsg; + info() << "TGeoConfigFilePath: " << m_TGeoConfigFilePath << endmsg; + info() << "MaterialMapFilePath: " << m_MaterialMapFilePath << endmsg; + + auto logger = Acts::getDefaultLogger("TGeoDetector", Acts::Logging::INFO); + trackingGeometry = buildTGeoDetector(geoContext, detElementStore, m_TGeoFilePath, m_TGeoConfigFilePath, m_MaterialMapFilePath, *logger); + + m_isGeometryBuilt = true; + info() << "ACTS geometry built successfully!" << endmsg; + + // (REMOVE IT) DEBUG: write to csv + // hit_stream = new std::ofstream("/home/zhangyz/CEPCSW/hits.csv"); + // hit_writer = new csv2::Writer<csv2::delimiter<','>>(*hit_stream); + // std::vector<std::string> hit_header = {"sim_x", "sim_y", "sim_z", "hit_x", "hit_y", "hit_z"}; + // hit_writer->write_row(hit_header); + + return StatusCode::SUCCESS; +} + +StatusCode RecActsSvc::ReadInput(const edm4hep::TrackerHit hit, + uint64_t acts_volume, uint64_t acts_layer, uint64_t acts_sensitive, + bool buildSpacePoint, + int moduleType, + double onSurfaceTolerance) +{ + if (!m_isGeometryBuilt){ + error() << "Read input failed, ACTS geometry is not built!" << endmsg; + return StatusCode::FAILURE; + } + + double acts_x = hit.getPosition()[0]; + double acts_y = hit.getPosition()[1]; + double acts_z = hit.getPosition()[2]; + std::array<float, 6> m_covMatrix = hit.getCovMatrix(); + + Acts::GeometryIdentifier moduleGeoId; + moduleGeoId.setVolume(acts_volume); + moduleGeoId.setBoundary(0); + moduleGeoId.setLayer(acts_layer); + moduleGeoId.setApproach(0); + moduleGeoId.setSensitive(acts_sensitive); + + uint32_t measurementIdx = m_measurements.size(); + ActsHelper::IndexSourceLink sourceLink{moduleGeoId, measurementIdx}; + Acts::SourceLink sl{sourceLink}; + boost::container::static_vector<Acts::SourceLink, 2> slinks; + slinks.emplace_back(sl); + + // get the surface of the hit + ActsHelper::IndexSourceLink::SurfaceAccessor surfaceAccessor{*trackingGeometry}; + const Acts::Surface* acts_surface = surfaceAccessor(sl); + + // get the local position of the hit + const Acts::Vector3 globalPos{acts_x, acts_y, acts_z}; + auto acts_local_postion = acts_surface->globalToLocal(geoContext, globalPos, globalFakeMom, onSurfaceTolerance); + if (!acts_local_postion.ok()){ + info() << "Error: failed to get local position at: (x,y,z) " << acts_x << ", " << acts_y << ", " << acts_z << endmsg; + return StatusCode::FAILURE; + } + const std::array<Acts::BoundIndices, 2> indices{Acts::BoundIndices::eBoundLoc0, Acts::BoundIndices::eBoundLoc1}; + const Acts::Vector2 par{acts_local_postion.value()[0], acts_local_postion.value()[1]}; + + auto acts_global_postion = acts_surface->localToGlobal(geoContext, par, globalFakeMom); + // debug() << "measurements global position(x,y,z): " << acts_x << ", " + // << acts_y << ", " << acts_z << endmsg; + // debug() << "converted position(x,y,z): " << acts_global_postion[0] << ", " + // << acts_global_postion[1] << ", " << acts_global_postion[2] << endmsg; + + // (REMOVE IT) DEBUG: write to csv + // std::vector<std::string> hit_data = {std::to_string(simhit.getPosition()[0]), std::to_string(simhit.getPosition()[1]), std::to_string(simhit.getPosition()[2]), std::to_string(hit.getPosition()[0]), std::to_string(hit.getPosition()[1]), std::to_string(hit.getPosition()[2])}; + // hit_writer->write_row(hit_data); + + // create and store the measurement + // 0: PLANAR, 1: CYLINDER, 2: TPC + // PLANAR {u_direction[0], u_direction[1], resU, v_direction[0], v_direction[1], resV} + // CYLINDER {resU*resU/2, 0, resU*resU/2, 0, 0, resV*resV} + // TPC {sin(unsmearedPhi)*sin(unsmearedPhi)*tpcRPhiRes*tpcRPhiRes, + // -cos(unsmearedPhi)*sin(unsmearedPhi)*tpcRPhiRes*tpcRPhiRes, + // cos(unsmearedPhi)*cos(unsmearedPhi)*tpcRPhiRes*tpcRPhiRes, + // 0, 0, tpcZRes*tpcZRes} + Acts::ActsSquareMatrix<2> cov = Acts::ActsSquareMatrix<2>::Identity(); + if (moduleType == 0){ + cov(0, 0) = std::max<double>(double(m_covMatrix[2]*m_covMatrix[2]), eps); + cov(1, 1) = std::max<double>(double(m_covMatrix[5]*m_covMatrix[5]), eps); + } else if (moduleType == 1){ + cov(0, 0) = std::max<double>(double(fabs(m_covMatrix[0] + m_covMatrix[2])), eps); + cov(1, 1) = std::max<double>(double(fabs(m_covMatrix[5])), eps); + } else if (moduleType == 2){ + cov(0, 0) = std::max<double>(double(fabs(m_covMatrix[0] + m_covMatrix[2])), eps); + cov(1, 1) = std::max<double>(double(fabs(m_covMatrix[5])), eps); + } else { + error() << "Invalid module type: " << moduleType << endmsg; + return StatusCode::FAILURE; + } + + // debug() << "covariance(u,v): " << cov(0, 0) << ", " << cov(1, 1) << endmsg; + + m_measurements.emplace_back(Acts::Measurement<Acts::BoundIndices, 2>(sl, indices, par, cov)); + m_sourceLinks.insert(m_sourceLinks.end(), sourceLink); + + if (buildSpacePoint){ + ActsHelper::SimSpacePoint *hitExt = new ActsHelper::SimSpacePoint( + acts_global_postion[0], acts_global_postion[1], acts_global_postion[2], 0., + eps, cov(1, 1), eps, + slinks); + + m_SpacePointPtrs.push_back(hitExt); + } + + return StatusCode::SUCCESS; +} + +StatusCode RecActsSvc::Clean() +{ + m_SpacePointPtrs.clear(); + m_sourceLinks.clear(); + m_measurements.clear(); + m_Seeds.clear(); + m_Selected_Seeds.clear(); + m_trackParameters.clear(); + m_trackSourceLinks.clear(); + + return StatusCode::SUCCESS; +} + +StatusCode RecActsSvc::WriteOutput() +{ + return StatusCode::SUCCESS; +} + +std::string RecActsSvc::GetTGeoFilePath() +{ + debug() << "Get TGeoFilePath: " << m_TGeoFilePath.value() << endmsg; + return m_TGeoFilePath.value(); +} + +std::string RecActsSvc::GetTGeoConfigFilePath() +{ + debug() << "Get TGeoConfigFilePath: " << m_TGeoConfigFilePath.value() << endmsg; + return m_TGeoConfigFilePath.value(); +} + +std::string RecActsSvc::GetMaterialMapFilePath() +{ + debug() << "Get MaterialMapFilePath: " << m_MaterialMapFilePath.value() << endmsg; + return m_MaterialMapFilePath.value(); +} + +std::shared_ptr<const Acts::TrackingGeometry> RecActsSvc::Geometry() +{ + if (!m_isGeometryBuilt) { + error() << "Failed to get ACTS geometry, Geometry is not built!" << endmsg; + return nullptr; + } + + return trackingGeometry; +} + +std::vector<const ActsHelper::SimSpacePoint*> *RecActsSvc::SpacePointPtrs() +{ + return &m_SpacePointPtrs; +} + +ActsHelper::IndexSourceLinkContainer *RecActsSvc::SourceLinks() +{ + return &m_sourceLinks; +} + +std::vector<::Acts::BoundVariantMeasurement> *RecActsSvc::Measurements() +{ + return &m_measurements; +} + +ActsHelper::SimSeedContainer *RecActsSvc::Seeds() +{ + return &m_Seeds; +} + +std::vector<ActsHelper::SimSeedContainer> *RecActsSvc::SelectedSeeds() +{ + return &m_Selected_Seeds; +} + +std::vector<std::vector<::Acts::BoundTrackParameters>> *RecActsSvc::TrackParameters() +{ + return &m_trackParameters; +} + +std::vector<std::vector<::Acts::SourceLink>> *RecActsSvc::TrackSourceLinks() +{ + return &m_trackSourceLinks; +} \ No newline at end of file diff --git a/Reconstruction/RecActsTracking/RecActsSvc/src/RecActsSvc.h b/Reconstruction/RecActsTracking/RecActsSvc/src/RecActsSvc.h new file mode 100644 index 00000000..110fa5d4 --- /dev/null +++ b/Reconstruction/RecActsTracking/RecActsSvc/src/RecActsSvc.h @@ -0,0 +1,83 @@ +#ifndef RECACTSSVC_H +#define RECACTSSVC_H + +#include "GaudiKernel/Service.h" +#include "RecActsSvc/IRecActsSvc.h" + + +#include <iostream> +#include <fstream> +#include <cstdlib> +#include <sstream> +#include <filesystem> + +// #include "csv2/writer.hpp" + +class RecActsSvc : public extends<Service, IRecActsSvc> { +public: + RecActsSvc(const std::string& name, ISvcLocator* svc); + virtual ~RecActsSvc(); + + StatusCode initialize() override; + StatusCode finalize() override; + + // --------------------------------- + // ---- main tracking functions ---- + // --------------------------------- + + StatusCode BuildGeometry() override; + + StatusCode ReadInput(const edm4hep::TrackerHit hit, + uint64_t acts_volume, uint64_t acts_layer, uint64_t acts_sensitive, + bool buildSpacePoint = false, + int moduleType = 0, /* 0: PLANAR, 1: CYLINDER, 2: TPC*/ + double onSurfaceTolerance = 1e-3) override; + + StatusCode Clean() override; + StatusCode WriteOutput() override; + + // ------------------ + // ---- Get Data ---- + // ------------------ + + std::string GetTGeoFilePath() override; + std::string GetTGeoConfigFilePath() override; + std::string GetMaterialMapFilePath() override; + std::shared_ptr<const Acts::TrackingGeometry> Geometry() override; + + std::vector<const ActsHelper::SimSpacePoint*>* SpacePointPtrs() override; + ActsHelper::IndexSourceLinkContainer* SourceLinks() override; + std::vector<::Acts::BoundVariantMeasurement>* Measurements() override; + ActsHelper::SimSeedContainer* Seeds() override; + std::vector<ActsHelper::SimSeedContainer>* SelectedSeeds() override; + std::vector<std::vector<::Acts::BoundTrackParameters>>* TrackParameters() override; + std::vector<std::vector<::Acts::SourceLink>>* TrackSourceLinks() override; + +private: + Gaudi::Property<std::string> m_TGeoFilePath{this, "TGeoFile"}; + Gaudi::Property<std::string> m_TGeoConfigFilePath{this, "TGeoConfigFile"}; + Gaudi::Property<std::string> m_MaterialMapFilePath{this, "MaterialMapFile"}; + + Acts::GeometryContext geoContext; + Acts::MagneticFieldContext magFieldContext; + Acts::CalibrationContext calibContext; + + bool m_isGeometryBuilt; + std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry; + std::vector<std::shared_ptr<const Acts::TGeoDetectorElement>> detElementStore; + + // Store the space points & measurements & sourcelinks **per event** + std::vector<const ActsHelper::SimSpacePoint*> m_SpacePointPtrs; + ActsHelper::IndexSourceLinkContainer m_sourceLinks; + std::vector<::Acts::BoundVariantMeasurement> m_measurements; + ActsHelper::SimSeedContainer m_Seeds; + std::vector<ActsHelper::SimSeedContainer> m_Selected_Seeds; + + std::vector<std::vector<::Acts::BoundTrackParameters>> m_trackParameters; + std::vector<std::vector<::Acts::SourceLink>> m_trackSourceLinks; + + double eps = 1e-5; + const Acts::Vector3 globalFakeMom{1.e6, 1.e6, 1.e6}; +}; + +#endif // RECACTSSVC_H \ No newline at end of file diff --git a/Reconstruction/RecActsTracking/RecActsSvc/src/csv2/mio.hpp b/Reconstruction/RecActsTracking/RecActsSvc/src/csv2/mio.hpp new file mode 100644 index 00000000..48a86684 --- /dev/null +++ b/Reconstruction/RecActsTracking/RecActsSvc/src/csv2/mio.hpp @@ -0,0 +1,1562 @@ + +/* Copyright 2017 https://github.com/mandreyel + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation files (the "Software"), to deal in the Software + * without restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be included in all copies + * or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef MIO_MMAP_HEADER +#define MIO_MMAP_HEADER + +// #include "mio/page.hpp" +/* Copyright 2017 https://github.com/mandreyel + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation files (the "Software"), to deal in the Software + * without restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be included in all copies + * or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef MIO_PAGE_HEADER +#define MIO_PAGE_HEADER + +#ifdef _WIN32 +#include <windows.h> +#else +#include <unistd.h> +#endif + +namespace mio { + +/** + * This is used by `basic_mmap` to determine whether to create a read-only or + * a read-write memory mapping. + */ +enum class access_mode { read, write }; + +/** + * Determines the operating system's page allocation granularity. + * + * On the first call to this function, it invokes the operating system specific syscall + * to determine the page size, caches the value, and returns it. Any subsequent call to + * this function serves the cached value, so no further syscalls are made. + */ +inline size_t page_size() { + static const size_t page_size = [] { +#ifdef _WIN32 + SYSTEM_INFO SystemInfo; + GetSystemInfo(&SystemInfo); + return SystemInfo.dwAllocationGranularity; +#else + return sysconf(_SC_PAGE_SIZE); +#endif + }(); + return page_size; +} + +/** + * Alligns `offset` to the operating's system page size such that it subtracts the + * difference until the nearest page boundary before `offset`, or does nothing if + * `offset` is already page aligned. + */ +inline size_t make_offset_page_aligned(size_t offset) noexcept { + const size_t page_size_ = page_size(); + // Use integer division to round down to the nearest page alignment. + return offset / page_size_ * page_size_; +} + +} // namespace mio + +#endif // MIO_PAGE_HEADER + +#include <cstdint> +#include <iterator> +#include <string> +#include <system_error> + +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif // WIN32_LEAN_AND_MEAN +#include <windows.h> +#else // ifdef _WIN32 +#define INVALID_HANDLE_VALUE -1 +#endif // ifdef _WIN32 + +namespace mio { + +// This value may be provided as the `length` parameter to the constructor or +// `map`, in which case a memory mapping of the entire file is created. +enum { map_entire_file = 0 }; + +#ifdef _WIN32 +using file_handle_type = HANDLE; +#else +using file_handle_type = int; +#endif + +// This value represents an invalid file handle type. This can be used to +// determine whether `basic_mmap::file_handle` is valid, for example. +const static file_handle_type invalid_handle = INVALID_HANDLE_VALUE; + +template <access_mode AccessMode, typename ByteT> struct basic_mmap { + using value_type = ByteT; + using size_type = size_t; + using reference = value_type &; + using const_reference = const value_type &; + using pointer = value_type *; + using const_pointer = const value_type *; + using difference_type = std::ptrdiff_t; + using iterator = pointer; + using const_iterator = const_pointer; + using reverse_iterator = std::reverse_iterator<iterator>; + using const_reverse_iterator = std::reverse_iterator<const_iterator>; + using iterator_category = std::random_access_iterator_tag; + using handle_type = file_handle_type; + + static_assert(sizeof(ByteT) == sizeof(char), "ByteT must be the same size as char."); + +private: + // Points to the first requested byte, and not to the actual start of the mapping. + pointer data_ = nullptr; + + // Length--in bytes--requested by user (which may not be the length of the + // full mapping) and the length of the full mapping. + size_type length_ = 0; + size_type mapped_length_ = 0; + + // Letting user map a file using both an existing file handle and a path + // introcudes some complexity (see `is_handle_internal_`). + // On POSIX, we only need a file handle to create a mapping, while on + // Windows systems the file handle is necessary to retrieve a file mapping + // handle, but any subsequent operations on the mapped region must be done + // through the latter. + handle_type file_handle_ = INVALID_HANDLE_VALUE; +#ifdef _WIN32 + handle_type file_mapping_handle_ = INVALID_HANDLE_VALUE; +#endif + + // Letting user map a file using both an existing file handle and a path + // introcudes some complexity in that we must not close the file handle if + // user provided it, but we must close it if we obtained it using the + // provided path. For this reason, this flag is used to determine when to + // close `file_handle_`. + bool is_handle_internal_; + +public: + /** + * The default constructed mmap object is in a non-mapped state, that is, + * any operation that attempts to access nonexistent underlying data will + * result in undefined behaviour/segmentation faults. + */ + basic_mmap() = default; + +#ifdef __cpp_exceptions + /** + * The same as invoking the `map` function, except any error that may occur + * while establishing the mapping is wrapped in a `std::system_error` and is + * thrown. + */ + template <typename String> + basic_mmap(const String &path, const size_type offset = 0, + const size_type length = map_entire_file) { + std::error_code error; + map(path, offset, length, error); + if (error) { + throw std::system_error(error); + } + } + + /** + * The same as invoking the `map` function, except any error that may occur + * while establishing the mapping is wrapped in a `std::system_error` and is + * thrown. + */ + basic_mmap(const handle_type handle, const size_type offset = 0, + const size_type length = map_entire_file) { + std::error_code error; + map(handle, offset, length, error); + if (error) { + throw std::system_error(error); + } + } +#endif // __cpp_exceptions + + /** + * `basic_mmap` has single-ownership semantics, so transferring ownership + * may only be accomplished by moving the object. + */ + basic_mmap(const basic_mmap &) = delete; + basic_mmap(basic_mmap &&); + basic_mmap &operator=(const basic_mmap &) = delete; + basic_mmap &operator=(basic_mmap &&); + + /** + * If this is a read-write mapping, the destructor invokes sync. Regardless + * of the access mode, unmap is invoked as a final step. + */ + ~basic_mmap(); + + /** + * On UNIX systems 'file_handle' and 'mapping_handle' are the same. On Windows, + * however, a mapped region of a file gets its own handle, which is returned by + * 'mapping_handle'. + */ + handle_type file_handle() const noexcept { return file_handle_; } + handle_type mapping_handle() const noexcept; + + /** Returns whether a valid memory mapping has been created. */ + bool is_open() const noexcept { return file_handle_ != invalid_handle; } + + /** + * Returns true if no mapping was established, that is, conceptually the + * same as though the length that was mapped was 0. This function is + * provided so that this class has Container semantics. + */ + bool empty() const noexcept { return length() == 0; } + + /** Returns true if a mapping was established. */ + bool is_mapped() const noexcept; + + /** + * `size` and `length` both return the logical length, i.e. the number of bytes + * user requested to be mapped, while `mapped_length` returns the actual number of + * bytes that were mapped which is a multiple of the underlying operating system's + * page allocation granularity. + */ + size_type size() const noexcept { return length(); } + size_type length() const noexcept { return length_; } + size_type mapped_length() const noexcept { return mapped_length_; } + + /** Returns the offset relative to the start of the mapping. */ + size_type mapping_offset() const noexcept { return mapped_length_ - length_; } + + /** + * Returns a pointer to the first requested byte, or `nullptr` if no memory mapping + * exists. + */ + template <access_mode A = AccessMode, + typename = typename std::enable_if<A == access_mode::write>::type> + pointer data() noexcept { + return data_; + } + const_pointer data() const noexcept { return data_; } + + /** + * Returns an iterator to the first requested byte, if a valid memory mapping + * exists, otherwise this function call is undefined behaviour. + */ + template <access_mode A = AccessMode, + typename = typename std::enable_if<A == access_mode::write>::type> + iterator begin() noexcept { + return data(); + } + const_iterator begin() const noexcept { return data(); } + const_iterator cbegin() const noexcept { return data(); } + + /** + * Returns an iterator one past the last requested byte, if a valid memory mapping + * exists, otherwise this function call is undefined behaviour. + */ + template <access_mode A = AccessMode, + typename = typename std::enable_if<A == access_mode::write>::type> + iterator end() noexcept { + return data() + length(); + } + const_iterator end() const noexcept { return data() + length(); } + const_iterator cend() const noexcept { return data() + length(); } + + /** + * Returns a reverse iterator to the last memory mapped byte, if a valid + * memory mapping exists, otherwise this function call is undefined + * behaviour. + */ + template <access_mode A = AccessMode, + typename = typename std::enable_if<A == access_mode::write>::type> + reverse_iterator rbegin() noexcept { + return reverse_iterator(end()); + } + const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); } + const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(end()); } + + /** + * Returns a reverse iterator past the first mapped byte, if a valid memory + * mapping exists, otherwise this function call is undefined behaviour. + */ + template <access_mode A = AccessMode, + typename = typename std::enable_if<A == access_mode::write>::type> + reverse_iterator rend() noexcept { + return reverse_iterator(begin()); + } + const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); } + const_reverse_iterator crend() const noexcept { return const_reverse_iterator(begin()); } + + /** + * Returns a reference to the `i`th byte from the first requested byte (as returned + * by `data`). If this is invoked when no valid memory mapping has been created + * prior to this call, undefined behaviour ensues. + */ + reference operator[](const size_type i) noexcept { return data_[i]; } + const_reference operator[](const size_type i) const noexcept { return data_[i]; } + + /** + * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the + * reason is reported via `error` and the object remains in a state as if this + * function hadn't been called. + * + * `path`, which must be a path to an existing file, is used to retrieve a file + * handle (which is closed when the object destructs or `unmap` is called), which is + * then used to memory map the requested region. Upon failure, `error` is set to + * indicate the reason and the object remains in an unmapped state. + * + * `offset` is the number of bytes, relative to the start of the file, where the + * mapping should begin. When specifying it, there is no need to worry about + * providing a value that is aligned with the operating system's page allocation + * granularity. This is adjusted by the implementation such that the first requested + * byte (as returned by `data` or `begin`), so long as `offset` is valid, will be at + * `offset` from the start of the file. + * + * `length` is the number of bytes to map. It may be `map_entire_file`, in which + * case a mapping of the entire file is created. + */ + template <typename String> + void map(const String &path, const size_type offset, const size_type length, + std::error_code &error); + + /** + * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the + * reason is reported via `error` and the object remains in a state as if this + * function hadn't been called. + * + * `path`, which must be a path to an existing file, is used to retrieve a file + * handle (which is closed when the object destructs or `unmap` is called), which is + * then used to memory map the requested region. Upon failure, `error` is set to + * indicate the reason and the object remains in an unmapped state. + * + * The entire file is mapped. + */ + template <typename String> void map(const String &path, std::error_code &error) { + map(path, 0, map_entire_file, error); + } + + /** + * Establishes a memory mapping with AccessMode. If the mapping is + * unsuccesful, the reason is reported via `error` and the object remains in + * a state as if this function hadn't been called. + * + * `handle`, which must be a valid file handle, which is used to memory map the + * requested region. Upon failure, `error` is set to indicate the reason and the + * object remains in an unmapped state. + * + * `offset` is the number of bytes, relative to the start of the file, where the + * mapping should begin. When specifying it, there is no need to worry about + * providing a value that is aligned with the operating system's page allocation + * granularity. This is adjusted by the implementation such that the first requested + * byte (as returned by `data` or `begin`), so long as `offset` is valid, will be at + * `offset` from the start of the file. + * + * `length` is the number of bytes to map. It may be `map_entire_file`, in which + * case a mapping of the entire file is created. + */ + void map(const handle_type handle, const size_type offset, const size_type length, + std::error_code &error); + + /** + * Establishes a memory mapping with AccessMode. If the mapping is + * unsuccesful, the reason is reported via `error` and the object remains in + * a state as if this function hadn't been called. + * + * `handle`, which must be a valid file handle, which is used to memory map the + * requested region. Upon failure, `error` is set to indicate the reason and the + * object remains in an unmapped state. + * + * The entire file is mapped. + */ + void map(const handle_type handle, std::error_code &error) { + map(handle, 0, map_entire_file, error); + } + + /** + * If a valid memory mapping has been created prior to this call, this call + * instructs the kernel to unmap the memory region and disassociate this object + * from the file. + * + * The file handle associated with the file that is mapped is only closed if the + * mapping was created using a file path. If, on the other hand, an existing + * file handle was used to create the mapping, the file handle is not closed. + */ + void unmap(); + + void swap(basic_mmap &other); + + /** Flushes the memory mapped page to disk. Errors are reported via `error`. */ + template <access_mode A = AccessMode> + typename std::enable_if<A == access_mode::write, void>::type sync(std::error_code &error); + + /** + * All operators compare the address of the first byte and size of the two mapped + * regions. + */ + +private: + template <access_mode A = AccessMode, + typename = typename std::enable_if<A == access_mode::write>::type> + pointer get_mapping_start() noexcept { + return !data() ? nullptr : data() - mapping_offset(); + } + + const_pointer get_mapping_start() const noexcept { + return !data() ? nullptr : data() - mapping_offset(); + } + + /** + * The destructor syncs changes to disk if `AccessMode` is `write`, but not + * if it's `read`, but since the destructor cannot be templated, we need to + * do SFINAE in a dedicated function, where one syncs and the other is a noop. + */ + template <access_mode A = AccessMode> + typename std::enable_if<A == access_mode::write, void>::type conditional_sync(); + template <access_mode A = AccessMode> + typename std::enable_if<A == access_mode::read, void>::type conditional_sync(); +}; + +template <access_mode AccessMode, typename ByteT> +bool operator==(const basic_mmap<AccessMode, ByteT> &a, const basic_mmap<AccessMode, ByteT> &b); + +template <access_mode AccessMode, typename ByteT> +bool operator!=(const basic_mmap<AccessMode, ByteT> &a, const basic_mmap<AccessMode, ByteT> &b); + +template <access_mode AccessMode, typename ByteT> +bool operator<(const basic_mmap<AccessMode, ByteT> &a, const basic_mmap<AccessMode, ByteT> &b); + +template <access_mode AccessMode, typename ByteT> +bool operator<=(const basic_mmap<AccessMode, ByteT> &a, const basic_mmap<AccessMode, ByteT> &b); + +template <access_mode AccessMode, typename ByteT> +bool operator>(const basic_mmap<AccessMode, ByteT> &a, const basic_mmap<AccessMode, ByteT> &b); + +template <access_mode AccessMode, typename ByteT> +bool operator>=(const basic_mmap<AccessMode, ByteT> &a, const basic_mmap<AccessMode, ByteT> &b); + +/** + * This is the basis for all read-only mmap objects and should be preferred over + * directly using `basic_mmap`. + */ +template <typename ByteT> using basic_mmap_source = basic_mmap<access_mode::read, ByteT>; + +/** + * This is the basis for all read-write mmap objects and should be preferred over + * directly using `basic_mmap`. + */ +template <typename ByteT> using basic_mmap_sink = basic_mmap<access_mode::write, ByteT>; + +/** + * These aliases cover the most common use cases, both representing a raw byte stream + * (either with a char or an unsigned char/uint8_t). + */ +using mmap_source = basic_mmap_source<char>; +using ummap_source = basic_mmap_source<unsigned char>; + +using mmap_sink = basic_mmap_sink<char>; +using ummap_sink = basic_mmap_sink<unsigned char>; + +/** + * Convenience factory method that constructs a mapping for any `basic_mmap` or + * `basic_mmap` type. + */ +template <typename MMap, typename MappingToken> +MMap make_mmap(const MappingToken &token, int64_t offset, int64_t length, std::error_code &error) { + MMap mmap; + mmap.map(token, offset, length, error); + return mmap; +} + +/** + * Convenience factory method. + * + * MappingToken may be a String (`std::string`, `std::string_view`, `const char*`, + * `std::filesystem::path`, `std::vector<char>`, or similar), or a + * `mmap_source::handle_type`. + */ +template <typename MappingToken> +mmap_source make_mmap_source(const MappingToken &token, mmap_source::size_type offset, + mmap_source::size_type length, std::error_code &error) { + return make_mmap<mmap_source>(token, offset, length, error); +} + +template <typename MappingToken> +mmap_source make_mmap_source(const MappingToken &token, std::error_code &error) { + return make_mmap_source(token, 0, map_entire_file, error); +} + +/** + * Convenience factory method. + * + * MappingToken may be a String (`std::string`, `std::string_view`, `const char*`, + * `std::filesystem::path`, `std::vector<char>`, or similar), or a + * `mmap_sink::handle_type`. + */ +template <typename MappingToken> +mmap_sink make_mmap_sink(const MappingToken &token, mmap_sink::size_type offset, + mmap_sink::size_type length, std::error_code &error) { + return make_mmap<mmap_sink>(token, offset, length, error); +} + +template <typename MappingToken> +mmap_sink make_mmap_sink(const MappingToken &token, std::error_code &error) { + return make_mmap_sink(token, 0, map_entire_file, error); +} + +} // namespace mio + +// #include "detail/mmap.ipp" +/* Copyright 2017 https://github.com/mandreyel + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation files (the "Software"), to deal in the Software + * without restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be included in all copies + * or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef MIO_BASIC_MMAP_IMPL +#define MIO_BASIC_MMAP_IMPL + +// #include "mio/mmap.hpp" + +// #include "mio/page.hpp" + +// #include "mio/detail/string_util.hpp" +/* Copyright 2017 https://github.com/mandreyel + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation files (the "Software"), to deal in the Software + * without restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be included in all copies + * or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef MIO_STRING_UTIL_HEADER +#define MIO_STRING_UTIL_HEADER + +#include <type_traits> + +namespace mio { +namespace detail { + +template <typename S, typename C = typename std::decay<S>::type, + typename = decltype(std::declval<C>().data()), + typename = typename std::enable_if<std::is_same<typename C::value_type, char>::value +#ifdef _WIN32 + || std::is_same<typename C::value_type, wchar_t>::value +#endif + >::type> +struct char_type_helper { + using type = typename C::value_type; +}; + +template <class T> struct char_type { using type = typename char_type_helper<T>::type; }; + +// TODO: can we avoid this brute force approach? +template <> struct char_type<char *> { using type = char; }; + +template <> struct char_type<const char *> { using type = char; }; + +template <size_t N> struct char_type<char[N]> { using type = char; }; + +template <size_t N> struct char_type<const char[N]> { using type = char; }; + +#ifdef _WIN32 +template <> struct char_type<wchar_t *> { using type = wchar_t; }; + +template <> struct char_type<const wchar_t *> { using type = wchar_t; }; + +template <size_t N> struct char_type<wchar_t[N]> { using type = wchar_t; }; + +template <size_t N> struct char_type<const wchar_t[N]> { using type = wchar_t; }; +#endif // _WIN32 + +template <typename CharT, typename S> struct is_c_str_helper { + static constexpr bool value = + std::is_same<CharT *, + // TODO: I'm so sorry for this... Can this be made cleaner? + typename std::add_pointer<typename std::remove_cv<typename std::remove_pointer< + typename std::decay<S>::type>::type>::type>::type>::value; +}; + +template <typename S> struct is_c_str { + static constexpr bool value = is_c_str_helper<char, S>::value; +}; + +#ifdef _WIN32 +template <typename S> struct is_c_wstr { + static constexpr bool value = is_c_str_helper<wchar_t, S>::value; +}; +#endif // _WIN32 + +template <typename S> struct is_c_str_or_c_wstr { + static constexpr bool value = is_c_str<S>::value +#ifdef _WIN32 + || is_c_wstr<S>::value +#endif + ; +}; + +template <typename String, typename = decltype(std::declval<String>().data()), + typename = typename std::enable_if<!is_c_str_or_c_wstr<String>::value>::type> +const typename char_type<String>::type *c_str(const String &path) { + return path.data(); +} + +template <typename String, typename = decltype(std::declval<String>().empty()), + typename = typename std::enable_if<!is_c_str_or_c_wstr<String>::value>::type> +bool empty(const String &path) { + return path.empty(); +} + +template <typename String, + typename = typename std::enable_if<is_c_str_or_c_wstr<String>::value>::type> +const typename char_type<String>::type *c_str(String path) { + return path; +} + +template <typename String, + typename = typename std::enable_if<is_c_str_or_c_wstr<String>::value>::type> +bool empty(String path) { + return !path || (*path == 0); +} + +} // namespace detail +} // namespace mio + +#endif // MIO_STRING_UTIL_HEADER + +#include <algorithm> + +#ifndef _WIN32 +#include <fcntl.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <unistd.h> +#endif + +namespace mio { +namespace detail { + +#ifdef _WIN32 +namespace win { + +/** Returns the 4 upper bytes of an 8-byte integer. */ +inline DWORD int64_high(int64_t n) noexcept { return n >> 32; } + +/** Returns the 4 lower bytes of an 8-byte integer. */ +inline DWORD int64_low(int64_t n) noexcept { return n & 0xffffffff; } + +template <typename String, typename = typename std::enable_if< + std::is_same<typename char_type<String>::type, char>::value>::type> +file_handle_type open_file_helper(const String &path, const access_mode mode) { + return ::CreateFileA( + c_str(path), mode == access_mode::read ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); +} + +template <typename String> +typename std::enable_if<std::is_same<typename char_type<String>::type, wchar_t>::value, + file_handle_type>::type +open_file_helper(const String &path, const access_mode mode) { + return ::CreateFileW( + c_str(path), mode == access_mode::read ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); +} + +} // namespace win +#endif // _WIN32 + +/** + * Returns the last platform specific system error (errno on POSIX and + * GetLastError on Win) as a `std::error_code`. + */ +inline std::error_code last_error() noexcept { + std::error_code error; +#ifdef _WIN32 + error.assign(GetLastError(), std::system_category()); +#else + error.assign(errno, std::system_category()); +#endif + return error; +} + +template <typename String> +file_handle_type open_file(const String &path, const access_mode mode, std::error_code &error) { + error.clear(); + if (detail::empty(path)) { + error = std::make_error_code(std::errc::invalid_argument); + return invalid_handle; + } +#ifdef _WIN32 + const auto handle = win::open_file_helper(path, mode); +#else // POSIX + const auto handle = ::open(c_str(path), mode == access_mode::read ? O_RDONLY : O_RDWR); +#endif + if (handle == invalid_handle) { + error = detail::last_error(); + } + return handle; +} + +inline size_t query_file_size(file_handle_type handle, std::error_code &error) { + error.clear(); +#ifdef _WIN32 + LARGE_INTEGER file_size; + if (::GetFileSizeEx(handle, &file_size) == 0) { + error = detail::last_error(); + return 0; + } + return static_cast<int64_t>(file_size.QuadPart); +#else // POSIX + struct stat sbuf; + if (::fstat(handle, &sbuf) == -1) { + error = detail::last_error(); + return 0; + } + return sbuf.st_size; +#endif +} + +struct mmap_context { + char *data; + int64_t length; + int64_t mapped_length; +#ifdef _WIN32 + file_handle_type file_mapping_handle; +#endif +}; + +inline mmap_context memory_map(const file_handle_type file_handle, const int64_t offset, + const int64_t length, const access_mode mode, + std::error_code &error) { + const int64_t aligned_offset = make_offset_page_aligned(offset); + const int64_t length_to_map = offset - aligned_offset + length; +#ifdef _WIN32 + const int64_t max_file_size = offset + length; + const auto file_mapping_handle = ::CreateFileMapping( + file_handle, 0, mode == access_mode::read ? PAGE_READONLY : PAGE_READWRITE, + win::int64_high(max_file_size), win::int64_low(max_file_size), 0); + if (file_mapping_handle == invalid_handle) { + error = detail::last_error(); + return {}; + } + char *mapping_start = static_cast<char *>(::MapViewOfFile( + file_mapping_handle, mode == access_mode::read ? FILE_MAP_READ : FILE_MAP_WRITE, + win::int64_high(aligned_offset), win::int64_low(aligned_offset), length_to_map)); + if (mapping_start == nullptr) { + // Close file handle if mapping it failed. + ::CloseHandle(file_mapping_handle); + error = detail::last_error(); + return {}; + } +#else // POSIX + char *mapping_start = + static_cast<char *>(::mmap(0, // Don't give hint as to where to map. + length_to_map, mode == access_mode::read ? PROT_READ : PROT_WRITE, + MAP_SHARED, file_handle, aligned_offset)); + if (mapping_start == MAP_FAILED) { + error = detail::last_error(); + return {}; + } +#endif + mmap_context ctx; + ctx.data = mapping_start + offset - aligned_offset; + ctx.length = length; + ctx.mapped_length = length_to_map; +#ifdef _WIN32 + ctx.file_mapping_handle = file_mapping_handle; +#endif + return ctx; +} + +} // namespace detail + +// -- basic_mmap -- + +template <access_mode AccessMode, typename ByteT> basic_mmap<AccessMode, ByteT>::~basic_mmap() { + conditional_sync(); + unmap(); +} + +template <access_mode AccessMode, typename ByteT> +basic_mmap<AccessMode, ByteT>::basic_mmap(basic_mmap &&other) + : data_(std::move(other.data_)), length_(std::move(other.length_)), + mapped_length_(std::move(other.mapped_length_)), file_handle_(std::move(other.file_handle_)) +#ifdef _WIN32 + , + file_mapping_handle_(std::move(other.file_mapping_handle_)) +#endif + , + is_handle_internal_(std::move(other.is_handle_internal_)) { + other.data_ = nullptr; + other.length_ = other.mapped_length_ = 0; + other.file_handle_ = invalid_handle; +#ifdef _WIN32 + other.file_mapping_handle_ = invalid_handle; +#endif +} + +template <access_mode AccessMode, typename ByteT> +basic_mmap<AccessMode, ByteT> &basic_mmap<AccessMode, ByteT>::operator=(basic_mmap &&other) { + if (this != &other) { + // First the existing mapping needs to be removed. + unmap(); + data_ = std::move(other.data_); + length_ = std::move(other.length_); + mapped_length_ = std::move(other.mapped_length_); + file_handle_ = std::move(other.file_handle_); +#ifdef _WIN32 + file_mapping_handle_ = std::move(other.file_mapping_handle_); +#endif + is_handle_internal_ = std::move(other.is_handle_internal_); + + // The moved from basic_mmap's fields need to be reset, because + // otherwise other's destructor will unmap the same mapping that was + // just moved into this. + other.data_ = nullptr; + other.length_ = other.mapped_length_ = 0; + other.file_handle_ = invalid_handle; +#ifdef _WIN32 + other.file_mapping_handle_ = invalid_handle; +#endif + other.is_handle_internal_ = false; + } + return *this; +} + +template <access_mode AccessMode, typename ByteT> +typename basic_mmap<AccessMode, ByteT>::handle_type +basic_mmap<AccessMode, ByteT>::mapping_handle() const noexcept { +#ifdef _WIN32 + return file_mapping_handle_; +#else + return file_handle_; +#endif +} + +template <access_mode AccessMode, typename ByteT> +template <typename String> +void basic_mmap<AccessMode, ByteT>::map(const String &path, const size_type offset, + const size_type length, std::error_code &error) { + error.clear(); + if (detail::empty(path)) { + error = std::make_error_code(std::errc::invalid_argument); + return; + } + const auto handle = detail::open_file(path, AccessMode, error); + if (error) { + return; + } + + map(handle, offset, length, error); + // This MUST be after the call to map, as that sets this to true. + if (!error) { + is_handle_internal_ = true; + } +} + +template <access_mode AccessMode, typename ByteT> +void basic_mmap<AccessMode, ByteT>::map(const handle_type handle, const size_type offset, + const size_type length, std::error_code &error) { + error.clear(); + if (handle == invalid_handle) { + error = std::make_error_code(std::errc::bad_file_descriptor); + return; + } + + const auto file_size = detail::query_file_size(handle, error); + if (error) { + return; + } + + if (offset + length > file_size) { + error = std::make_error_code(std::errc::invalid_argument); + return; + } + + const auto ctx = detail::memory_map( + handle, offset, length == map_entire_file ? (file_size - offset) : length, AccessMode, error); + if (!error) { + // We must unmap the previous mapping that may have existed prior to this call. + // Note that this must only be invoked after a new mapping has been created in + // order to provide the strong guarantee that, should the new mapping fail, the + // `map` function leaves this instance in a state as though the function had + // never been invoked. + unmap(); + file_handle_ = handle; + is_handle_internal_ = false; + data_ = reinterpret_cast<pointer>(ctx.data); + length_ = ctx.length; + mapped_length_ = ctx.mapped_length; +#ifdef _WIN32 + file_mapping_handle_ = ctx.file_mapping_handle; +#endif + } +} + +template <access_mode AccessMode, typename ByteT> +template <access_mode A> +typename std::enable_if<A == access_mode::write, void>::type +basic_mmap<AccessMode, ByteT>::sync(std::error_code &error) { + error.clear(); + if (!is_open()) { + error = std::make_error_code(std::errc::bad_file_descriptor); + return; + } + + if (data()) { +#ifdef _WIN32 + if (::FlushViewOfFile(get_mapping_start(), mapped_length_) == 0 || + ::FlushFileBuffers(file_handle_) == 0) +#else // POSIX + if (::msync(get_mapping_start(), mapped_length_, MS_SYNC) != 0) +#endif + { + error = detail::last_error(); + return; + } + } +#ifdef _WIN32 + if (::FlushFileBuffers(file_handle_) == 0) { + error = detail::last_error(); + } +#endif +} + +template <access_mode AccessMode, typename ByteT> void basic_mmap<AccessMode, ByteT>::unmap() { + if (!is_open()) { + return; + } + // TODO do we care about errors here? +#ifdef _WIN32 + if (is_mapped()) { + ::UnmapViewOfFile(get_mapping_start()); + ::CloseHandle(file_mapping_handle_); + } +#else // POSIX + if (data_) { + ::munmap(const_cast<pointer>(get_mapping_start()), mapped_length_); + } +#endif + + // If `file_handle_` was obtained by our opening it (when map is called with + // a path, rather than an existing file handle), we need to close it, + // otherwise it must not be closed as it may still be used outside this + // instance. + if (is_handle_internal_) { +#ifdef _WIN32 + ::CloseHandle(file_handle_); +#else // POSIX + ::close(file_handle_); +#endif + } + + // Reset fields to their default values. + data_ = nullptr; + length_ = mapped_length_ = 0; + file_handle_ = invalid_handle; +#ifdef _WIN32 + file_mapping_handle_ = invalid_handle; +#endif +} + +template <access_mode AccessMode, typename ByteT> +bool basic_mmap<AccessMode, ByteT>::is_mapped() const noexcept { +#ifdef _WIN32 + return file_mapping_handle_ != invalid_handle; +#else // POSIX + return is_open(); +#endif +} + +template <access_mode AccessMode, typename ByteT> +void basic_mmap<AccessMode, ByteT>::swap(basic_mmap &other) { + if (this != &other) { + using std::swap; + swap(data_, other.data_); + swap(file_handle_, other.file_handle_); +#ifdef _WIN32 + swap(file_mapping_handle_, other.file_mapping_handle_); +#endif + swap(length_, other.length_); + swap(mapped_length_, other.mapped_length_); + swap(is_handle_internal_, other.is_handle_internal_); + } +} + +template <access_mode AccessMode, typename ByteT> +template <access_mode A> +typename std::enable_if<A == access_mode::write, void>::type +basic_mmap<AccessMode, ByteT>::conditional_sync() { + // This is invoked from the destructor, so not much we can do about + // failures here. + std::error_code ec; + sync(ec); +} + +template <access_mode AccessMode, typename ByteT> +template <access_mode A> +typename std::enable_if<A == access_mode::read, void>::type +basic_mmap<AccessMode, ByteT>::conditional_sync() { + // noop +} + +template <access_mode AccessMode, typename ByteT> +bool operator==(const basic_mmap<AccessMode, ByteT> &a, const basic_mmap<AccessMode, ByteT> &b) { + return a.data() == b.data() && a.size() == b.size(); +} + +template <access_mode AccessMode, typename ByteT> +bool operator!=(const basic_mmap<AccessMode, ByteT> &a, const basic_mmap<AccessMode, ByteT> &b) { + return !(a == b); +} + +template <access_mode AccessMode, typename ByteT> +bool operator<(const basic_mmap<AccessMode, ByteT> &a, const basic_mmap<AccessMode, ByteT> &b) { + if (a.data() == b.data()) { + return a.size() < b.size(); + } + return a.data() < b.data(); +} + +template <access_mode AccessMode, typename ByteT> +bool operator<=(const basic_mmap<AccessMode, ByteT> &a, const basic_mmap<AccessMode, ByteT> &b) { + return !(a > b); +} + +template <access_mode AccessMode, typename ByteT> +bool operator>(const basic_mmap<AccessMode, ByteT> &a, const basic_mmap<AccessMode, ByteT> &b) { + if (a.data() == b.data()) { + return a.size() > b.size(); + } + return a.data() > b.data(); +} + +template <access_mode AccessMode, typename ByteT> +bool operator>=(const basic_mmap<AccessMode, ByteT> &a, const basic_mmap<AccessMode, ByteT> &b) { + return !(a < b); +} + +} // namespace mio + +#endif // MIO_BASIC_MMAP_IMPL + +#endif // MIO_MMAP_HEADER +/* Copyright 2017 https://github.com/mandreyel + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation files (the "Software"), to deal in the Software + * without restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be included in all copies + * or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef MIO_PAGE_HEADER +#define MIO_PAGE_HEADER + +#ifdef _WIN32 +#include <windows.h> +#else +#include <unistd.h> +#endif + +namespace mio { + +/** + * This is used by `basic_mmap` to determine whether to create a read-only or + * a read-write memory mapping. + */ +enum class access_mode { read, write }; + +/** + * Determines the operating system's page allocation granularity. + * + * On the first call to this function, it invokes the operating system specific syscall + * to determine the page size, caches the value, and returns it. Any subsequent call to + * this function serves the cached value, so no further syscalls are made. + */ +inline size_t page_size() { + static const size_t page_size = [] { +#ifdef _WIN32 + SYSTEM_INFO SystemInfo; + GetSystemInfo(&SystemInfo); + return SystemInfo.dwAllocationGranularity; +#else + return sysconf(_SC_PAGE_SIZE); +#endif + }(); + return page_size; +} + +/** + * Alligns `offset` to the operating's system page size such that it subtracts the + * difference until the nearest page boundary before `offset`, or does nothing if + * `offset` is already page aligned. + */ +inline size_t make_offset_page_aligned(size_t offset) noexcept { + const size_t page_size_ = page_size(); + // Use integer division to round down to the nearest page alignment. + return offset / page_size_ * page_size_; +} + +} // namespace mio + +#endif // MIO_PAGE_HEADER +/* Copyright 2017 https://github.com/mandreyel + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation files (the "Software"), to deal in the Software + * without restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be included in all copies + * or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef MIO_SHARED_MMAP_HEADER +#define MIO_SHARED_MMAP_HEADER + +// #include "mio/mmap.hpp" + +#include <memory> // std::shared_ptr +#include <system_error> // std::error_code + +namespace mio { + +/** + * Exposes (nearly) the same interface as `basic_mmap`, but endowes it with + * `std::shared_ptr` semantics. + * + * This is not the default behaviour of `basic_mmap` to avoid allocating on the heap if + * shared semantics are not required. + */ +template <access_mode AccessMode, typename ByteT> class basic_shared_mmap { + using impl_type = basic_mmap<AccessMode, ByteT>; + std::shared_ptr<impl_type> pimpl_; + +public: + using value_type = typename impl_type::value_type; + using size_type = typename impl_type::size_type; + using reference = typename impl_type::reference; + using const_reference = typename impl_type::const_reference; + using pointer = typename impl_type::pointer; + using const_pointer = typename impl_type::const_pointer; + using difference_type = typename impl_type::difference_type; + using iterator = typename impl_type::iterator; + using const_iterator = typename impl_type::const_iterator; + using reverse_iterator = typename impl_type::reverse_iterator; + using const_reverse_iterator = typename impl_type::const_reverse_iterator; + using iterator_category = typename impl_type::iterator_category; + using handle_type = typename impl_type::handle_type; + using mmap_type = impl_type; + + basic_shared_mmap() = default; + basic_shared_mmap(const basic_shared_mmap &) = default; + basic_shared_mmap &operator=(const basic_shared_mmap &) = default; + basic_shared_mmap(basic_shared_mmap &&) = default; + basic_shared_mmap &operator=(basic_shared_mmap &&) = default; + + /** Takes ownership of an existing mmap object. */ + basic_shared_mmap(mmap_type &&mmap) : pimpl_(std::make_shared<mmap_type>(std::move(mmap))) {} + + /** Takes ownership of an existing mmap object. */ + basic_shared_mmap &operator=(mmap_type &&mmap) { + pimpl_ = std::make_shared<mmap_type>(std::move(mmap)); + return *this; + } + + /** Initializes this object with an already established shared mmap. */ + basic_shared_mmap(std::shared_ptr<mmap_type> mmap) : pimpl_(std::move(mmap)) {} + + /** Initializes this object with an already established shared mmap. */ + basic_shared_mmap &operator=(std::shared_ptr<mmap_type> mmap) { + pimpl_ = std::move(mmap); + return *this; + } + +#ifdef __cpp_exceptions + /** + * The same as invoking the `map` function, except any error that may occur + * while establishing the mapping is wrapped in a `std::system_error` and is + * thrown. + */ + template <typename String> + basic_shared_mmap(const String &path, const size_type offset = 0, + const size_type length = map_entire_file) { + std::error_code error; + map(path, offset, length, error); + if (error) { + throw std::system_error(error); + } + } + + /** + * The same as invoking the `map` function, except any error that may occur + * while establishing the mapping is wrapped in a `std::system_error` and is + * thrown. + */ + basic_shared_mmap(const handle_type handle, const size_type offset = 0, + const size_type length = map_entire_file) { + std::error_code error; + map(handle, offset, length, error); + if (error) { + throw std::system_error(error); + } + } +#endif // __cpp_exceptions + + /** + * If this is a read-write mapping and the last reference to the mapping, + * the destructor invokes sync. Regardless of the access mode, unmap is + * invoked as a final step. + */ + ~basic_shared_mmap() = default; + + /** Returns the underlying `std::shared_ptr` instance that holds the mmap. */ + std::shared_ptr<mmap_type> get_shared_ptr() { return pimpl_; } + + /** + * On UNIX systems 'file_handle' and 'mapping_handle' are the same. On Windows, + * however, a mapped region of a file gets its own handle, which is returned by + * 'mapping_handle'. + */ + handle_type file_handle() const noexcept { + return pimpl_ ? pimpl_->file_handle() : invalid_handle; + } + + handle_type mapping_handle() const noexcept { + return pimpl_ ? pimpl_->mapping_handle() : invalid_handle; + } + + /** Returns whether a valid memory mapping has been created. */ + bool is_open() const noexcept { return pimpl_ && pimpl_->is_open(); } + + /** + * Returns true if no mapping was established, that is, conceptually the + * same as though the length that was mapped was 0. This function is + * provided so that this class has Container semantics. + */ + bool empty() const noexcept { return !pimpl_ || pimpl_->empty(); } + + /** + * `size` and `length` both return the logical length, i.e. the number of bytes + * user requested to be mapped, while `mapped_length` returns the actual number of + * bytes that were mapped which is a multiple of the underlying operating system's + * page allocation granularity. + */ + size_type size() const noexcept { return pimpl_ ? pimpl_->length() : 0; } + size_type length() const noexcept { return pimpl_ ? pimpl_->length() : 0; } + size_type mapped_length() const noexcept { return pimpl_ ? pimpl_->mapped_length() : 0; } + + /** + * Returns a pointer to the first requested byte, or `nullptr` if no memory mapping + * exists. + */ + template <access_mode A = AccessMode, + typename = typename std::enable_if<A == access_mode::write>::type> + pointer data() noexcept { + return pimpl_->data(); + } + const_pointer data() const noexcept { return pimpl_ ? pimpl_->data() : nullptr; } + + /** + * Returns an iterator to the first requested byte, if a valid memory mapping + * exists, otherwise this function call is undefined behaviour. + */ + iterator begin() noexcept { return pimpl_->begin(); } + const_iterator begin() const noexcept { return pimpl_->begin(); } + const_iterator cbegin() const noexcept { return pimpl_->cbegin(); } + + /** + * Returns an iterator one past the last requested byte, if a valid memory mapping + * exists, otherwise this function call is undefined behaviour. + */ + template <access_mode A = AccessMode, + typename = typename std::enable_if<A == access_mode::write>::type> + iterator end() noexcept { + return pimpl_->end(); + } + const_iterator end() const noexcept { return pimpl_->end(); } + const_iterator cend() const noexcept { return pimpl_->cend(); } + + /** + * Returns a reverse iterator to the last memory mapped byte, if a valid + * memory mapping exists, otherwise this function call is undefined + * behaviour. + */ + template <access_mode A = AccessMode, + typename = typename std::enable_if<A == access_mode::write>::type> + reverse_iterator rbegin() noexcept { + return pimpl_->rbegin(); + } + const_reverse_iterator rbegin() const noexcept { return pimpl_->rbegin(); } + const_reverse_iterator crbegin() const noexcept { return pimpl_->crbegin(); } + + /** + * Returns a reverse iterator past the first mapped byte, if a valid memory + * mapping exists, otherwise this function call is undefined behaviour. + */ + template <access_mode A = AccessMode, + typename = typename std::enable_if<A == access_mode::write>::type> + reverse_iterator rend() noexcept { + return pimpl_->rend(); + } + const_reverse_iterator rend() const noexcept { return pimpl_->rend(); } + const_reverse_iterator crend() const noexcept { return pimpl_->crend(); } + + /** + * Returns a reference to the `i`th byte from the first requested byte (as returned + * by `data`). If this is invoked when no valid memory mapping has been created + * prior to this call, undefined behaviour ensues. + */ + reference operator[](const size_type i) noexcept { return (*pimpl_)[i]; } + const_reference operator[](const size_type i) const noexcept { return (*pimpl_)[i]; } + + /** + * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the + * reason is reported via `error` and the object remains in a state as if this + * function hadn't been called. + * + * `path`, which must be a path to an existing file, is used to retrieve a file + * handle (which is closed when the object destructs or `unmap` is called), which is + * then used to memory map the requested region. Upon failure, `error` is set to + * indicate the reason and the object remains in an unmapped state. + * + * `offset` is the number of bytes, relative to the start of the file, where the + * mapping should begin. When specifying it, there is no need to worry about + * providing a value that is aligned with the operating system's page allocation + * granularity. This is adjusted by the implementation such that the first requested + * byte (as returned by `data` or `begin`), so long as `offset` is valid, will be at + * `offset` from the start of the file. + * + * `length` is the number of bytes to map. It may be `map_entire_file`, in which + * case a mapping of the entire file is created. + */ + template <typename String> + void map(const String &path, const size_type offset, const size_type length, + std::error_code &error) { + map_impl(path, offset, length, error); + } + + /** + * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the + * reason is reported via `error` and the object remains in a state as if this + * function hadn't been called. + * + * `path`, which must be a path to an existing file, is used to retrieve a file + * handle (which is closed when the object destructs or `unmap` is called), which is + * then used to memory map the requested region. Upon failure, `error` is set to + * indicate the reason and the object remains in an unmapped state. + * + * The entire file is mapped. + */ + template <typename String> void map(const String &path, std::error_code &error) { + map_impl(path, 0, map_entire_file, error); + } + + /** + * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the + * reason is reported via `error` and the object remains in a state as if this + * function hadn't been called. + * + * `handle`, which must be a valid file handle, which is used to memory map the + * requested region. Upon failure, `error` is set to indicate the reason and the + * object remains in an unmapped state. + * + * `offset` is the number of bytes, relative to the start of the file, where the + * mapping should begin. When specifying it, there is no need to worry about + * providing a value that is aligned with the operating system's page allocation + * granularity. This is adjusted by the implementation such that the first requested + * byte (as returned by `data` or `begin`), so long as `offset` is valid, will be at + * `offset` from the start of the file. + * + * `length` is the number of bytes to map. It may be `map_entire_file`, in which + * case a mapping of the entire file is created. + */ + void map(const handle_type handle, const size_type offset, const size_type length, + std::error_code &error) { + map_impl(handle, offset, length, error); + } + + /** + * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the + * reason is reported via `error` and the object remains in a state as if this + * function hadn't been called. + * + * `handle`, which must be a valid file handle, which is used to memory map the + * requested region. Upon failure, `error` is set to indicate the reason and the + * object remains in an unmapped state. + * + * The entire file is mapped. + */ + void map(const handle_type handle, std::error_code &error) { + map_impl(handle, 0, map_entire_file, error); + } + + /** + * If a valid memory mapping has been created prior to this call, this call + * instructs the kernel to unmap the memory region and disassociate this object + * from the file. + * + * The file handle associated with the file that is mapped is only closed if the + * mapping was created using a file path. If, on the other hand, an existing + * file handle was used to create the mapping, the file handle is not closed. + */ + void unmap() { + if (pimpl_) + pimpl_->unmap(); + } + + void swap(basic_shared_mmap &other) { pimpl_.swap(other.pimpl_); } + + /** Flushes the memory mapped page to disk. Errors are reported via `error`. */ + template <access_mode A = AccessMode, + typename = typename std::enable_if<A == access_mode::write>::type> + void sync(std::error_code &error) { + if (pimpl_) + pimpl_->sync(error); + } + + /** All operators compare the underlying `basic_mmap`'s addresses. */ + + friend bool operator==(const basic_shared_mmap &a, const basic_shared_mmap &b) { + return a.pimpl_ == b.pimpl_; + } + + friend bool operator!=(const basic_shared_mmap &a, const basic_shared_mmap &b) { + return !(a == b); + } + + friend bool operator<(const basic_shared_mmap &a, const basic_shared_mmap &b) { + return a.pimpl_ < b.pimpl_; + } + + friend bool operator<=(const basic_shared_mmap &a, const basic_shared_mmap &b) { + return a.pimpl_ <= b.pimpl_; + } + + friend bool operator>(const basic_shared_mmap &a, const basic_shared_mmap &b) { + return a.pimpl_ > b.pimpl_; + } + + friend bool operator>=(const basic_shared_mmap &a, const basic_shared_mmap &b) { + return a.pimpl_ >= b.pimpl_; + } + +private: + template <typename MappingToken> + void map_impl(const MappingToken &token, const size_type offset, const size_type length, + std::error_code &error) { + if (!pimpl_) { + mmap_type mmap = make_mmap<mmap_type>(token, offset, length, error); + if (error) { + return; + } + pimpl_ = std::make_shared<mmap_type>(std::move(mmap)); + } else { + pimpl_->map(token, offset, length, error); + } + } +}; + +/** + * This is the basis for all read-only mmap objects and should be preferred over + * directly using basic_shared_mmap. + */ +template <typename ByteT> +using basic_shared_mmap_source = basic_shared_mmap<access_mode::read, ByteT>; + +/** + * This is the basis for all read-write mmap objects and should be preferred over + * directly using basic_shared_mmap. + */ +template <typename ByteT> +using basic_shared_mmap_sink = basic_shared_mmap<access_mode::write, ByteT>; + +/** + * These aliases cover the most common use cases, both representing a raw byte stream + * (either with a char or an unsigned char/uint8_t). + */ +using shared_mmap_source = basic_shared_mmap_source<char>; +using shared_ummap_source = basic_shared_mmap_source<unsigned char>; + +using shared_mmap_sink = basic_shared_mmap_sink<char>; +using shared_ummap_sink = basic_shared_mmap_sink<unsigned char>; + +} // namespace mio + +#endif // MIO_SHARED_MMAP_HEADER diff --git a/Reconstruction/RecActsTracking/RecActsSvc/src/csv2/parameters.hpp b/Reconstruction/RecActsTracking/RecActsSvc/src/csv2/parameters.hpp new file mode 100644 index 00000000..f3a858c1 --- /dev/null +++ b/Reconstruction/RecActsTracking/RecActsSvc/src/csv2/parameters.hpp @@ -0,0 +1,50 @@ + +#pragma once +#include <utility> + +namespace csv2 { + +namespace trim_policy { +struct no_trimming { +public: + static std::pair<size_t, size_t> trim(const char *buffer, size_t start, size_t end) { + (void)(buffer); // to silence unused parameter warning + return {start, end}; + } +}; + +template <char... character_list> struct trim_characters { +private: + constexpr static bool is_trim_char(char) { return false; } + + template <class... Tail> constexpr static bool is_trim_char(char c, char head, Tail... tail) { + return c == head || is_trim_char(c, tail...); + } + +public: + static std::pair<size_t, size_t> trim(const char *buffer, size_t start, size_t end) { + size_t new_start = start, new_end = end; + while (new_start != new_end && is_trim_char(buffer[new_start], character_list...)) + ++new_start; + while (new_start != new_end && is_trim_char(buffer[new_end - 1], character_list...)) + --new_end; + return {new_start, new_end}; + } +}; + +using trim_whitespace = trim_characters<' ', '\t'>; +} // namespace trim_policy + +template <char character> struct delimiter { + constexpr static char value = character; +}; + +template <char character> struct quote_character { + constexpr static char value = character; +}; + +template <bool flag> struct first_row_is_header { + constexpr static bool value = flag; +}; + +} \ No newline at end of file diff --git a/Reconstruction/RecActsTracking/RecActsSvc/src/csv2/reader.hpp b/Reconstruction/RecActsTracking/RecActsSvc/src/csv2/reader.hpp new file mode 100644 index 00000000..4fb93bbd --- /dev/null +++ b/Reconstruction/RecActsTracking/RecActsSvc/src/csv2/reader.hpp @@ -0,0 +1,306 @@ + +#pragma once +#include <cstring> +#if __has_include("sys/mman.h") || __has_include(<sys/mman.h>) || __has_include("windows.h") || __has_include(<windows.h>) +#define __CSV2_HAS_MMAN_H__ 1 +#include "mio.hpp" +#endif +#include "parameters.hpp" +#include <istream> +#include <string> +#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L) + #include <string_view> +#endif + +namespace csv2 { + +template <class delimiter = delimiter<','>, class quote_character = quote_character<'"'>, + class first_row_is_header = first_row_is_header<true>, + class trim_policy = trim_policy::trim_whitespace> +class Reader { + #if __CSV2_HAS_MMAN_H__ + mio::mmap_source mmap_; // mmap source + #endif + const char *buffer_{nullptr}; // pointer to memory-mapped data + size_t buffer_size_{0}; // mapped length of buffer + size_t header_start_{0}; // start index of header (cache) + size_t header_end_{0}; // end index of header (cache) + +public: + #if __CSV2_HAS_MMAN_H__ + // Use this if you'd like to mmap the CSV file + template <typename StringType> bool mmap(StringType &&filename) { + mmap_ = mio::mmap_source(filename); + if (!mmap_.is_open() || !mmap_.is_mapped()) + return false; + buffer_ = mmap_.data(); + buffer_size_ = mmap_.mapped_length(); + return true; + } + #endif + + // Use this if you have the CSV contents + // in an std::string already + template <typename StringType> bool parse(StringType &&contents) { + buffer_ = std::forward<StringType>(contents).c_str(); + buffer_size_ = contents.size(); + return buffer_size_ > 0; + } + + + // Use this if you already have the CSV contents + // in a std::string_view +#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L) + bool parse_view(std::string_view sv) { + buffer_ = sv.data(); + buffer_size_ = sv.size(); + return buffer_size_ > 0; + } +#endif + + + class RowIterator; + class Row; + class CellIterator; + + class Cell { + const char *buffer_{nullptr}; // Pointer to memory-mapped buffer + size_t start_{0}; // Start index of cell content + size_t end_{0}; // End index of cell content + bool escaped_{false}; // Does the cell have escaped content? + friend class Row; + friend class CellIterator; + + public: + + // returns a view on the cell's contents if C++17 available + #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L) + std::string_view read_view() const { + const auto new_start_end = trim_policy::trim(buffer_, start_, end_); + return std::string_view(buffer_ + new_start_end.first, new_start_end.second- new_start_end.first); + } + #endif + // Returns the raw_value of the cell without handling escaped + // content, e.g., cell containing """foo""" will be returned + // as is + template <typename Container> void read_raw_value(Container &result) const { + if (start_ >= end_) + return; + result.reserve(end_ - start_); + for (size_t i = start_; i < end_; ++i) + result.push_back(buffer_[i]); + } + + // If cell is escaped, convert and return correct cell contents, + // e.g., """foo""" => ""foo"" + template <typename Container> void read_value(Container &result) const { + if (start_ >= end_) + return; + result.reserve(end_ - start_); + const auto new_start_end = trim_policy::trim(buffer_, start_, end_); + for (size_t i = new_start_end.first; i < new_start_end.second; ++i) + result.push_back(buffer_[i]); + for (size_t i = 1; i < result.size(); ++i) { + if (result[i] == quote_character::value && result[i - 1] == quote_character::value) { + result.erase(i - 1, 1); + } + } + } + }; + + class Row { + const char *buffer_{nullptr}; // Pointer to memory-mapped buffer + size_t start_{0}; // Start index of row content + size_t end_{0}; // End index of row content + friend class RowIterator; + friend class Reader; + + public: + // address of row + const char *address() const { return buffer_; } + // returns the char length of the row + size_t length() const { return end_ - start_; } + + // Returns the raw_value of the row + template <typename Container> void read_raw_value(Container &result) const { + if (start_ >= end_) + return; + result.reserve(end_ - start_); + for (size_t i = start_; i < end_; ++i) + result.push_back(buffer_[i]); + } + + class CellIterator { + friend class Row; + const char *buffer_; + size_t buffer_size_; + size_t start_; + size_t current_; + size_t end_; + + public: + CellIterator(const char *buffer, size_t buffer_size, size_t start, size_t end) + : buffer_(buffer), buffer_size_(buffer_size), start_(start), current_(start_), end_(end) { + } + + CellIterator &operator++() { + current_ += 1; + return *this; + } + + Cell operator*() { + bool escaped{false}; + class Cell cell; + cell.buffer_ = buffer_; + cell.start_ = current_; + cell.end_ = end_; + + size_t last_quote_location = 0; + bool quote_opened = false; + for (auto i = current_; i < end_; i++) { + current_ = i; + if (buffer_[i] == delimiter::value && !quote_opened) { + // actual delimiter + // end of cell + cell.end_ = current_; + cell.escaped_ = escaped; + return cell; + } else { + if (buffer_[i] == quote_character::value) { + if (!quote_opened) { + // first quote for this cell + quote_opened = true; + last_quote_location = i; + } else { + escaped = (last_quote_location == i - 1); + last_quote_location += (i - last_quote_location) * size_t(!escaped); + quote_opened = escaped || (buffer_[i + 1] != delimiter::value); + } + } + } + } + cell.end_ = current_ + 1; + return cell; + } + + bool operator!=(const CellIterator &rhs) { return current_ != rhs.current_; } + }; + + CellIterator begin() const { return CellIterator(buffer_, end_ - start_, start_, end_); } + CellIterator end() const { return CellIterator(buffer_, end_ - start_, end_, end_); } + }; + + class RowIterator { + friend class Reader; + const char *buffer_; + size_t buffer_size_; + size_t start_; + size_t end_; + + public: + RowIterator(const char *buffer, size_t buffer_size, size_t start) + : buffer_(buffer), buffer_size_(buffer_size), start_(start), end_(start_) {} + + RowIterator &operator++() { + start_ = end_ + 1; + end_ = start_; + return *this; + } + + Row operator*() { + Row result; + result.buffer_ = buffer_; + result.start_ = start_; + result.end_ = end_; + + if (const char *ptr = + static_cast<const char *>(memchr(&buffer_[start_], '\n', (buffer_size_ - start_)))) { + end_ = start_ + (ptr - &buffer_[start_]); + result.end_ = end_; + start_ = end_ + 1; + } else { + // last row + end_ = buffer_size_; + result.end_ = end_; + } + return result; + } + + bool operator!=(const RowIterator &rhs) { return start_ != rhs.start_; } + }; + + RowIterator begin() const { + if (buffer_size_ == 0) + return end(); + if (first_row_is_header::value) { + const auto header_indices = header_indices_(); + return RowIterator(buffer_, buffer_size_, header_indices.second > 0 ? header_indices.second + 1 : 0); + } else { + return RowIterator(buffer_, buffer_size_, 0); + } + } + + RowIterator end() const { return RowIterator(buffer_, buffer_size_, buffer_size_ + 1); } + +private: + std::pair<size_t, size_t> header_indices_() const { + size_t start = 0, end = 0; + + if (const char *ptr = + static_cast<const char *>(memchr(&buffer_[start], '\n', (buffer_size_ - start)))) { + end = start + (ptr - &buffer_[start]); + } + return {start, end}; + } + +public: + + Row header() const { + size_t start = 0, end = 0; + Row result; + result.buffer_ = buffer_; + result.start_ = start; + result.end_ = end; + + if (const char *ptr = + static_cast<const char *>(memchr(&buffer_[start], '\n', (buffer_size_ - start)))) { + end = start + (ptr - &buffer_[start]); + result.end_ = end; + } + return result; + } + + /** + * @returns The number of rows (excluding the header) + */ + size_t rows(bool ignore_empty_lines = false) const { + size_t result{0}; + if (!buffer_ || buffer_size_ == 0) + return result; + + // Count the first row if not header + if (not first_row_is_header::value + and (not ignore_empty_lines + or *(static_cast<const char*>(buffer_)) != '\r')) + ++result; + + for (const char *p = buffer_ + ; (p = static_cast<const char *>(memchr(p, '\n', (buffer_ + buffer_size_) - p))) + ; ++p) { + if (ignore_empty_lines + and (p >= buffer_ + buffer_size_ - 1 + or *(p + 1) == '\r')) + continue; + ++result; + } + return result; + } + + size_t cols() const { + size_t result{0}; + for (const auto cell : header()) + result += 1; + return result; + } +}; +} // namespace csv2 diff --git a/Reconstruction/RecActsTracking/RecActsSvc/src/csv2/writer.hpp b/Reconstruction/RecActsTracking/RecActsSvc/src/csv2/writer.hpp new file mode 100644 index 00000000..1d813ab8 --- /dev/null +++ b/Reconstruction/RecActsTracking/RecActsSvc/src/csv2/writer.hpp @@ -0,0 +1,38 @@ + +#pragma once +#include <cstring> +#include "parameters.hpp" +#include <fstream> +#include <iostream> +#include <iterator> +#include <string> +#include <utility> + +namespace csv2 { + +template <class delimiter = delimiter<','>, typename Stream = std::ofstream> class Writer { + Stream &stream_; // output stream for the writer +public: + Writer(Stream &stream) : stream_(stream) {} + + ~Writer() { + stream_.close(); + } + + template <typename Container> void write_row(Container &&row) { + const auto &strings = std::forward<Container>(row); + const auto delimiter_string = std::string(1, delimiter::value); + std::copy(strings.begin(), strings.end() - 1, + std::ostream_iterator<std::string>(stream_, delimiter_string.c_str())); + stream_ << strings.back() << "\n"; + } + + template <typename Container> void write_rows(Container &&rows) { + const auto &container_of_rows = std::forward<Container>(rows); + for (const auto &row : container_of_rows) { + write_row(row); + } + } +}; + +} // namespace csv2 diff --git a/Reconstruction/RecActsTracking/RecActsTracking/CMakeLists.txt b/Reconstruction/RecActsTracking/RecActsTracking/CMakeLists.txt new file mode 100644 index 00000000..a0aad036 --- /dev/null +++ b/Reconstruction/RecActsTracking/RecActsTracking/CMakeLists.txt @@ -0,0 +1,46 @@ +find_package(Acts COMPONENTS + Core PluginFpeMonitoring PluginGeant4 PluginJson + PluginTGeo PluginDD4hep PluginEDM4hep Fatras) + +if(NOT Acts_FOUND) + message("Acts package not found. RecActsTracking module requires Acts.") + return() +endif() + +gaudi_add_module(RecActsTracking + SOURCES + src/RecActsReadInput.cpp + src/RecActsTruthInput.cpp + src/RecActsSeeding.cpp + src/RecActsTrackParamsEstimation.cpp + src/RecActsTrackFinding.cpp + src/RecActsTrackFitting.cpp + # src/RecActsTrackReFitting.cpp + # src/RecActsTruthTracking.cpp + LINK DetInterface + k4FWCore::k4FWCore + Gaudi::GaudiAlgLib Gaudi::GaudiKernel + DataHelperLib + ${LCIO_LIBRARIES} + ${DD4hep_COMPONENT_LIBRARIES} + EDM4HEP::edm4hep EDM4HEP::edm4hepDict + ${podio_LIBRARIES} podio::podioRootIO + GearSvc ${GEAR_LIBRARIES} + RecActsSvc + ActsCore ActsPluginFpeMonitoring ActsPluginGeant4 + ActsPluginJson ActsPluginTGeo ActsPluginDD4hep + ActsPluginEDM4hep ActsFatras +) + +target_include_directories(RecActsTracking PUBLIC $ENV{ACTS}/include) + +target_include_directories(RecActsTracking PUBLIC + ${LCIO_INCLUDE_DIRS} + $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}>/include + $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>) + +install(TARGETS RecActsTracking + EXPORT CEPCSWTargets + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT bin + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT shlib + COMPONENT dev) diff --git a/Reconstruction/RecActsTracking/RecActsTracking/options/RecActsTracking.py b/Reconstruction/RecActsTracking/RecActsTracking/options/RecActsTracking.py new file mode 100644 index 00000000..0a99619e --- /dev/null +++ b/Reconstruction/RecActsTracking/RecActsTracking/options/RecActsTracking.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python +import os +from Gaudi.Configuration import * + +from Configurables import k4DataSvc +dsvc = k4DataSvc("EventDataSvc", input="rec_v01.root") + +from Configurables import PodioInput +podioinput = PodioInput("PodioReader", collections=[ +# "EventHeader", + "MCParticle", + "VXDCollection", + "VXDTrackerHits", + "ITKBarrelCollection", + "ITKBarrelTrackerHits", + "ITKEndcapCollection", + "ITKEndcapTrackerHits", + "TPCCollection", + "TPCTrackerHits", + "OTKBarrelCollection", + "OTKBarrelTrackerHits", + "OTKEndcapCollection", + "OTKEndcapTrackerHits", + ]) + +############################################################################## +# Geometry Svc +############################################################################## + +geometry_option = "TDR_o1_v01/TDR_o1_v01.xml" + +if not os.getenv("DETCRDROOT"): + print("Can't find the geometry. Please setup envvar DETCRDROOT." ) + sys.exit(-1) + +geometry_path = os.path.join(os.getenv("DETCRDROOT"), "compact", geometry_option) +if not os.path.exists(geometry_path): + print("Can't find the compact geometry file: %s"%geometry_path) + sys.exit(-1) + +from Configurables import DetGeomSvc +geosvc = DetGeomSvc("GeomSvc") +geosvc.compact = geometry_path + +from Configurables import MarlinEvtSeeder +evtseeder = MarlinEvtSeeder("EventSeeder") + +from Configurables import GearSvc +gearsvc = GearSvc("GearSvc") + +from Configurables import TrackSystemSvc +tracksystemsvc = TrackSystemSvc("TrackSystemSvc") + +############################################################################## +# RecActsSvc +############################################################################## + +cepcswdatatop ="/cvmfs/cepcsw.ihep.ac.cn/prototype/releases/data/latest" + +from Configurables import RecActsSvc +recactssvc = RecActsSvc("RecActsSvc") +recactssvc.TGeoFile = os.path.join(cepcswdatatop, "CEPCSWData/offline-data/Reconstruction/RecActsTracking/data/tdr25.5.0/CEPC-tgeo.root") +recactssvc.TGeoConfigFile = os.path.join(cepcswdatatop, "CEPCSWData/offline-data/Reconstruction/RecActsTracking/data/tdr25.5.0/CEPC-tgeo-config.json") +recactssvc.MaterialMapFile = os.path.join(cepcswdatatop, "CEPCSWData/offline-data/Reconstruction/RecActsTracking/data/tdr25.5.0/CEPC-material-maps") + +############################################################################## +# RecActsTracking +############################################################################## + +from Configurables import RecActsReadInput +from Configurables import RecActsSeeding +from Configurables import RecActsTrackParamsEstimation +from Configurables import RecActsTrackFinding +from Configurables import RecActsTrackFitting + +############################################################################## +# Silicon Track +############################################################################## +# include read VTX+SIT, seeding, param estimation, track finding +# only use VTX + SIT +ReadSi = RecActsReadInput("ActsReadSi") +ReadSi.useVTX = True +ReadSi.useITKBarrel = True +ReadSi.useITKEndcap = True +ReadSi.useTPC = False +ReadSi.useOTKBarrel = False +ReadSi.useOTKEndcap = False + +Seeding = RecActsSeeding("ActsSeeding") +Seeding.SeedDeltaRMin = 0.05 + +TrackParamsEstimation = RecActsTrackParamsEstimation("ActsTrackParamsEstimation") +TrackParamsEstimation.AssumeParticle = "muon" +# TrackParamsEstimation.AssumeParticle = "electron" +TrackParamsEstimation.initialVarInflation = [1, 1, 10, 10, 10, 10] + +SiTrackFinding = RecActsTrackFinding("ActsSiTrackFinding") +SiTrackFinding.ACTSFindOutCol = "ACTSSiTracks" +SiTrackFinding.numMeasurementsCutOff = 2 + +############################################################################## +# Full Track +############################################################################## +# include read TPC+OTK, track finding, track fitting +# use VTX + SIT + TPC + OTK + +ReadOuter = RecActsReadInput("ACTSReadOuter") +ReadOuter.useVTX = False +ReadOuter.useITKBarrel = False +ReadOuter.useITKEndcap = False +ReadOuter.useTPC = True +ReadOuter.useOTKBarrel = True +ReadOuter.useOTKEndcap = True +ReadOuter.CleanBeforeRead = False + +FullTrackFinding = RecActsTrackFinding("ActsFullTrackFinding") +FullTrackFinding.ACTSFindOutCol = "ACTSFullTracks" +FullTrackFinding.numMeasurementsCutOff = 2 + +TrackFitting = RecActsTrackFitting("ActsTrackFitting") +TrackFitting.ACTSFitOutCol = "ACTSCompleteTracks" +TrackFitting.fitType = "kalman" +# TrackFitting.fitType = "gsf" +# TrackFitting.maxComponents = 12 + +############################################################################## +# output +############################################################################## +from Configurables import PodioOutput +out = PodioOutput("out") +out.filename = "rec_acts.root" +out.outputCommands = ["keep *"] + +# ApplicationMgr +from Configurables import ApplicationMgr +mgr = ApplicationMgr( + # TopAlg = [podioinput, ActsReadInput, ActsSeeding, out], + TopAlg = [podioinput, ReadSi, Seeding, TrackParamsEstimation, SiTrackFinding, ReadOuter, FullTrackFinding, TrackFitting, out], + EvtSel = 'NONE', + EvtMax = -1, + ExtSvc = [dsvc, geosvc, evtseeder, recactssvc], + # OutputLevel=DEBUG +) diff --git a/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsReadInput.cpp b/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsReadInput.cpp new file mode 100644 index 00000000..c02b76aa --- /dev/null +++ b/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsReadInput.cpp @@ -0,0 +1,447 @@ +// dependence +#include "RecActsReadInput.h" + +DECLARE_COMPONENT(RecActsReadInput) + +RecActsReadInput::RecActsReadInput(const std::string& name, ISvcLocator* svcLoc) + : GaudiAlgorithm(name, svcLoc) +{ +} + +StatusCode RecActsReadInput::initialize() +{ + // -------------------------------- + // ---- initialize properties ----- + // -------------------------------- + + m_geosvc = service<IGeomSvc>("GeomSvc"); + if (!m_geosvc) { + error() << "Failed to get GeomSvc" << endmsg; + return StatusCode::FAILURE; + } + + vtx_decoder = m_geosvc->getDecoder("VXDCollection"); + if(!vtx_decoder){ + info() << "Failed to create vtx_decoder" << endmsg; + return StatusCode::FAILURE; + } + + ITKBarrel_decoder = m_geosvc->getDecoder("ITKBarrelCollection"); + if(!ITKBarrel_decoder){ + info() << "Failed to create ITKBarrel_decoder" << endmsg; + return StatusCode::FAILURE; + } + + ITKEndcap_decoder = m_geosvc->getDecoder("ITKEndcapCollection"); + if(!ITKEndcap_decoder){ + info() << "Failed to create ITKEndcap_decoder" << endmsg; + return StatusCode::FAILURE; + } + + tpc_decoder = m_geosvc->getDecoder("TPCCollection"); + if(!tpc_decoder){ + info() << "Failed to create TPC_decoder" << endmsg; + return StatusCode::FAILURE; + } + + OTKBarrel_decoder = m_geosvc->getDecoder("OTKBarrelCollection"); + if(!OTKBarrel_decoder){ + info() << "Failed to create OTKBarrel_decoder" << endmsg; + return StatusCode::FAILURE; + } + + OTKEndcap_decoder = m_geosvc->getDecoder("OTKEndcapCollection"); + if(!OTKEndcap_decoder){ + info() << "Failed to create OTKEndcap_decoder" << endmsg; + return StatusCode::FAILURE; + } + + // -------------------------------- + // ---- initialize recActsSvc ---- + // -------------------------------- + + recActsSvc = service<IRecActsSvc>("RecActsSvc"); + if (!recActsSvc) { + error() << "Failed to get RecActsSvc" << endmsg; + return StatusCode::FAILURE; + } + + chronoStatSvc = service<IChronoStatSvc>("ChronoStatSvc"); + + _nEvt = -1; + return StatusCode::SUCCESS; +} + +StatusCode RecActsReadInput::execute() +{ + _nEvt++; + isGoodEvent = true; + + if (CleanBeforeRead.value()) { + recActsSvc->Clean(); + VTXhits_num = 0; + ITKhits_num = 0; + + if (collect_bad_events.value()) { + const edm4hep::MCParticleCollection* mcCols = nullptr; + try { mcCols = _inMCColHdl.get(); } + catch ( GaudiException &e ) { + debug() << "Collection " << _inMCColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; + return StatusCode::FAILURE; + } + + for(const auto& mc : *mcCols){ + if (mc.getGeneratorStatus() != 1){ + info() << "MCParticle " << mc.getPDG() << " is not primary at event " << _nEvt << endmsg; + isGoodEvent = false; + } + } + } + } + + chronoStatSvc->chronoStart("Read Input"); + + if (useVTX.value()) { + if (!ReadInputVTX()) { + info() << "VTX input failed at event " << _nEvt << endmsg; + } + } + + if (useITKBarrel.value()) { + if (!ReadInputITKBarrel()) { + info() << "ITKBarrel input failed at event " << _nEvt << endmsg; + } + } + + if (useITKEndcap.value()) { + if (!ReadInputITKEndcap()) { + info() << "ITKEndcap input failed at event " << _nEvt << endmsg; + } + } + + if (collect_bad_events.value() && CleanBeforeRead.value()){ + if (VTXhits_num < 1 || ITKhits_num < 2) { + info() << "Event " << _nEvt << " has no VTX hit or less than 2 ITK hits" << endmsg; + isGoodEvent = false; + } + } + + if (useTPC.value()) { + if (!ReadInputTPC()) { + info() << "TPC input failed at event " << _nEvt << endmsg; + } + } + + if (useOTKBarrel.value()) { + if (!ReadInputOTKBarrel()) { + info() << "OTKBarrel input failed at event " << _nEvt << endmsg; + } + } + + if (useOTKEndcap.value()) { + if (!ReadInputOTKEndcap()) { + info() << "OTKEndcap input failed at event " << _nEvt << endmsg; + } + } + + if (!isGoodEvent) { + debug() << "Event " << _nEvt << " is not good" << endmsg; + m_badEvents++; + } + + chronoStatSvc->chronoStop("Read Input"); + + return StatusCode::SUCCESS; +} + +StatusCode RecActsReadInput::finalize() +{ + info() << "finalize ReadInput" << endmsg; + info() << "Total number of events processed: " << _nEvt + 1 << endmsg; + info() << "Number of bad events: " << m_badEvents << endmsg; + return StatusCode::SUCCESS; +} + +bool RecActsReadInput::ReadInputVTX() +{ + const edm4hep::TrackerHitCollection* hitVTXCol = nullptr; + + try { hitVTXCol = _inVTXTrackHdl.get(); } + catch (GaudiException& e) + { + fatal() << "Collection " << _inVTXTrackHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; + return false; + } + + if(hitVTXCol) + { + int nelem = hitVTXCol->size(); + debug() << "VTX hits number: " << nelem << endmsg; + VTXhits_num += nelem; + + for(int ielem = 0; ielem < nelem; ++ielem){ + auto hit = hitVTXCol->at(ielem); + + auto cellid = hit.getCellID(); + uint64_t m_layer = vtx_decoder->get(cellid, "layer"); + uint64_t m_module = vtx_decoder->get(cellid, "module"); + uint64_t m_sensor = vtx_decoder->get(cellid, "sensor"); + + if(m_layer <= 3){ + uint64_t acts_volume = VXD_volume_ids[m_layer]; + uint64_t acts_layer = 2; + uint64_t acts_sensitive = 1; + bool buildSpacePoint = true; + int moduleType = 1; + double onSurfaceTolerance = 1e-4; + + if (!recActsSvc->ReadInput(hit, + acts_volume, acts_layer, acts_sensitive, + buildSpacePoint, moduleType, onSurfaceTolerance)) + { return false; } + } else { + uint64_t acts_volume = VXD_volume_ids[4]; + uint64_t acts_layer = 2; + uint64_t acts_sensitive = (m_layer == 5) ? m_module*2 + 1 : m_module*2 + 2; + bool buildSpacePoint = true; + int moduleType = 0; + double onSurfaceTolerance = 1e-4; + + if (!recActsSvc->ReadInput(hit, + acts_volume, acts_layer, acts_sensitive, + buildSpacePoint, moduleType, onSurfaceTolerance)) + { return false; } + } + } + } + + return true; +} + +bool RecActsReadInput::ReadInputITKBarrel() +{ + const edm4hep::TrackerHitCollection* hitITKBarrelCol = nullptr; + + try { + hitITKBarrelCol = _inITKBarrelTrackHdl.get(); + } catch (GaudiException& e) { + fatal() << "Collection " << _inITKBarrelTrackHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; + return false; + } + + if(hitITKBarrelCol) + { + int nelem = hitITKBarrelCol->size(); + debug() << "ITKBarrel hits number: " << nelem << endmsg; + ITKhits_num += nelem; + + for (int ielem = 0; ielem < nelem; ++ielem) + { + auto hit = hitITKBarrelCol->at(ielem); + + auto cellid = hit.getCellID(); + uint64_t m_layer = ITKBarrel_decoder->get(cellid, "layer"); + uint64_t m_stave = ITKBarrel_decoder->get(cellid, "stave"); + + uint64_t acts_volume = ITKBarrel_volume_ids[m_layer]; + uint64_t acts_layer = 2; + uint64_t acts_sensitive = m_stave + 1; + bool buildSpacePoint = true; + int moduleType = 0; + double onSurfaceTolerance = 1e-4; + + if (!recActsSvc->ReadInput(hit, + acts_volume, acts_layer, acts_sensitive, + buildSpacePoint, moduleType, onSurfaceTolerance)) + { return false; } + } + } + + return true; +} + +bool RecActsReadInput::ReadInputITKEndcap() +{ + const edm4hep::TrackerHitCollection* hitITKEndcapCol = nullptr; + + try { + hitITKEndcapCol = _inITKEndcapTrackHdl.get(); + } catch (GaudiException& e) { + fatal() << "Collection " << _inITKEndcapTrackHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; + return false; + } + + if (hitITKEndcapCol) + { + int nelem = hitITKEndcapCol->size(); + debug() << "ITKEndcap hits number: " << nelem << endmsg; + ITKhits_num += nelem; + + for (int ielem = 0; ielem < nelem; ++ielem) + { + auto hit = hitITKEndcapCol->at(ielem); + + auto cellid = hit.getCellID(); + int m_side = ITKEndcap_decoder->get(cellid, "side"); + uint64_t m_layer = ITKEndcap_decoder->get(cellid, "layer"); + uint64_t m_module = ITKEndcap_decoder->get(cellid, "module"); + uint64_t m_ring = ITKEndcap_decoder->get(cellid, "ring"); + + uint64_t acts_volume = (m_side == 1) ? ITKEndcap_positive_volume_ids[m_layer] : ITKEndcap_negative_volume_ids[m_layer]; + uint64_t acts_layer = 2; + uint64_t acts_sensitive = 0; + + if (m_ring > 0){ + acts_sensitive += ITKEndcap_modules_per_ring[m_layer][0] * 2; + } + + if (m_ring > 1) { + acts_sensitive += ITKEndcap_modules_per_ring[m_layer][1] * 2; + } + + if (m_module % 2 == 0) { + acts_sensitive += (m_module / 2) + ITKEndcap_modules_per_ring[m_layer][m_ring] + 1; + } else { + acts_sensitive += (m_module / 2) + 1; + } + + bool buildSpacePoint = true; + int moduleType = 0; + double onSurfaceTolerance = 1e-4; + + if (!recActsSvc->ReadInput(hit, + acts_volume, acts_layer, acts_sensitive, + buildSpacePoint, moduleType, onSurfaceTolerance)) + { return false; } + } + } + + return true; +} + + +bool RecActsReadInput::ReadInputTPC() +{ + const edm4hep::TrackerHitCollection* hitTPCCol = nullptr; + + try { + hitTPCCol = _inTPCTrackHdl.get(); + } catch (GaudiException& e) { + fatal() << "Collection " << _inTPCTrackHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; + return false; + } + + if(hitTPCCol) + { + int nelem = hitTPCCol->size(); + debug() << "TPC hits number: " << nelem << endmsg; + + for (int ielem = 0; ielem < nelem; ++ielem) + { + auto hit = hitTPCCol->at(ielem); + + auto cellid = hit.getCellID(); + uint64_t m_layer = tpc_decoder->get(cellid, "layer"); + + uint64_t acts_volume = TPC_volume_id; + uint64_t acts_layer = (m_layer + 1) * 2; + uint64_t acts_sensitive = 1; + bool buildSpacePoint = false; + int moduleType = 2; + double onSurfaceTolerance = 1e-4; + + if (!recActsSvc->ReadInput(hit, + acts_volume, acts_layer, acts_sensitive, + buildSpacePoint, moduleType, onSurfaceTolerance)) + { return false; } + } + } + + return true; +} + +bool RecActsReadInput::ReadInputOTKBarrel() +{ + const edm4hep::TrackerHitCollection* hitOTKBarrelCol = nullptr; + + try { + hitOTKBarrelCol = _inOTKBarrelTrackHdl.get(); + } catch (GaudiException& e) { + fatal() << "Collection " << _inOTKBarrelTrackHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; + return false; + } + + if(hitOTKBarrelCol) + { + int nelem = hitOTKBarrelCol->size(); + debug() << "OTKBarrel hits number: " << nelem << endmsg; + + for (int ielem = 0; ielem < nelem; ++ielem) + { + auto hit = hitOTKBarrelCol->at(ielem); + + // system:5,side:-2,layer:9,module:8,iladder:32:4,oladder:-4,mmodule:-6 + auto cellid = hit.getCellID(); + uint64_t m_module = OTKBarrel_decoder->get(cellid, "module"); + + uint64_t acts_volume = OTKBarrel_volume_id; + uint64_t acts_layer = 2; + uint64_t acts_sensitive = m_module + 1; + + if (!recActsSvc->ReadInput(hit, + acts_volume, acts_layer, acts_sensitive)) + { return false; } + } + } + return true; +} + +bool RecActsReadInput::ReadInputOTKEndcap() +{ + const edm4hep::TrackerHitCollection* hitOTKEndcapCol = nullptr; + + try { + hitOTKEndcapCol = _inOTKEndcapTrackHdl.get(); + } catch (GaudiException& e) { + fatal() << "Collection " << _inOTKEndcapTrackHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; + return false; + } + + if(hitOTKEndcapCol) + { + int nelem = hitOTKEndcapCol->size(); + debug() << "OTKEndcap hits number: " << nelem << endmsg; + + for (int ielem = 0; ielem < nelem; ++ielem) + { + auto hit = hitOTKEndcapCol->at(ielem); + + auto cellid = hit.getCellID(); + int m_side = OTKEndcap_decoder->get(cellid, "side"); + double x = hit.getPosition()[0]; + double y = hit.getPosition()[1]; + + // Calculate the angle of the hit in the x-y plane + // The angle is in the range [-pi/16, 31pi/16) + // Returned angle index is in the range [1, 16] + double theta = atan2(y, x); + if (theta < 0) { theta += 2 * M_PI; } + theta += M_PI/16; + if (theta >= 2 * M_PI) { theta -= 2 * M_PI; } + int index = floor(theta / (M_PI/8)); + + uint64_t acts_volume = (m_side == 1) ? OTKEndcap_positive_volume_id : OTKEndcap_negative_volume_id; + uint64_t acts_layer = 2; + uint64_t acts_sensitive = index % 16 + 1; + bool buildSpacePoint = false; + int moduleType = 0; + double onSurfaceTolerance = 1e-2; + + if (!recActsSvc->ReadInput(hit, + acts_volume, acts_layer, acts_sensitive, + buildSpacePoint, moduleType, onSurfaceTolerance)) + { return false; } + } + } + return true; +} \ No newline at end of file diff --git a/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsReadInput.h b/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsReadInput.h new file mode 100644 index 00000000..4482c0aa --- /dev/null +++ b/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsReadInput.h @@ -0,0 +1,103 @@ +#ifndef RecActsReadInput_H +#define RecActsReadInput_H + +// gaudi framework +#include "k4FWCore/DataHandle.h" +#include "GaudiAlg/GaudiAlgorithm.h" + +// services +#include "RecActsSvc/IRecActsSvc.h" +#include "DetInterface/IGeomSvc.h" + +// DD4hep +#include "DD4hep/Detector.h" +#include "DDRec/ISurface.h" +#include "DDRec/SurfaceManager.h" + +#include "UTIL/ILDConf.h" +#include "DataHelper/Navigation.h" + +// edm4hep +#include "edm4hep/MCParticle.h" +#include "edm4hep/MCParticleCollection.h" +#include "edm4hep/TrackerHitCollection.h" +#include "edm4hep/SimTrackerHitCollection.h" +#include "edm4hep/EventHeaderCollection.h" + +#include "edm4hep/Track.h" +#include "edm4hep/MutableTrack.h" +#include "edm4hep/TrackState.h" +#include "edm4hep/TrackCollection.h" + + +class RecActsReadInput : public GaudiAlgorithm +{ + public: + RecActsReadInput(const std::string& name, ISvcLocator* svcLoc); + + StatusCode initialize(); + StatusCode execute(); + StatusCode finalize(); + + private: + // Input collections + DataHandle<edm4hep::MCParticleCollection> _inMCColHdl{"MCParticle", Gaudi::DataHandle::Reader, this}; + + DataHandle<edm4hep::TrackerHitCollection> _inVTXTrackHdl{"VXDTrackerHits", Gaudi::DataHandle::Reader, this}; + DataHandle<edm4hep::TrackerHitCollection> _inITKBarrelTrackHdl{"ITKBarrelTrackerHits", Gaudi::DataHandle::Reader, this}; + DataHandle<edm4hep::TrackerHitCollection> _inITKEndcapTrackHdl{"ITKEndcapTrackerHits", Gaudi::DataHandle::Reader, this}; + DataHandle<edm4hep::TrackerHitCollection> _inOTKBarrelTrackHdl{"OTKBarrelTrackerHits", Gaudi::DataHandle::Reader, this}; + DataHandle<edm4hep::TrackerHitCollection> _inOTKEndcapTrackHdl{"OTKEndcapTrackerHits", Gaudi::DataHandle::Reader, this}; + DataHandle<edm4hep::TrackerHitCollection> _inTPCTrackHdl{"TPCTrackerHits", Gaudi::DataHandle::Reader, this}; + + // properties + Gaudi::Property<bool> useVTX{this, "useVTX", true}; + Gaudi::Property<bool> useITKBarrel{this, "useITKBarrel", true}; + Gaudi::Property<bool> useITKEndcap{this, "useITKEndcap", true}; + Gaudi::Property<bool> useTPC{this, "useTPC", true}; + Gaudi::Property<bool> useOTKBarrel{this, "useOTKBarrel", true}; + Gaudi::Property<bool> useOTKEndcap{this, "useOTKEndcap", true}; + + Gaudi::Property<bool> CleanBeforeRead{this, "CleanBeforeRead", true}; + Gaudi::Property<bool> collect_bad_events{this, "collect_bad_events", true}; + + // read input + bool ReadInputVTX(); + bool ReadInputITKBarrel(); + bool ReadInputITKEndcap(); + bool ReadInputTPC(); + bool ReadInputOTKBarrel(); + bool ReadInputOTKEndcap(); + + // services + SmartIF<IGeomSvc> m_geosvc; + SmartIF<IRecActsSvc> recActsSvc; + SmartIF<IChronoStatSvc> chronoStatSvc; + + dd4hep::DDSegmentation::BitFieldCoder *vtx_decoder; + dd4hep::DDSegmentation::BitFieldCoder *ITKBarrel_decoder; + dd4hep::DDSegmentation::BitFieldCoder *ITKEndcap_decoder; + dd4hep::DDSegmentation::BitFieldCoder *tpc_decoder; + dd4hep::DDSegmentation::BitFieldCoder *OTKBarrel_decoder; + dd4hep::DDSegmentation::BitFieldCoder *OTKEndcap_decoder; + + // constants + int _nEvt; + bool isGoodEvent = true; + uint64_t TPC_volume_id = 45; + uint64_t OTKBarrel_volume_id = 47; + uint64_t OTKEndcap_positive_volume_id = 48; + uint64_t OTKEndcap_negative_volume_id = 2; + std::vector<uint64_t> VXD_volume_ids{28, 29, 30, 31, 32}; + std::vector<uint64_t> ITKBarrel_volume_ids{35, 38, 41}; + std::vector<uint64_t> ITKEndcap_positive_volume_ids{36, 39, 42, 43}; + std::vector<uint64_t> ITKEndcap_negative_volume_ids{34, 17, 12, 10}; + std::vector<std::vector<uint64_t>> ITKEndcap_modules_per_ring{{13, 20, 0}, {16, 24, 28}, {24, 36, 44}, {24, 36, 44}}; + std::vector<uint64_t> ITKBarrel_module_nums{7, 10, 14}; + + uint64_t VTXhits_num = 0; + uint64_t ITKhits_num = 0; + mutable std::atomic<std::size_t> m_badEvents{0}; +}; + +#endif // RecActsReadInput_H \ No newline at end of file diff --git a/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsSeeding.cpp b/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsSeeding.cpp new file mode 100644 index 00000000..75df9cfe --- /dev/null +++ b/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsSeeding.cpp @@ -0,0 +1,169 @@ +// dependence +#include "RecActsSeeding.h" + +DECLARE_COMPONENT(RecActsSeeding) + +RecActsSeeding::RecActsSeeding(const std::string& name, ISvcLocator* svcLoc) + : GaudiAlgorithm(name, svcLoc) +{ +} + +StatusCode RecActsSeeding::initialize() +{ + recActsSvc = service<IRecActsSvc>("RecActsSvc"); + if (!recActsSvc) { + error() << "Failed to get RecActsSvc" << endmsg; + return StatusCode::FAILURE; + } + + chronoStatSvc = service<IChronoStatSvc>("ChronoStatSvc"); + + // configure seed finder + m_cfg.seedFinderOptions.bFieldInZ = m_field.value(); + m_cfg.seedFinderConfig.deltaRMin = SeedDeltaRMin.value(); + m_cfg.seedFinderConfig.deltaRMax = SeedDeltaRMax.value(); + m_cfg.seedFinderConfig.rMax = SeedRMax.value(); + m_cfg.seedFinderConfig.rMin = SeedRMin.value(); + m_cfg.seedFinderConfig.impactMax = SeedImpactMax.value(); + m_cfg.seedFinderConfig.useVariableMiddleSPRange = false; + m_cfg.seedFinderConfig.rMinMiddle = SeedRMinMiddle.value(); + m_cfg.seedFinderConfig.rMaxMiddle = SeedRMaxMiddle.value(); + + // initialize the seeding tools + m_cfg.seedFilterConfig = m_cfg.seedFilterConfig.toInternalUnits(); + m_cfg.seedFinderConfig.seedFilter = + std::make_unique<Acts::SeedFilter<ActsHelper::SimSpacePoint>>(m_cfg.seedFilterConfig); + m_cfg.seedFinderConfig = + m_cfg.seedFinderConfig.toInternalUnits().calculateDerivedQuantities(); + m_cfg.seedFinderOptions = + m_cfg.seedFinderOptions.toInternalUnits().calculateDerivedQuantities(m_cfg.seedFinderConfig); + m_cfg.gridConfig = m_cfg.gridConfig.toInternalUnits(); + m_cfg.gridOptions = m_cfg.gridOptions.toInternalUnits(); + + if (std::isnan(m_cfg.seedFinderConfig.deltaRMaxTopSP)) { + m_cfg.seedFinderConfig.deltaRMaxTopSP = m_cfg.seedFinderConfig.deltaRMax;} + if (std::isnan(m_cfg.seedFinderConfig.deltaRMinTopSP)) { + m_cfg.seedFinderConfig.deltaRMinTopSP = m_cfg.seedFinderConfig.deltaRMin;} + if (std::isnan(m_cfg.seedFinderConfig.deltaRMaxBottomSP)) { + m_cfg.seedFinderConfig.deltaRMaxBottomSP = m_cfg.seedFinderConfig.deltaRMax;} + if (std::isnan(m_cfg.seedFinderConfig.deltaRMinBottomSP)) { + m_cfg.seedFinderConfig.deltaRMinBottomSP = m_cfg.seedFinderConfig.deltaRMin;} + + m_bottomBinFinder = std::make_unique<const Acts::GridBinFinder<2ul>>( + m_cfg.numPhiNeighbors, m_cfg.zBinNeighborsBottom); + m_topBinFinder = std::make_unique<const Acts::GridBinFinder<2ul>>( + m_cfg.numPhiNeighbors, m_cfg.zBinNeighborsTop); + + m_cfg.seedFinderConfig.seedFilter = + std::make_unique<Acts::SeedFilter<ActsHelper::SimSpacePoint>>(m_cfg.seedFilterConfig); + m_seedFinder = + Acts::SeedFinder<ActsHelper::SimSpacePoint, Acts::CylindricalSpacePointGrid<ActsHelper::SimSpacePoint>>(m_cfg.seedFinderConfig); + + _nEvt = -1; + return StatusCode::SUCCESS; +} + +StatusCode RecActsSeeding::execute() +{ + _nEvt++; + + auto SpacePointPtrs = recActsSvc->SpacePointPtrs(); + + chronoStatSvc->chronoStart("Seeding"); + + auto extractGlobalQuantities = [=](const ActsHelper::SimSpacePoint& sp, float, float, float) + { + Acts::Vector3 position{sp.x(), sp.y(), sp.z()}; + Acts::Vector2 covariance{sp.varianceR(), sp.varianceZ()}; + return std::make_tuple(position, covariance, sp.t()); + }; + + Acts::Extent rRangeSPExtent; + + Acts::CylindricalSpacePointGrid<ActsHelper::SimSpacePoint> grid = + Acts::CylindricalSpacePointGridCreator::createGrid<ActsHelper::SimSpacePoint>(m_cfg.gridConfig, m_cfg.gridOptions); + Acts::CylindricalSpacePointGridCreator::fillGrid( + m_cfg.seedFinderConfig, m_cfg.seedFinderOptions, grid, + SpacePointPtrs->begin(), SpacePointPtrs->end(), extractGlobalQuantities, rRangeSPExtent); + + std::array<std::vector<std::size_t>, 2ul> navigation; + navigation[1ul] = m_cfg.seedFinderConfig.zBinsCustomLooping; + + auto spacePointsGrouping = Acts::CylindricalBinnedGroup<ActsHelper::SimSpacePoint>( + std::move(grid), *m_bottomBinFinder, *m_topBinFinder, std::move(navigation)); + + // safely clamp double to float + float up = Acts::clampValue<float>(std::floor(rRangeSPExtent.max(Acts::binR) / 2) * 2); + + /// variable middle SP radial region of interest + const Acts::Range1D<float> rMiddleSPRange( + std::floor(rRangeSPExtent.min(Acts::binR) / 2) * 2 + + m_cfg.seedFinderConfig.deltaRMiddleMinSPRange, + up - m_cfg.seedFinderConfig.deltaRMiddleMaxSPRange); + + // run the seeding + static thread_local ActsHelper::SimSeedContainer seeds; + seeds.clear(); + static thread_local decltype(m_seedFinder)::SeedingState state; + state.spacePointData.resize( + SpacePointPtrs->size(), + m_cfg.seedFinderConfig.useDetailedDoubleMeasurementInfo); + + // use double stripe measurement + if (m_cfg.seedFinderConfig.useDetailedDoubleMeasurementInfo) + { + for (std::size_t grid_glob_bin(0); grid_glob_bin < spacePointsGrouping.grid().size(); ++grid_glob_bin) + { + const auto& collection = spacePointsGrouping.grid().at(grid_glob_bin); + for (const auto& sp : collection) + { + std::size_t index = sp->index(); + const float topHalfStripLength = + m_cfg.seedFinderConfig.getTopHalfStripLength(sp->sp()); + const float bottomHalfStripLength = + m_cfg.seedFinderConfig.getBottomHalfStripLength(sp->sp()); + const Acts::Vector3 topStripDirection = + m_cfg.seedFinderConfig.getTopStripDirection(sp->sp()); + const Acts::Vector3 bottomStripDirection = + m_cfg.seedFinderConfig.getBottomStripDirection(sp->sp()); + + state.spacePointData.setTopStripVector( + index, topHalfStripLength * topStripDirection); + state.spacePointData.setBottomStripVector( + index, bottomHalfStripLength * bottomStripDirection); + state.spacePointData.setStripCenterDistance( + index, m_cfg.seedFinderConfig.getStripCenterDistance(sp->sp())); + state.spacePointData.setTopStripCenterPosition( + index, m_cfg.seedFinderConfig.getTopStripCenterPosition(sp->sp())); + } + } + } + + for (const auto [bottom, middle, top] : spacePointsGrouping) + { + m_seedFinder.createSeedsForGroup( + m_cfg.seedFinderOptions, state, spacePointsGrouping.grid(), + std::back_inserter(seeds), bottom, middle, top, rMiddleSPRange); + } + + debug() << "Found " << seeds.size() << " seeds for event " << _nEvt << "!" << endmsg; + + // Sort seeds by the radius of their bottom space point + std::sort(seeds.begin(), seeds.end(), + [](const ActsHelper::SimSeed& a, const ActsHelper::SimSeed& b) { + return a.sp()[0]->r() < b.sp()[0]->r(); + }); + + // clear the seeds in RecActsSvc and insert the new seeds + recActsSvc->Seeds()->clear(); + recActsSvc->Seeds()->insert(recActsSvc->Seeds()->end(), seeds.begin(), seeds.end()); + + chronoStatSvc->chronoStop("Seeding"); + + return StatusCode::SUCCESS; +} + +StatusCode RecActsSeeding::finalize() +{ + return StatusCode::SUCCESS; +} \ No newline at end of file diff --git a/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsSeeding.h b/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsSeeding.h new file mode 100644 index 00000000..ee97506e --- /dev/null +++ b/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsSeeding.h @@ -0,0 +1,84 @@ +#ifndef RecActsSeeding_H +#define RecActsSeeding_H + +// gaudi framework +#include "GaudiAlg/GaudiAlgorithm.h" + +// services +#include "RecActsSvc/IRecActsSvc.h" +#include "DetInterface/IGeomSvc.h" + +// Acts +#include "Acts/Seeding/SeedFilterConfig.hpp" +#include "Acts/Seeding/SeedFinder.hpp" +#include "Acts/Seeding/SeedFinderConfig.hpp" +#include "Acts/Seeding/SpacePointGrid.hpp" +#include "Acts/Utilities/GridBinFinder.hpp" +#include "Acts/Utilities/Logger.hpp" + +namespace Acts { + template <std::size_t> class GridBinFinder; +} + +class RecActsSeeding : public GaudiAlgorithm +{ + public: + RecActsSeeding(const std::string& name, ISvcLocator* svcLoc); + + StatusCode initialize(); + StatusCode execute(); + StatusCode finalize(); + + private: + // properties + Gaudi::Property<double> m_field{this, "bFieldInZ", 3.0}; // tesla + + Gaudi::Property<double> SeedDeltaRMin{this, "SeedDeltaRMin", 0.5}; // mm + Gaudi::Property<double> SeedDeltaRMax{this, "SeedDeltaRMax", 600}; // mm + Gaudi::Property<double> SeedRMax{this, "SeedRMax", 600}; // mm + Gaudi::Property<double> SeedRMin{this, "SeedRMin", 10}; // mm + Gaudi::Property<double> SeedImpactMax{this, "SeedImpactMax", 3}; // mm + Gaudi::Property<double> SeedRMinMiddle{this, "SeedRMinMiddle", 10}; // mm + Gaudi::Property<double> SeedRMaxMiddle{this, "SeedRMaxMiddle", 600}; // mm + + // services + SmartIF<IRecActsSvc> recActsSvc; + SmartIF<IChronoStatSvc> chronoStatSvc; + + struct Config { + /// Input space point collections. + /// + /// We allow multiple space point collections to allow different parts of + /// the detector to use different algorithms for space point construction, + /// e.g. single-hit space points for pixel-like detectors or double-hit + /// space points for strip-like detectors. + std::vector<std::string> inputSpacePoints; + /// Output track seed collection. + std::string outputSeeds; + + Acts::SeedFilterConfig seedFilterConfig; + Acts::SeedFinderConfig<ActsHelper::SimSpacePoint> seedFinderConfig; + Acts::CylindricalSpacePointGridConfig gridConfig; + Acts::CylindricalSpacePointGridOptions gridOptions; + Acts::SeedFinderOptions seedFinderOptions; + + // allow for different values of rMax in gridConfig and seedFinderConfig + bool allowSeparateRMax = false; + + // vector containing the map of z bins in the top and bottom layers + std::vector<std::pair<int, int>> zBinNeighborsTop; + std::vector<std::pair<int, int>> zBinNeighborsBottom; + // number of phiBin neighbors at each side of the current bin that will be + // used to search for SPs + int numPhiNeighbors = 1; + }; + + Config m_cfg; + std::unique_ptr<const Acts::GridBinFinder<2ul>> m_bottomBinFinder; + std::unique_ptr<const Acts::GridBinFinder<2ul>> m_topBinFinder; + Acts::SeedFinder<ActsHelper::SimSpacePoint, Acts::CylindricalSpacePointGrid<ActsHelper::SimSpacePoint>> m_seedFinder; + + int _nEvt; +}; + +#endif // RecActsSeeding_H \ No newline at end of file diff --git a/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTrackFinding.cpp b/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTrackFinding.cpp new file mode 100644 index 00000000..cf526186 --- /dev/null +++ b/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTrackFinding.cpp @@ -0,0 +1,451 @@ +// dependence +#include "RecActsTrackFinding.h" +#include "TError.h" + +DECLARE_COMPONENT(RecActsTrackFinding) + +RecActsTrackFinding::RecActsTrackFinding(const std::string& name, ISvcLocator* svcLoc) + : GaudiAlgorithm(name, svcLoc) +{ + declareProperty("ACTSFindOutCol", _outColHdl, "ACTS Track Finding Output track collection"); +} + +StatusCode RecActsTrackFinding::initialize() +{ + recActsSvc = service<IRecActsSvc>("RecActsSvc"); + if (!recActsSvc) { + error() << "Failed to get RecActsSvc" << endmsg; + return StatusCode::FAILURE; + } + + chronoStatSvc = service<IChronoStatSvc>("ChronoStatSvc"); + + magneticField = std::make_shared<Acts::ConstantBField>( + Acts::Vector3(0., 0., m_field.value()*_FCT)); + findTracks = makeTrackFinderFunction(recActsSvc->Geometry(), magneticField); + + _nEvt = -1; + return StatusCode::SUCCESS; +} + +StatusCode RecActsTrackFinding::execute() +{ + _nEvt++; + + auto trkCol = _outColHdl.createAndPut(); + + auto measurements = recActsSvc->Measurements(); + auto sourceLinks = recActsSvc->SourceLinks(); + auto Selected_Seeds = recActsSvc->SelectedSeeds(); + auto trackParameters = recActsSvc->TrackParameters(); + auto trackSourceLinks = recActsSvc->TrackSourceLinks(); + // trackSourceLinks only store the track source links of latest trackParameters + trackSourceLinks->clear(); + + if ((trackParameters->size() == 0) || (Selected_Seeds->size() == 0)) { + debug() << "No initial parameters or selected seeds found for event " << _nEvt << endmsg; + return StatusCode::SUCCESS; + } + + auto initialParameters = trackParameters->back(); + auto selectedSeeds = Selected_Seeds->back(); + ActsHelper::SimSeedContainer currentSeeds; + + chronoStatSvc->chronoStart("CKF Track Finding"); + + ActsHelper::IndexSourceLink::SurfaceAccessor surfaceAccessor{*recActsSvc->Geometry()}; + // Construct a perigee surface as the target surface + auto pSurface = Acts::Surface::makeShared<Acts::PerigeeSurface>(Acts::Vector3{0., 0., 0.}); + ActsHelper::PassThroughCalibrator pcalibrator; + ActsHelper::MeasurementCalibratorAdapter calibrator(pcalibrator, *measurements); + Acts::GainMatrixUpdater kfUpdater; + Acts::MeasurementSelector::Config measurementSelectorCfg = + { + {Acts::GeometryIdentifier(), {{}, {CKFchi2Cut.value()}, {numMeasurementsCutOff.value()}}}, + }; + + MeasurementSelector measSel{ Acts::MeasurementSelector(measurementSelectorCfg) }; + BranchStopper branchStopper(trackSelectorCfg); + + // Construct the CKF + Extensions extensions; + extensions.calibrator.connect<&ActsHelper::MeasurementCalibratorAdapter::calibrate>(&calibrator); + extensions.updater.connect<&Acts::GainMatrixUpdater::operator()<Acts::VectorMultiTrajectory>>(&kfUpdater); + extensions.measurementSelector.connect<&MeasurementSelector::select>(&measSel); + extensions.branchStopper.connect<&BranchStopper::operator()>(&branchStopper); + + ActsHelper::IndexSourceLinkAccessor slAccessor; + slAccessor.container = sourceLinks; + Acts::SourceLinkAccessorDelegate<ActsHelper::IndexSourceLinkAccessor::Iterator> slAccessorDelegate; + slAccessorDelegate.connect<&ActsHelper::IndexSourceLinkAccessor::range>(&slAccessor); + + Acts::PropagatorPlainOptions firstPropOptions; + firstPropOptions.maxSteps = maxSteps; + firstPropOptions.direction = Acts::Direction::Forward; + + Acts::PropagatorPlainOptions secondPropOptions; + secondPropOptions.maxSteps = maxSteps; + secondPropOptions.direction = firstPropOptions.direction.invert(); + + // Set the CombinatorialKalmanFilter options + TrackFinderOptions firstOptions( + geoContext, magFieldContext, calibContext, + slAccessorDelegate, extensions, firstPropOptions); + + TrackFinderOptions secondOptions( + geoContext, magFieldContext, calibContext, + slAccessorDelegate, extensions, secondPropOptions); + secondOptions.targetSurface = pSurface.get(); + + Acts::Propagator<Acts::EigenStepper<>, Acts::Navigator> extrapolator( + Acts::EigenStepper<>(magneticField), Acts::Navigator({recActsSvc->Geometry()})); + + Acts::PropagatorOptions<Acts::ActionList<Acts::MaterialInteractor>, Acts::AbortList<Acts::EndOfWorldReached>> + extrapolationOptions(geoContext, magFieldContext); + + auto trackContainer = std::make_shared<Acts::VectorTrackContainer>(); + auto trackStateContainer = std::make_shared<Acts::VectorMultiTrajectory>(); + auto trackContainerTemp = std::make_shared<Acts::VectorTrackContainer>(); + auto trackStateContainerTemp = std::make_shared<Acts::VectorMultiTrajectory>(); + TrackContainer tracks(trackContainer, trackStateContainer); + TrackContainer tracksTemp(trackContainerTemp, trackStateContainerTemp); + + tracks.addColumn<unsigned int>("trackGroup"); + tracksTemp.addColumn<unsigned int>("trackGroup"); + Acts::ProxyAccessor<unsigned int> seedNumber("trackGroup"); + + unsigned int nSeed = 0; + // A map indicating whether a seed has been discovered already + std::unordered_map<SeedIdentifier, bool> discoveredSeeds; + auto addTrack = [&](const TrackProxy& track, const ActsHelper::SimSeed& seed) + { + ++m_nFoundTracks; + // flag seeds which are covered by the track + visitSeedIdentifiers(track, [&](const SeedIdentifier& seedIdentifier) + { + if (auto it = discoveredSeeds.find(seedIdentifier); it != discoveredSeeds.end()) + { + it->second = true; + } + }); + + if (m_trackSelector.has_value() && !m_trackSelector->isValidTrack(track)) { return; } + + ++m_nSelectedTracks; + currentSeeds.push_back(seed); + auto destProxy = tracks.makeTrack(); + // make sure we copy track states! + destProxy.copyFrom(track, true); + }; + + for (std::size_t iSeed = 0; iSeed < selectedSeeds.size(); ++iSeed) { + SeedIdentifier seedIdentifier = makeSeedIdentifier(selectedSeeds.at(iSeed)); + discoveredSeeds.emplace(seedIdentifier, false); + } + + for (std::size_t iSeed = 0; iSeed < initialParameters.size(); ++iSeed) + { + m_nTotalSeeds++; + const auto& seed = selectedSeeds.at(iSeed); + + SeedIdentifier seedIdentifier = makeSeedIdentifier(seed); + // check if the seed has been discovered already + if (auto it = discoveredSeeds.find(seedIdentifier); it != discoveredSeeds.end() && it->second) + { + m_nDeduplicatedSeeds++; + continue; + } + + /// Whether to stick on the seed measurements during track finding. + // measSel.setSeed(seed); + + // Clear trackContainerTemp and trackStateContainerTemp + tracksTemp.clear(); + + const Acts::BoundTrackParameters& firstInitialParameters = initialParameters.at(iSeed); + auto firstResult = (*findTracks)(firstInitialParameters, firstOptions, tracksTemp); + + nSeed++; + if (!firstResult.ok()) + { + m_nFailedSeeds++; + continue; + } + + auto& firstTracksForSeed = firstResult.value(); + for (auto& firstTrack : firstTracksForSeed) + { + auto trackCandidate = tracksTemp.makeTrack(); + trackCandidate.copyFrom(firstTrack, true); + + auto firstSmoothingResult = Acts::smoothTrack(geoContext, trackCandidate); + + if (!firstSmoothingResult.ok()) + { + m_nFailedSmoothing++; + debug() << "First smoothing for seed " + << iSeed << " and track " << firstTrack.index() + << " failed with error " << firstSmoothingResult.error() << endmsg; + continue; + } + + seedNumber(trackCandidate) = nSeed - 1; + + // second way track finding + std::size_t nSecond = 0; + if (CKFtwoWay) + { + std::optional<Acts::VectorMultiTrajectory::TrackStateProxy> firstMeasurement; + for (auto trackState : trackCandidate.trackStatesReversed()) + { + bool isMeasurement = trackState.typeFlags().test(Acts::TrackStateFlag::MeasurementFlag); + bool isOutlier = trackState.typeFlags().test(Acts::TrackStateFlag::OutlierFlag); + if (isMeasurement && !isOutlier) { firstMeasurement = trackState; } + } + + if (firstMeasurement.has_value()) + { + Acts::BoundTrackParameters secondInitialParameters = trackCandidate.createParametersFromState(*firstMeasurement); + auto secondResult = (*findTracks)(secondInitialParameters, secondOptions, tracksTemp); + if (!secondResult.ok()) + { + debug() << "Second track finding failed for seed " + << iSeed << " with error" << secondResult.error() << endmsg; + } else { + auto firstState = *std::next(trackCandidate.trackStatesReversed().begin(), trackCandidate.nTrackStates() - 1); + auto& secondTracksForSeed = secondResult.value(); + for (auto& secondTrack : secondTracksForSeed) + { + if (secondTrack.nTrackStates() < 2) { continue; } + auto secondTrackCopy = tracksTemp.makeTrack(); + secondTrackCopy.copyFrom(secondTrack, true); + secondTrackCopy.reverseTrackStates(true); + + firstState.previous() = (*std::next(secondTrackCopy.trackStatesReversed().begin())).index(); + Acts::calculateTrackQuantities(trackCandidate); + auto secondExtrapolationResult = Acts::extrapolateTrackToReferenceSurface( + trackCandidate, *pSurface, extrapolator, + extrapolationOptions, extrapolationStrategy); + if (!secondExtrapolationResult.ok()) + { + m_nFailedExtrapolation++; + debug() << "Second extrapolation for seed " + << iSeed << " and track " << secondTrack.index() + << " failed with error " + << secondExtrapolationResult.error() << endmsg; + continue; + } + + addTrack(trackCandidate, seed); + + ++nSecond; + } + + firstState.previous() = Acts::kTrackIndexInvalid; + Acts::calculateTrackQuantities(trackCandidate); + } + } + } + + // if no second track was found, we will use only the first track + if (nSecond == 0) { + auto firstExtrapolationResult = Acts::extrapolateTrackToReferenceSurface( + trackCandidate, *pSurface, extrapolator, extrapolationOptions, extrapolationStrategy); + + if (!firstExtrapolationResult.ok()) + { + m_nFailedExtrapolation++; + continue; + } + + addTrack(trackCandidate, seed); + } + } + } + + chronoStatSvc->chronoStop("CKF Track Finding"); + + chronoStatSvc->chronoStart("Track Selection & WriteOut"); + // debug() << "CKF found " << tracks.size() << " tracks for event " << _nEvt << "!" << endmsg; + m_memoryStatistics.local().hist += tracks.trackStateContainer().statistics().hist; + auto constTrackStateContainer = std::make_shared<Acts::ConstVectorMultiTrajectory>(std::move(*trackStateContainer)); + auto constTrackContainer = std::make_shared<Acts::ConstVectorTrackContainer>(std::move(*trackContainer)); + ConstTrackContainer constTracks{constTrackContainer, constTrackStateContainer}; + std::vector<Acts::BoundTrackParameters> cur_track_params; + + debug() << "CKF found " << constTracks.size() << " tracks at event " << _nEvt << endmsg; + + // bool isSingleTrack = constTracks.size() == 1; + // if (!isSingleTrack) { + // info() << "CKF found " << constTracks.size() << " tracks at event " << _nEvt << endmsg; + // info() << "all measurements size: " << measurements->size() << endmsg; + // } + + // std::vector<int> picked_track_idx; + // std::vector<double> picked_track_Chi2; + // std::vector<int> picked_track_nMeasurements; + // for (int i = 0; i < constTracks.size(); i++) { + // auto cur_track = constTracks.getTrack(i); + // auto cur_chi2 = cur_track.chi2(); + // auto cur_nMeasurements = cur_track.nMeasurements(); + + // if (cur_nMeasurements < TrackNdfCut.value()) { + // continue; + // } + + // picked_track_idx.push_back(i); + // picked_track_Chi2.push_back(cur_chi2); + // picked_track_nMeasurements.push_back(cur_nMeasurements); + // } + + // std::sort(picked_track_idx.begin(), picked_track_idx.end(), + // [&picked_track_Chi2, &picked_track_nMeasurements](int i1, int i2) { + // if (picked_track_nMeasurements[i1] != picked_track_nMeasurements[i2]) { + // return picked_track_nMeasurements[i1] > picked_track_nMeasurements[i2]; + // } + // return picked_track_Chi2[i1] < picked_track_Chi2[i2]; + // }); + + std::vector<int> picked_track_idx; + std::vector<double> picked_track_Chi2; + ActsHelper::SimSeedContainer writeout_seeds; + // std::vector<int> picked_track_nMeasurements; + for (int i = 0; i < constTracks.size(); i++) { + auto cur_track = constTracks.getTrack(i); + auto cur_chi2 = cur_track.chi2(); + auto cur_nMeasurements = cur_track.nMeasurements(); + + picked_track_idx.push_back(i); + picked_track_Chi2.push_back(cur_chi2/cur_nMeasurements); + } + + std::sort(picked_track_idx.begin(), picked_track_idx.end(), + [&picked_track_Chi2](int i1, int i2) { + return picked_track_Chi2[i1] < picked_track_Chi2[i2]; + }); + + int picked_track_num = std::min(pickTrackMaxNum.value(), picked_track_idx.size()); + for (int i = 0; i < picked_track_num; i++) { + auto writeout_track = trkCol->create(); + auto cur_track = constTracks.getTrack(picked_track_idx[i]); + writeout_seeds.push_back(currentSeeds[picked_track_idx[i]]); + + writeout_track.setChi2(cur_track.chi2()); + writeout_track.setNdf(cur_track.nDoF()); + writeout_track.setDEdx(cur_track.absoluteMomentum() / Acts::UnitConstants::GeV); + + // if (!isSingleTrack){ + // info() << "picked Track Chi2: " << cur_track.chi2() << " nMeasurements: " << cur_track.nMeasurements() << endmsg; + // } + + debug() << "A track with p=" << cur_track.absoluteMomentum() << " GeV is found for event " << _nEvt << "!" << endmsg; + debug() << "Track nMeasurements: " << cur_track.nMeasurements() << endmsg; + debug() << "MC nMeasurements: " << measurements->size() << endmsg; + + // TODO: covmatrix need to be converted + std::array<float, 21> writeout_covMatrix; + auto cur_track_covariance = cur_track.covariance(); + for (int i = 0; i < 6; i++) { + for (int j = 0; j < 6-i; j++) { + writeout_covMatrix[int((13-i)*i/2 + j)] = cur_track_covariance(writeout_indices[i], writeout_indices[j]); + } + } + // location: At{Other|IP|FirstHit|LastHit|Calorimeter|Vertex}|LastLocation + // TrackState: location, d0, phi, omega, z0, tanLambda, time, referencePoint, covMatrix + edm4hep::TrackState writeout_trackState{ + 1, // location: AtOther + cur_track.loc0() / Acts::UnitConstants::mm, // d0 + cur_track.phi(), // phi + cur_track.qOverP() * _FCT * m_field.value() / sin(cur_track.theta()), // omega = qop * sin(theta) * _FCT * bf + cur_track.loc1() / Acts::UnitConstants::mm, // z0 + 1 / tan(cur_track.theta()), // tanLambda = 1 / tan(theta) + cur_track.time(), // time + ::edm4hep::Vector3f(0, 0, 0), // referencePoint + writeout_covMatrix + }; + + writeout_track.addToTrackStates(writeout_trackState); + + // for track fitting + std::vector<Acts::SourceLink> cur_trackSourceLinks; + for (auto trackState : cur_track.trackStates()) + { + if (trackState.hasUncalibratedSourceLink()) + { + auto cur_measurement_sl = trackState.getUncalibratedSourceLink(); + cur_trackSourceLinks.push_back(cur_measurement_sl); + } + } + + cur_track_params.push_back(cur_track.createParametersAtReference()); + trackSourceLinks->push_back(cur_trackSourceLinks); + + m_nFinalTracks++; + } + + trackParameters->push_back(cur_track_params); + Selected_Seeds->push_back(writeout_seeds); + chronoStatSvc->chronoStop("Track Selection & WriteOut"); + + return StatusCode::SUCCESS; +} + +StatusCode RecActsTrackFinding::finalize() +{ + info() << "finalize Finding" << endmsg; + info() << "Total number of events processed: " << _nEvt + 1 << endmsg; + info() << "Total number of **TotalSeeds** processed: " << m_nTotalSeeds << endmsg; + info() << "Total number of **FoundTracks** processed: " << m_nFoundTracks << endmsg; + info() << "Total number of **SelectedTracks** processed: " << m_nSelectedTracks << endmsg; + info() << "Total number of **FinalTracks** processed: " << m_nFinalTracks << endmsg; + return StatusCode::SUCCESS; +} + +template <typename source_link_accessor_container_t> +void RecActsTrackFinding::computeSharedHits(const source_link_accessor_container_t& sourceLinks, TrackContainer& tracks) const +{ + // Compute shared hits from all the reconstructed tracks + // Compute nSharedhits and Update ckf results + // hit index -> list of multi traj indexes [traj, meas] + + std::vector<std::size_t> firstTrackOnTheHit(sourceLinks.size(), std::numeric_limits<std::size_t>::max()); + std::vector<std::size_t> firstStateOnTheHit(sourceLinks.size(), std::numeric_limits<std::size_t>::max()); + + for (auto track : tracks) + { + for (auto state : track.trackStatesReversed()) + { + if (!state.typeFlags().test(Acts::TrackStateFlag::MeasurementFlag)) { continue; } + + std::size_t hitIndex = state.getUncalibratedSourceLink() + .template get<ActsHelper::IndexSourceLink>() + .index(); + + // Check if hit not already used + if (firstTrackOnTheHit.at(hitIndex) == std::numeric_limits<std::size_t>::max()) + { + firstTrackOnTheHit.at(hitIndex) = track.index(); + firstStateOnTheHit.at(hitIndex) = state.index(); + continue; + } + + // if already used, control if first track state has been marked + // as shared + int indexFirstTrack = firstTrackOnTheHit.at(hitIndex); + int indexFirstState = firstStateOnTheHit.at(hitIndex); + + auto firstState = tracks.getTrack(indexFirstTrack) + .container() + .trackStateContainer() + .getTrackState(indexFirstState); + + if (!firstState.typeFlags().test(Acts::TrackStateFlag::SharedHitFlag)) + { + firstState.typeFlags().set(Acts::TrackStateFlag::SharedHitFlag); + } + + // Decorate this track state + state.typeFlags().set(Acts::TrackStateFlag::SharedHitFlag); + } + } +} \ No newline at end of file diff --git a/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTrackFinding.h b/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTrackFinding.h new file mode 100644 index 00000000..20e152d9 --- /dev/null +++ b/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTrackFinding.h @@ -0,0 +1,378 @@ +#ifndef RecActsTrackFinding_H +#define RecActsTrackFinding_H + +// gaudi framework +#include "k4FWCore/DataHandle.h" +#include "GaudiAlg/GaudiAlgorithm.h" + +// services +#include "RecActsSvc/IRecActsSvc.h" +#include "DetInterface/IGeomSvc.h" + +#include "edm4hep/Track.h" +#include "edm4hep/MutableTrack.h" +#include "edm4hep/TrackState.h" +#include "edm4hep/TrackCollection.h" + +// Acts +#include "Acts/Definitions/Algebra.hpp" +#include "Acts/Definitions/Direction.hpp" +#include "Acts/Definitions/TrackParametrization.hpp" +#include "Acts/EventData/MultiTrajectory.hpp" +#include "Acts/EventData/TrackProxy.hpp" +#include "Acts/EventData/ProxyAccessor.hpp" +#include "Acts/EventData/SourceLink.hpp" +#include "Acts/EventData/TrackContainer.hpp" +#include "Acts/EventData/TrackParameters.hpp" +#include "Acts/EventData/VectorMultiTrajectory.hpp" +#include "Acts/EventData/VectorTrackContainer.hpp" +#include "Acts/Geometry/GeometryIdentifier.hpp" +#include "Acts/Geometry/TrackingGeometry.hpp" +#include "Acts/Propagator/AbortList.hpp" +#include "Acts/Propagator/EigenStepper.hpp" +#include "Acts/Propagator/MaterialInteractor.hpp" +#include "Acts/Propagator/Navigator.hpp" +#include "Acts/Propagator/Propagator.hpp" +#include "Acts/Propagator/StandardAborters.hpp" +#include "Acts/Surfaces/PerigeeSurface.hpp" +#include "Acts/Surfaces/Surface.hpp" +#include "Acts/TrackFinding/CombinatorialKalmanFilter.hpp" +#include "Acts/TrackFinding/MeasurementSelector.hpp" +#include "Acts/TrackFinding/TrackSelector.hpp" +#include "Acts/TrackFitting/GainMatrixSmoother.hpp" +#include "Acts/TrackFitting/GainMatrixUpdater.hpp" +#include "Acts/TrackFitting/KalmanFitter.hpp" +#include "Acts/Utilities/Delegate.hpp" +#include "Acts/Utilities/Enumerate.hpp" +#include "Acts/Utilities/Logger.hpp" +#include "Acts/Utilities/TrackHelpers.hpp" +#include "Acts/Utilities/Result.hpp" + +#include <cmath> +#include <functional> +#include <memory> +#include <optional> +#include <ostream> +#include <stdexcept> +#include <system_error> +#include <unordered_map> +#include <utility> +#include <atomic> +#include <cstddef> +#include <limits> +#include <string> +#include <variant> + +#include <boost/functional/hash.hpp> +#include <tbb/combinable.h> + +namespace Acts +{ + class MagneticFieldProvider; + class TrackingGeometry; +} + +using TrackParameters = ::Acts::BoundTrackParameters; +using TrackParametersContainer = std::vector<TrackParameters>; +using TrackContainer = Acts::TrackContainer<Acts::VectorTrackContainer, Acts::VectorMultiTrajectory, std::shared_ptr>; +using ConstTrackContainer = Acts::TrackContainer<Acts::ConstVectorTrackContainer, Acts::ConstVectorMultiTrajectory, std::shared_ptr>; +using TrackIndexType = TrackContainer::IndexType; +using TrackProxy = TrackContainer::TrackProxy; +using ConstTrackProxy = ConstTrackContainer::ConstTrackProxy; + +using TrackFinderOptions = Acts::CombinatorialKalmanFilterOptions<ActsHelper::IndexSourceLinkAccessor::Iterator, Acts::VectorMultiTrajectory>; +using TrackFinderResult = Acts::Result<std::vector<TrackProxy>>; +using Extensions = Acts::CombinatorialKalmanFilterExtensions<Acts::VectorMultiTrajectory>; +using Updater = Acts::GainMatrixUpdater; +using Smoother = Acts::GainMatrixSmoother; +using Stepper = Acts::EigenStepper<>; +using Navigator = Acts::Navigator; +using Propagator = Acts::Propagator<Stepper, Navigator>; + +using CKF = Acts::CombinatorialKalmanFilter<Propagator, Acts::VectorMultiTrajectory>; + +class RecActsTrackFinding : public GaudiAlgorithm +{ + public: + RecActsTrackFinding(const std::string& name, ISvcLocator* svcLoc); + + StatusCode initialize(); + StatusCode execute(); + StatusCode finalize(); + + class TrackFinderFunction + { + public: + virtual ~TrackFinderFunction() = default; + virtual TrackFinderResult operator()(const TrackParameters&, + const TrackFinderOptions&, + TrackContainer&) const = 0; + }; + + static std::shared_ptr<TrackFinderFunction> makeTrackFinderFunction( + std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry, + std::shared_ptr<const Acts::MagneticFieldProvider> magneticField + ); + + private: + // Output collections + DataHandle<edm4hep::TrackCollection> _outColHdl{"ACTSTracks", Gaudi::DataHandle::Writer, this}; + + // CKF config + Gaudi::Property<double> CKFchi2Cut{this, "CKFchi2Cut", std::numeric_limits<double>::max()}; + Gaudi::Property<std::size_t> numMeasurementsCutOff{this, "numMeasurementsCutOff", 1u}; + Gaudi::Property<std::size_t> pickTrackMaxNum{this, "pickTrackMaxNum", 1u}; + Gaudi::Property<bool> CKFtwoWay{this, "CKFtwoWay", true}; + Gaudi::Property<double> m_field{this, "bFieldInZ", 3.0}; // tesla + + template <typename source_link_accessor_container_t> + void computeSharedHits(const source_link_accessor_container_t& sourcelinks, TrackContainer& tracks) const; + + // track finder + std::shared_ptr<TrackFinderFunction> findTracks; + std::optional<Acts::TrackSelector> m_trackSelector; + std::optional<std::variant<Acts::TrackSelector::Config, Acts::TrackSelector::EtaBinnedConfig>> trackSelectorCfg = std::nullopt; + std::shared_ptr<const Acts::MagneticFieldProvider> magneticField; + + SmartIF<IRecActsSvc> recActsSvc; + SmartIF<IChronoStatSvc> chronoStatSvc; + + int _nEvt; + const double _FCT = 2.99792458E-4; + const Acts::Vector3 globalFakeMom{1.e6, 1.e6, 1.e6}; + + const std::array<Acts::BoundIndices, 6> writeout_indices{ + Acts::BoundIndices::eBoundLoc0, Acts::BoundIndices::eBoundPhi, + Acts::BoundIndices::eBoundQOverP, Acts::BoundIndices::eBoundLoc1, + Acts::BoundIndices::eBoundTheta, Acts::BoundIndices::eBoundTime}; + + Acts::GeometryContext geoContext; + Acts::MagneticFieldContext magFieldContext; + Acts::CalibrationContext calibContext; + + mutable std::atomic<std::size_t> m_nTotalSeeds{0}; + mutable std::atomic<std::size_t> m_nDeduplicatedSeeds{0}; + mutable std::atomic<std::size_t> m_nFailedSeeds{0}; + mutable std::atomic<std::size_t> m_nFailedSmoothing{0}; + mutable std::atomic<std::size_t> m_nFailedExtrapolation{0}; + mutable std::atomic<std::size_t> m_nFoundTracks{0}; + mutable std::atomic<std::size_t> m_nSelectedTracks{0}; + mutable std::atomic<std::size_t> m_nStoppedBranches{0}; + mutable std::atomic<std::size_t> m_nFinalTracks{0}; + + // layer hits, VXD (0-5) & ITKBarrel (6-8) + std::array<std::atomic<size_t>, 9> m_nLayerHits{0, 0, 0, 0, 0, 0, 0, 0, 0}; + std::array<std::atomic<size_t>, 6> m_nRec_VTX{0, 0, 0, 0, 0, 0}; + std::array<std::atomic<size_t>, 3> m_nRec_ITKBarrel{0, 0, 0}; + std::array<std::atomic<size_t>, 3> m_nRec_ITKEndcap{0, 0, 0}; + std::array<std::atomic<size_t>, 9> m_n0EventHits{0, 0, 0, 0, 0, 0, 0, 0, 0}; + std::array<std::atomic<size_t>, 9> m_n1EventHits{0, 0, 0, 0, 0, 0, 0, 0, 0}; + std::array<std::atomic<size_t>, 9> m_n2EventHits{0, 0, 0, 0, 0, 0, 0, 0, 0}; + std::array<std::atomic<size_t>, 9> m_n3EventHits{0, 0, 0, 0, 0, 0, 0, 0, 0}; + + mutable tbb::combinable<Acts::VectorMultiTrajectory::Statistics> m_memoryStatistics{[]() { + auto mtj = std::make_shared<Acts::VectorMultiTrajectory>(); + return mtj->statistics(); + }}; + Acts::TrackExtrapolationStrategy extrapolationStrategy = Acts::TrackExtrapolationStrategy::firstOrLast; /// Extrapolation strategy + unsigned int maxSteps = 100000; +}; + +struct TrackFinderFunctionImpl: public RecActsTrackFinding::TrackFinderFunction +{ + CKF trackFinder; + TrackFinderFunctionImpl(CKF&& f) : trackFinder(std::move(f)) {} + + TrackFinderResult operator()( + const TrackParameters& initialParameters, + const TrackFinderOptions& options, + TrackContainer& tracks) const override + { + return trackFinder.findTracks(initialParameters, options, tracks); + }; +}; + +std::shared_ptr<RecActsTrackFinding::TrackFinderFunction> RecActsTrackFinding::makeTrackFinderFunction( + std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry, + std::shared_ptr<const Acts::MagneticFieldProvider> magneticField) +{ + Stepper stepper(magneticField); + Navigator::Config cfg{trackingGeometry}; + cfg.resolvePassive = false; + cfg.resolveMaterial = true; + cfg.resolveSensitive = true; + Navigator navigator(cfg); + Propagator propagator(std::move(stepper), std::move(navigator)); + CKF trackFinder(std::move(propagator)); + + // build the track finder functions. owns the track finder object. + return std::make_shared<TrackFinderFunctionImpl>(std::move(trackFinder)); +} + +// Specialize std::hash for SeedIdentifier +// This is required to use SeedIdentifier as a key in an `std::unordered_map`. +template <class T, std::size_t N> +struct std::hash<std::array<T, N>> +{ + std::size_t operator()(const std::array<T, N>& array) const + { + std::hash<T> hasher; + std::size_t result = 0; + for (auto&& element : array) { boost::hash_combine(result, hasher(element)); } + return result; + } +}; + +class MeasurementSelector +{ +public: + using Traj = Acts::VectorMultiTrajectory; + explicit MeasurementSelector(Acts::MeasurementSelector selector): m_selector(std::move(selector)) {} + + void setSeed(const std::optional<ActsHelper::SimSeed>& seed) { m_seed = seed; } + + Acts::Result<std::pair<std::vector<Traj::TrackStateProxy>::iterator, std::vector<Traj::TrackStateProxy>::iterator>> select( + std::vector<Traj::TrackStateProxy>& candidates, bool& isOutlier, const Acts::Logger& logger) const + { + if (m_seed.has_value()) + { + std::vector<Traj::TrackStateProxy> newCandidates; + for (const auto& candidate : candidates) + { + if (isSeedCandidate(candidate)) { newCandidates.push_back(candidate); } + } + if (!newCandidates.empty()) { candidates = std::move(newCandidates); } + } + + return m_selector.select<Acts::VectorMultiTrajectory>(candidates, isOutlier, logger); + } + +private: + Acts::MeasurementSelector m_selector; + std::optional<ActsHelper::SimSeed> m_seed; + + bool isSeedCandidate(const Traj::TrackStateProxy& candidate) const + { + assert(candidate.hasUncalibratedSourceLink()); + const Acts::SourceLink& sourceLink = candidate.getUncalibratedSourceLink(); + for (const auto& sp : m_seed->sp()) + { + for (const auto& sl : sp->sourceLinks()) + { + if (sourceLink.get<ActsHelper::IndexSourceLink>() == sl.get<ActsHelper::IndexSourceLink>()) { return true; } + } + } + return false; + } +}; + +/// Source link indices of the bottom, middle, top measurements. +/// In case of strip seeds only the first source link of the pair is used. +using SeedIdentifier = std::array<ActsHelper::Index, 3>; + +/// Build a seed identifier from a seed. +/// +/// @param seed The seed to build the identifier from. +/// @return The seed identifier. +SeedIdentifier makeSeedIdentifier(const ActsHelper::SimSeed& seed) +{ + SeedIdentifier result; + for (const auto& [i, sp] : Acts::enumerate(seed.sp())) + { + const Acts::SourceLink& firstSourceLink = sp->sourceLinks().front(); + result.at(i) = firstSourceLink.get<ActsHelper::IndexSourceLink>().index(); + } + + return result; +} + +/// Visit all possible seed identifiers of a track. +/// +/// @param track The track to visit the seed identifiers of. +/// @param visitor The visitor to call for each seed identifier. +template <typename Visitor> +void visitSeedIdentifiers(const TrackProxy& track, Visitor visitor) +{ + // first we collect the source link indices of the track states + std::vector<ActsHelper::Index> sourceLinkIndices; + sourceLinkIndices.reserve(track.nMeasurements()); + + for (const auto& trackState : track.trackStatesReversed()) + { + if (!trackState.hasUncalibratedSourceLink()) { continue; } + const Acts::SourceLink& sourceLink = trackState.getUncalibratedSourceLink(); + sourceLinkIndices.push_back(sourceLink.get<ActsHelper::IndexSourceLink>().index()); + } + + // then we iterate over all possible triplets and form seed identifiers + for (std::size_t i = 0; i < sourceLinkIndices.size(); ++i) + { + for (std::size_t j = i + 1; j < sourceLinkIndices.size(); ++j) + { + for (std::size_t k = j + 1; k < sourceLinkIndices.size(); ++k) + { + // Putting them into reverse order (k, j, i) to compensate for the + // `trackStatesReversed` above. + visitor({sourceLinkIndices.at(k), sourceLinkIndices.at(j), + sourceLinkIndices.at(i)}); + } + } + } +} + +class BranchStopper +{ +public: + using Config = std::optional<std::variant<Acts::TrackSelector::Config, Acts::TrackSelector::EtaBinnedConfig>>; + using BranchStopperResult = Acts::CombinatorialKalmanFilterBranchStopperResult; + + mutable std::atomic<std::size_t> m_nStoppedBranches{0}; + + explicit BranchStopper(const Config& config) : m_config(config) {} + + BranchStopperResult operator()( + const Acts::CombinatorialKalmanFilterTipState& tipState, + Acts::VectorMultiTrajectory::TrackStateProxy& trackState) const + { + if (!m_config.has_value()) { return BranchStopperResult::Continue; } + + const Acts::TrackSelector::Config* singleConfig = std::visit( + [&](const auto& config) -> const Acts::TrackSelector::Config* + { + using T = std::decay_t<decltype(config)>; + if constexpr (std::is_same_v<T, Acts::TrackSelector::Config>) + { + return &config; + } else if constexpr (std::is_same_v<T, Acts::TrackSelector::EtaBinnedConfig>) + { + double theta = trackState.parameters()[Acts::eBoundTheta]; + double eta = -std::log(std::tan(0.5 * theta)); + return config.hasCuts(eta) ? &config.getCuts(eta) : nullptr; + } + }, *m_config); + + if (singleConfig == nullptr) + { + ++m_nStoppedBranches; + return BranchStopperResult::StopAndDrop; + } + + bool enoughMeasurements = tipState.nMeasurements >= singleConfig->minMeasurements; + bool tooManyHoles = tipState.nHoles > singleConfig->maxHoles; + bool tooManyOutliers = tipState.nOutliers > singleConfig->maxOutliers; + + if (tooManyHoles || tooManyOutliers) + { + ++m_nStoppedBranches; + return enoughMeasurements ? BranchStopperResult::StopAndKeep + : BranchStopperResult::StopAndDrop; + } + + return BranchStopperResult::Continue; +} + +private: + Config m_config; +}; + +#endif // RecActsTrackFinding_H \ No newline at end of file diff --git a/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTrackFitting.cpp b/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTrackFitting.cpp new file mode 100644 index 00000000..e78742e0 --- /dev/null +++ b/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTrackFitting.cpp @@ -0,0 +1,144 @@ +// dependence +#include "RecActsTrackFitting.h" + +DECLARE_COMPONENT(RecActsTrackFitting) + +RecActsTrackFitting::RecActsTrackFitting(const std::string& name, ISvcLocator* svcLoc) + : GaudiAlgorithm(name, svcLoc) +{ + declareProperty("ACTSFitOutCol", _outColHdl, "ACTS Track Fitting Output track collection"); +} + +StatusCode RecActsTrackFitting::initialize() +{ + recActsSvc = service<IRecActsSvc>("RecActsSvc"); + if (!recActsSvc) { + error() << "Failed to get RecActsSvc" << endmsg; + return StatusCode::FAILURE; + } + + chronoStatSvc = service<IChronoStatSvc>("ChronoStatSvc"); + + magneticField = std::make_shared<Acts::ConstantBField>(Acts::Vector3(0., 0., m_field.value()*_FCT)); + + if (m_fitType == "gsf") { + fit = ActsHelper::makeGsfFitterFunction(recActsSvc->Geometry(), magneticField, + betheHeitlerApprox, m_maxComponents.value(), weightCutoff, mergeMethod, reductionAlg, + *Acts::getDefaultLogger("Gsf", Acts::Logging::INFO)); + } else if (m_fitType == "kalman") { + fit = ActsHelper::makeKalmanFitterFunction(recActsSvc->Geometry(), magneticField); + } else { + error() << "Invalid fit type: " << m_fitType << endmsg; + return StatusCode::FAILURE; + } + + // fit = ActsHelper::makeGlobalChiSquareFitterFunction(recActsSvc->Geometry(), magneticField); (ok) + + _nEvt = -1; + return StatusCode::SUCCESS; +} + +StatusCode RecActsTrackFitting::execute() +{ + _nEvt++; + + auto trkCol = _outColHdl.createAndPut(); + + auto measurements = recActsSvc->Measurements(); + auto trackSourceLinks = recActsSvc->TrackSourceLinks(); + auto trackParameters = recActsSvc->TrackParameters(); + + chronoStatSvc->chronoStart("Track Fitting & WriteOut"); + + if (trackParameters->size() == 0) { + debug() << "No track parameters found for event " << _nEvt << endmsg; + return StatusCode::SUCCESS; + } + + auto initialParameters = trackParameters->back(); + + if (initialParameters.size() == 0) { + debug() << "No initial parameters found for event " << _nEvt << endmsg; + return StatusCode::SUCCESS; + } + + if (initialParameters.size() != trackSourceLinks->size()) { + debug() << "Number of tracks and source links do not match for event " << _nEvt << endmsg; + return StatusCode::SUCCESS; + } + + auto pSurface = Acts::Surface::makeShared<Acts::PerigeeSurface>(Acts::Vector3{0., 0., 0.}); + ActsHelper::PassThroughCalibrator pcalibrator; + ActsHelper::MeasurementCalibratorAdapter calibrator(pcalibrator, *measurements); + ActsHelper::TrackFitterFunction::GeneralFitterOptions options{ + geoContext, magFieldContext, calibContext, pSurface.get(), Acts::PropagatorPlainOptions()}; + + for (int i = 0; i < initialParameters.size(); i++) + { + auto trackContainer = std::make_shared<Acts::VectorTrackContainer>(); + auto trackStateContainer = std::make_shared<Acts::VectorMultiTrajectory>(); + ActsHelper::TrackContainer tracks(trackContainer, trackStateContainer); + + auto cur_trackSourceLinks = trackSourceLinks->at(i); + auto cur_trackParameters = initialParameters.at(i); + auto result = (*fit)(cur_trackSourceLinks, cur_trackParameters, options, calibrator, tracks); + + if (!result.ok()) { + info() << "Track fit failed for event " << _nEvt << endmsg; + continue; + } + + std::stringstream ss; + trackStateContainer->statistics().toStream(ss); + debug() << ss.str() << endmsg; + + ActsHelper::ConstTrackContainer constTracks + { + std::make_shared<Acts::ConstVectorTrackContainer>(std::move(*trackContainer)), + std::make_shared<Acts::ConstVectorMultiTrajectory>(std::move(*trackStateContainer)) + }; + + for (const auto& cur_track : constTracks) + { + auto writeout_track = trkCol->create(); + + writeout_track.setChi2(cur_track.chi2()); + writeout_track.setNdf(cur_track.nDoF()); + writeout_track.setDEdx(cur_track.absoluteMomentum() / Acts::UnitConstants::GeV); + + // TODO: covmatrix need to be converted + std::array<float, 21> writeout_covMatrix; + auto cur_track_covariance = cur_track.covariance(); + for (int i = 0; i < 6; i++) { + for (int j = 0; j < 6-i; j++) { + writeout_covMatrix[int((13-i)*i/2 + j)] = cur_track_covariance(writeout_indices[i], writeout_indices[j]); + } + } + // location: At{Other|IP|FirstHit|LastHit|Calorimeter|Vertex}|LastLocation + // TrackState: location, d0, phi, omega, z0, tanLambda, time, referencePoint, covMatrix + edm4hep::TrackState writeout_trackState{ + 1, // location: AtOther + cur_track.loc0() / Acts::UnitConstants::mm, // d0 + cur_track.phi(), // phi + cur_track.qOverP() * _FCT * m_field.value() / sin(cur_track.theta()) , // omega = qop * sin(theta) * _FCT * bf + cur_track.loc1() / Acts::UnitConstants::mm, // z0 + 1 / tan(cur_track.theta()), // tanLambda = 1 / tan(theta) + cur_track.time(), // time + ::edm4hep::Vector3f(0, 0, 0), // referencePoint + writeout_covMatrix + }; + + debug() << "Found track with momentum " << cur_track.absoluteMomentum() / Acts::UnitConstants::GeV << " GeV!" << endmsg; + writeout_track.addToTrackStates(writeout_trackState); + } + } + + chronoStatSvc->chronoStop("Track Fitting & WriteOut"); + + return StatusCode::SUCCESS; +} + +StatusCode RecActsTrackFitting::finalize() +{ + return StatusCode::SUCCESS; +} \ No newline at end of file diff --git a/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTrackFitting.h b/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTrackFitting.h new file mode 100644 index 00000000..e3a1291a --- /dev/null +++ b/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTrackFitting.h @@ -0,0 +1,194 @@ +#ifndef RecActsTrackFitting_H +#define RecActsTrackFitting_H + +// gaudi framework +#include "k4FWCore/DataHandle.h" +#include "GaudiAlg/GaudiAlgorithm.h" + +#include "UTIL/ILDConf.h" +#include "DataHelper/Navigation.h" + +// services +#include "RecActsSvc/IRecActsSvc.h" +#include "DetInterface/IGeomSvc.h" + +// DD4hep +#include "DD4hep/Detector.h" +#include "DDRec/ISurface.h" +#include "DDRec/SurfaceManager.h" + +// edm4hep +#include "edm4hep/MCParticle.h" +#include "edm4hep/MCParticleCollection.h" +#include "edm4hep/TrackerHitCollection.h" +#include "edm4hep/SimTrackerHitCollection.h" +#include "edm4hep/EventHeaderCollection.h" + +#include "edm4hep/Track.h" +#include "edm4hep/MutableTrack.h" +#include "edm4hep/TrackState.h" +#include "edm4hep/TrackCollection.h" +// Acts +#include "Acts/Definitions/Algebra.hpp" +#include "Acts/EventData/GenericBoundTrackParameters.hpp" +#include "Acts/EventData/SourceLink.hpp" +#include "Acts/EventData/TrackProxy.hpp" +#include "Acts/EventData/VectorMultiTrajectory.hpp" +#include "Acts/EventData/VectorTrackContainer.hpp" +#include "Acts/Propagator/Propagator.hpp" +#include "Acts/Surfaces/PerigeeSurface.hpp" +#include "Acts/Surfaces/Surface.hpp" +#include "Acts/Utilities/Result.hpp" + +#include "Acts/Definitions/Direction.hpp" +#include "Acts/Definitions/TrackParametrization.hpp" +#include "Acts/EventData/MultiTrajectory.hpp" +#include "Acts/EventData/TrackContainer.hpp" +#include "Acts/EventData/TrackStatePropMask.hpp" +#include "Acts/EventData/detail/CorrectedTransformationFreeToBound.hpp" +#include "Acts/Geometry/GeometryIdentifier.hpp" +#include "Acts/Propagator/DirectNavigator.hpp" +#include "Acts/Propagator/EigenStepper.hpp" +#include "Acts/Propagator/Navigator.hpp" +#include "Acts/TrackFitting/GlobalChiSquareFitter.hpp" +#include "Acts/TrackFitting/KalmanFitter.hpp" +#include "Acts/Utilities/Delegate.hpp" +#include "Acts/Utilities/Logger.hpp" + +namespace Acts +{ + class MagneticFieldProvider; + class TrackingGeometry; +} + +class RecActsTrackFitting : public GaudiAlgorithm +{ + public: + RecActsTrackFitting(const std::string& name, ISvcLocator* svcLoc); + + StatusCode initialize(); + StatusCode execute(); + StatusCode finalize(); + + private: + // Output collections + DataHandle<edm4hep::TrackCollection> _outColHdl{"ACTSFitTracks", Gaudi::DataHandle::Writer, this}; + + Gaudi::Property<double> m_field{this, "bFieldInZ", 3.0}; // tesla + Gaudi::Property<std::string> m_fitType{this, "fitType", "kalman"}; // gsf or kalman + Gaudi::Property<std::size_t> m_maxComponents{this, "maxComponents", 12}; + + // services + SmartIF<IRecActsSvc> recActsSvc; + SmartIF<IChronoStatSvc> chronoStatSvc; + + std::shared_ptr<ActsHelper::TrackFitterFunction> fit; + std::shared_ptr<const Acts::MagneticFieldProvider> magneticField; + + // context + Acts::GeometryContext geoContext; + Acts::MagneticFieldContext magFieldContext; + Acts::CalibrationContext calibContext; + + Acts::AtlasBetheHeitlerApprox<6, 5> makeBetheHeitlerApprox() { + // reference: https://gitlab.cern.ch/atlas/athena/ + // Tracking/TrkFitter/TrkGaussianSumFilter/Data/GeantSim_LT01_cdf_nC6_O5.par + constexpr static Acts::AtlasBetheHeitlerApprox<6, 5>::Data LT01_cdf_cmps6_order5_data = {{ + // Component #1 + { + {{3.2101094136612709e+06, -9.4705630748389300e+05, 1.0829875911775141e+05, -6.1863554011577025e+03, 2.0135361106894280e+02, -8.0761514988818153e+00}}, + {{4.5079440999297943e+05, -1.0647181055807657e+05, 9.0139114799507752e+03, -3.6081366141823679e+02, 7.0376737639960325e+00, -2.3610285047746506e+00}}, + {{7.4586241329435969e+05, -1.6634188647165423e+05, 1.2838436550628834e+04, -4.5120828291620853e+02, 8.1842526809672229e+00, -5.9197536687071333e+00}} + }, + // Component #2 + { + {{3.5884379653355042e+06, -1.0531756617027025e+06, 1.1934641124479045e+05, -6.7061190805056403e+03, 2.1095020483594095e+02, -6.5568419073184483e+00}}, + {{0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, -1.5062019624783798e+00, -3.1569307956279197e-01}}, + {{0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, -1.3027693288928379e+00, -3.5400481738796068e+00}} + }, + // Component #3 + { + {{2.3155452602605596e+06, -7.1891501255134703e+05, 8.6585158124840658e+04, -5.1799762005076909e+03, 1.7441315420719826e+02, -5.3334936315347807e+00}}, + {{0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, -3.6114283847420849e+00, 1.5982998291730415e+00}}, + {{0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, -9.8697714460669317e-01, -4.0296821938338319e+00}} + }, + // Component #4 + { + {{ 2.5492741738774744e+06, -7.8599345529792004e+05, 9.3737591740107193e+04, -5.5326423872095538e+03, 1.8118619438298339e+02, -5.2390153677605218e+00}}, + {{-3.1098153044707078e+05, 1.1007248411865601e+05, -1.4280144141196661e+04, 8.4109025518696251e+02, -2.5970904293141370e+01, 3.1892310883718391e+00}}, + {{-5.5577338590808783e+05, 1.3154358085719805e+05, -1.1694747055412488e+04, 5.6105436016810438e+02, -1.5530677686084243e+01, -6.1618612270588793e+00}} + }, + // Component #5 + { + {{ 2.6932154305977230e+06, -8.2250052647013229e+05, 9.6899959691172277e+04, -5.6297294779617941e+03, 1.7951168208697126e+02, -4.6983951237217196e+00}}, + {{ 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, -5.4812317220100892e+00, 4.7513315671141720e+00}}, + {{-5.2836565144663176e+05, 1.2409531281512717e+05, -1.0931090612321719e+04, 5.2509257144231174e+02, -1.3301367935777353e+01, -9.1621620095231666e+00}} + }, + // Component #6 + { + {{-2.7011359673979054e+06, 8.2180193078306376e+05, -9.6658466651702445e+04, 5.6226808449705832e+03, -1.8772212765456376e+02, 3.8617748667187937e+00}}, + {{-5.2076889316070534e+05, 1.5949629384340727e+05, -1.8999044900140336e+04, 1.1022106651944848e+03, -3.4436466136411170e+01, 7.4376238285956164e+00}}, + {{ 6.4766725322662554e+04, -2.6994996461319020e+04, 2.0876601827129484e+03, 7.6609049415560705e+01, 2.6995934389534368e+00, -1.6338670795256700e+01}} + } + }}; + + // Tracking/TrkFitter/TrkGaussianSumFilterUtils/Data/GeantSim_GT01_cdf_nC6_O5.par + constexpr static Acts::AtlasBetheHeitlerApprox<6, 5>::Data GT01_cdf_cmps6_order5_data = {{ + // Component #1 + { + {{ 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 3.4177030972717031e+00, -4.5023370509744884e+00}}, + {{ 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, -3.9457052964315942e+00, -2.0763454756086683e+00}}, + {{ 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, -7.1457121881276997e+00, -5.3628979048490102e+00}} + }, + // Component #2 + { + {{ 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 1.1451687460393387e+00, -2.8495425297831072e+00}}, + {{ 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, -5.2948114471475387e+00, -9.8180069037555190e-02}}, + {{ 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, -6.2682749645404909e+00, -3.1860384549381653e+00}} + }, + // Component #3 + { + {{-1.6121439489178472e+04, 1.5384843175364240e+04, -5.6689338934841298e+03, 9.8861606625107947e+02, -7.4716003818930389e+01, -3.8665489218520077e-04}}, + {{ 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, -5.3892009434433490e+00, 1.6646106984668607e+00}}, + {{ 8.5418865316008014e+04, -8.4729845210357686e+04, 3.2509874328900842e+04, -6.0360232287805875e+03, 5.4703207243206543e+02, -2.3269764393538701e+01}} + }, + // Component #4 + { + {{-2.1753363459026186e+03, 2.5480537135521458e+03, -1.0800153221381784e+03, 1.9801727578735878e+02, -1.1004696684536585e+01, -1.9122411799639756e+00}}, + {{-7.2398222368353381e+04, 7.1692026459293120e+04, -2.7540169230500542e+04, 5.1273037919535100e+03, -4.6741803632344750e+02, 1.9108986234485663e+01}}, + {{ 1.1990918855988217e+05, -1.1822072172982995e+05, 4.5191687950925800e+04, -8.3693591975687395e+03, 7.5772428412511772e+02, -3.2747029952012895e+01}} + }, + // Component #5 + { + {{ 3.9301134316298808e+03, -3.7541418325082136e+03, 1.4425795489191560e+03, -2.9377291122879348e+02, 3.3552924307793113e+01, -3.1130586170893051e+00}}, + {{ 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, 0.0000000000000000e+00, -6.1138164489828783e+00, 4.6083958462708150e+00}}, + {{ 1.5753424210854530e+05, -1.5644030230854396e+05, 6.0286848768357333e+04, -1.1264081605869356e+04, 1.0303907886480429e+03, -4.5437223190174670e+01}} + }, + // Component #6 + { + {{ 3.2397164095336298e+04, -3.2114134513896468e+04, 1.2294103984600111e+04, -2.2470209645997870e+03, 1.8686345236342740e+02, -5.6709849549599838e+00}}, + {{-5.3617340636071443e+04, 5.4302846581616992e+04, -2.1435558635721187e+04, 4.1270402937878653e+03, -3.9750537586689597e+02, 2.1789322216626250e+01}}, + {{ 1.7215536713492026e+05, -1.7277470681531032e+05, 6.7174146724203878e+04, -1.2602759089486393e+04, 1.1522785437972470e+03, -5.3827210284314098e+01}} + } + }}; + + return Acts::AtlasBetheHeitlerApprox<6, 5>( + LT01_cdf_cmps6_order5_data, GT01_cdf_cmps6_order5_data, true, true); + }; + + //gsf parameters + // Acts::AtlasBetheHeitlerApprox<6, 5> betheHeitlerApprox = makeBetheHeitlerApprox(); + Acts::AtlasBetheHeitlerApprox<6, 5> betheHeitlerApprox = Acts::makeDefaultBetheHeitlerApprox(); + double weightCutoff = 1.0e-4; + Acts::ComponentMergeMethod mergeMethod = Acts::ComponentMergeMethod::eMaxWeight; + ActsHelper::MixtureReductionAlgorithm reductionAlg = ActsHelper::MixtureReductionAlgorithm::KLDistance; + + int _nEvt; + const double _FCT = 2.99792458E-4; + const std::array<Acts::BoundIndices, 6> writeout_indices{ + Acts::BoundIndices::eBoundLoc0, Acts::BoundIndices::eBoundPhi, + Acts::BoundIndices::eBoundQOverP, Acts::BoundIndices::eBoundLoc1, + Acts::BoundIndices::eBoundTheta, Acts::BoundIndices::eBoundTime}; +}; + +#endif // RecActsTrackFitting_H \ No newline at end of file diff --git a/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTrackParamsEstimation.cpp b/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTrackParamsEstimation.cpp new file mode 100644 index 00000000..5f0f2b91 --- /dev/null +++ b/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTrackParamsEstimation.cpp @@ -0,0 +1,134 @@ +// dependence +#include "RecActsTrackParamsEstimation.h" + +DECLARE_COMPONENT(RecActsTrackParamsEstimation) + +RecActsTrackParamsEstimation::RecActsTrackParamsEstimation(const std::string& name, ISvcLocator* svcLoc) + : GaudiAlgorithm(name, svcLoc) +{ +} + +StatusCode RecActsTrackParamsEstimation::initialize() +{ + recActsSvc = service<IRecActsSvc>("RecActsSvc"); + if (!recActsSvc) { + error() << "Failed to get RecActsSvc" << endmsg; + return StatusCode::FAILURE; + } + + chronoStatSvc = service<IChronoStatSvc>("ChronoStatSvc"); + + info() << "Assume Particle: " << m_particle.value() << endmsg; + if(m_particle.value() == "muon"){ + particleHypothesis = Acts::ParticleHypothesis::muon(); + } + else if(m_particle.value() == "pion"){ + particleHypothesis = Acts::ParticleHypothesis::pion(); + } + else if(m_particle.value() == "electron"){ + particleHypothesis = Acts::ParticleHypothesis::electron(); + } + else if(m_particle.value() == "kaon"){ + particleHypothesis = Acts::ParticleHypothesis::kaon(); + } + else if(m_particle.value() == "proton"){ + particleHypothesis = Acts::ParticleHypothesis::proton(); + } + else if(m_particle.value() == "photon"){ + particleHypothesis = Acts::ParticleHypothesis::photon(); + } + else if(m_particle.value() == "geantino"){ + particleHypothesis = Acts::ParticleHypothesis::geantino(); + } + else if(m_particle.value() == "chargedgeantino"){ + particleHypothesis = Acts::ParticleHypothesis::chargedGeantino(); + } + else{ + info() << "Supported Assumed Particle: " << particleNames[0] << ", " << particleNames[1] << ", " << particleNames[2] << ", " + << particleNames[3] << ", " << particleNames[4] << ", " << particleNames[5] << ", " + << particleNames[6] << ", " << particleNames[7] << endmsg; + error() << "Unsupported particle name " << m_particle.value() << endmsg; + return StatusCode::FAILURE; + } + + acts_field_value = Acts::Vector3(0., 0., m_field.value() * _FCT); + bFieldMin = 0.1 * m_field.value() * _FCT * Acts::UnitConstants::T; + + _nEvt = -1; + return StatusCode::SUCCESS; +} + +StatusCode RecActsTrackParamsEstimation::execute() +{ + _nEvt++; + // DEBUG + // info() << "DEBUG: print first seed" << endmsg; + // auto seed = recActsSvc->GetSeed(0); + // for (const auto& sp : seed.sp()) { + // info() << "seed: x=" << sp->x() << " y=" << sp->y() << " z=" << sp->z() << endmsg; + // } + auto trackParameters = recActsSvc->TrackParameters(); + auto seeds = recActsSvc->Seeds(); + auto selectedSeeds = recActsSvc->SelectedSeeds(); + + ActsHelper::SimSeedContainer currentSeed; + std::vector<Acts::BoundTrackParameters> initialParameters; + + auto trackingGeometry = recActsSvc->Geometry(); + if (!trackingGeometry) { + error() << "Tracking geometry is not set" << endmsg; + return StatusCode::FAILURE; + } + + chronoStatSvc->chronoStart("Track Params Estimation"); + + ActsHelper::IndexSourceLink::SurfaceAccessor surfaceAccessor{*trackingGeometry}; + + for (std::size_t iseed = 0; iseed < seeds->size(); ++iseed) + { + const auto& seed = seeds->at(iseed); + const auto bottomSP = seed.sp().front(); + const auto& sourceLink = bottomSP->sourceLinks()[0]; + const Acts::Surface* surface = surfaceAccessor(sourceLink); + if (surface == nullptr) { + debug() << "Surface from source link is not found in the tracking geometry: iseed " << iseed << endmsg; + continue; + } + + auto optParams = Acts::estimateTrackParamsFromSeed( + geoContext, seed.sp().begin(), seed.sp().end(), *surface, acts_field_value, bFieldMin); + + if (!optParams.has_value()) { + debug() << "Estimation of track parameters for seed " << iseed << " failed." << endmsg; + continue; + } + + const auto& params = optParams.value(); + Acts::BoundSquareMatrix cov = Acts::BoundSquareMatrix::Zero(); + for (std::size_t i = Acts::eBoundLoc0; i < Acts::eBoundSize; ++i) { + double sigma = initialSigmas[i]; + sigma += abs(initialSimgaQoverPCoefficients[i] * params[Acts::eBoundQOverP]); + double var = sigma * sigma; + // var *= noTimeVarInflation.value(); + if (i == Acts::eBoundTime && !bottomSP->t().has_value()) { var *= noTimeVarInflation.value(); } + var *= initialVarInflation.value()[i]; + + cov(i, i) = var; + } + initialParameters.emplace_back(surface->getSharedPtr(), params, cov, particleHypothesis); + currentSeed.push_back(seed); + + debug() << "A track with p=" << -1 / params[Acts::eBoundQOverP] << " GeV is estimated for event " << _nEvt << "!" << endmsg; + } + + trackParameters->push_back(initialParameters); + selectedSeeds->push_back(currentSeed); + chronoStatSvc->chronoStop("Track Params Estimation"); + + return StatusCode::SUCCESS; +} + +StatusCode RecActsTrackParamsEstimation::finalize() +{ + return StatusCode::SUCCESS; +} \ No newline at end of file diff --git a/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTrackParamsEstimation.h b/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTrackParamsEstimation.h new file mode 100644 index 00000000..70616854 --- /dev/null +++ b/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTrackParamsEstimation.h @@ -0,0 +1,80 @@ +#ifndef RecActsTrackParamsEstimation_H +#define RecActsTrackParamsEstimation_H + +// gaudi framework +#include "GaudiAlg/GaudiAlgorithm.h" + +// services +#include "RecActsSvc/IRecActsSvc.h" +#include "DetInterface/IGeomSvc.h" + +// Acts +#include "Acts/Definitions/Algebra.hpp" +#include "Acts/Definitions/TrackParametrization.hpp" +#include "Acts/Definitions/Units.hpp" +#include "Acts/EventData/ParticleHypothesis.hpp" +#include "Acts/EventData/SourceLink.hpp" +#include "Acts/Geometry/TrackingGeometry.hpp" +#include "Acts/Geometry/GeometryIdentifier.hpp" +#include "Acts/MagneticField/ConstantBField.hpp" +#include "Acts/MagneticField/InterpolatedBFieldMap.hpp" +#include "Acts/MagneticField/MagneticFieldProvider.hpp" +#include "Acts/Seeding/EstimateTrackParamsFromSeed.hpp" +#include "Acts/Seeding/Seed.hpp" +#include "Acts/Surfaces/Surface.hpp" +#include "Acts/Utilities/Result.hpp" +#include "Acts/Utilities/Logger.hpp" + +class RecActsTrackParamsEstimation : public GaudiAlgorithm +{ + public: + RecActsTrackParamsEstimation(const std::string& name, ISvcLocator* svcLoc); + + StatusCode initialize(); + StatusCode execute(); + StatusCode finalize(); + + private: + // properties + Gaudi::Property<std::string> m_particle{this, "AssumeParticle", "muon"}; + Gaudi::Property<double> m_field{this, "bFieldInZ", 3.0}; // tesla + Gaudi::Property<std::vector<double>> initialVarInflation{this, "initialVarInflation", {1, 1, 1, 1, 1, 1}}; + Gaudi::Property<double> noTimeVarInflation{this, "noTimeVarInflation", 1.}; + + // services + SmartIF<IRecActsSvc> recActsSvc; + SmartIF<IChronoStatSvc> chronoStatSvc; + + // param estimate configuration + // Params: loc0, loc1, phi, theta, qop, time + // double noTimeVarInflation = 100.; + std::array<double, 6> initialSigmas = { + 5 * Acts::UnitConstants::um, + 5 * Acts::UnitConstants::um, + 2e-2 * Acts::UnitConstants::degree, + 2e-2 * Acts::UnitConstants::degree, + 0 * Acts::UnitConstants::e / Acts::UnitConstants::GeV, + 1 * Acts::UnitConstants::s + }; + std::array<double, 6> initialSimgaQoverPCoefficients = { + 0 * Acts::UnitConstants::mm / (Acts::UnitConstants::e * Acts::UnitConstants::GeV), + 0 * Acts::UnitConstants::mm / (Acts::UnitConstants::e * Acts::UnitConstants::GeV), + 0 * Acts::UnitConstants::degree / (Acts::UnitConstants::e * Acts::UnitConstants::GeV), + 0 * Acts::UnitConstants::degree / (Acts::UnitConstants::e * Acts::UnitConstants::GeV), + 0.1, + 0 * Acts::UnitConstants::ns / (Acts::UnitConstants::e * Acts::UnitConstants::GeV) + }; + + std::array<std::string, 8> particleNames = {"muon", "pion", "electron", "kaon", "proton", "photon", "geantino", "chargedgeantino"}; + + // configs to build acts geometry + int _nEvt; + const double _FCT = 2.99792458E-4; + Acts::Vector3 acts_field_value; + double bFieldMin; + Acts::GeometryContext geoContext; + Acts::ParticleHypothesis particleHypothesis = Acts::ParticleHypothesis::muon(); + +}; + +#endif // RecActsTrackParamsEstimation_H \ No newline at end of file diff --git a/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTrackReFitting.cpp b/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTrackReFitting.cpp new file mode 100644 index 00000000..87ce36e5 --- /dev/null +++ b/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTrackReFitting.cpp @@ -0,0 +1,401 @@ +// dependence +#include "RecActsTrackReFitting.h" + +DECLARE_COMPONENT(RecActsTrackReFitting) + +RecActsTrackReFitting::RecActsTrackReFitting(const std::string& name, ISvcLocator* svcLoc) + : GaudiAlgorithm(name, svcLoc) +{ +} + +StatusCode RecActsTrackReFitting::initialize() +{ + // -------------------------------- + // ---- initialize properties ----- + // -------------------------------- + + info() << "Assume Particle: " << m_particle.value() << endmsg; + if(m_particle.value() == "muon"){ + particleHypothesis = Acts::ParticleHypothesis::muon(); + } + else if(m_particle.value() == "pion"){ + particleHypothesis = Acts::ParticleHypothesis::pion(); + } + else if(m_particle.value() == "electron"){ + particleHypothesis = Acts::ParticleHypothesis::electron(); + } + else if(m_particle.value() == "kaon"){ + particleHypothesis = Acts::ParticleHypothesis::kaon(); + } + else if(m_particle.value() == "proton"){ + particleHypothesis = Acts::ParticleHypothesis::proton(); + } + else if(m_particle.value() == "photon"){ + particleHypothesis = Acts::ParticleHypothesis::photon(); + } + else if(m_particle.value() == "geantino"){ + particleHypothesis = Acts::ParticleHypothesis::geantino(); + } + else if(m_particle.value() == "chargedgeantino"){ + particleHypothesis = Acts::ParticleHypothesis::chargedGeantino(); + } + else{ + info() << "Supported Assumed Particle: " << particleNames[0] << ", " << particleNames[1] << ", " << particleNames[2] << ", " + << particleNames[3] << ", " << particleNames[4] << ", " << particleNames[5] << ", " + << particleNames[6] << ", " << particleNames[7] << endmsg; + error() << "Unsupported particle name " << m_particle.value() << endmsg; + return StatusCode::FAILURE; + } + + vtx_decoder = new dd4hep::DDSegmentation::BitFieldCoder("system:5,side:-2,layer:9,module:8,sensor:32:16"); + if(!vtx_decoder){ + info() << "Failed to create vtx_decoder" << endmsg; + return StatusCode::FAILURE; + } + + ITKBarrel_decoder = new dd4hep::DDSegmentation::BitFieldCoder("system:5,side:-2,layer:9,stave:8,module:8,sensor:5"); + if(!ITKBarrel_decoder){ + info() << "Failed to create ITKBarrel_decoder" << endmsg; + return StatusCode::FAILURE; + } + + ITKEndcap_decoder = new dd4hep::DDSegmentation::BitFieldCoder("system:5,side:-2,layer:9,module:8,sensor:8"); + if(!ITKEndcap_decoder){ + info() << "Failed to create ITKEndcap_decoder" << endmsg; + return StatusCode::FAILURE; + } + + tpc_decoder = new dd4hep::DDSegmentation::BitFieldCoder("system:5,side:-2,layer:13,module:6,sensor:6"); + if(!tpc_decoder){ + info() << "Failed to create TPC_decoder" << endmsg; + return StatusCode::FAILURE; + } + + OTKBarrel_decoder = new dd4hep::DDSegmentation::BitFieldCoder("system:5,side:-2,layer:9,module:8,iladder:32:4,oladder:-4,mmodule:-6"); + if(!OTKBarrel_decoder){ + info() << "Failed to create OTKBarrel_decoder" << endmsg; + return StatusCode::FAILURE; + } + + recActsSvc = service<IRecActsSvc>("RecActsSvc"); + if (!recActsSvc) { + error() << "Failed to get RecActsSvc" << endmsg; + return StatusCode::FAILURE; + } + + // -------------------------------- + // ---- initialize recActsSvc ---- + // -------------------------------- + + recActsSvc = service<IRecActsSvc>("RecActsSvc"); + if (!recActsSvc) { + error() << "Failed to get RecActsSvc" << endmsg; + return StatusCode::FAILURE; + } + + magneticField = std::make_shared<Acts::ConstantBField>(Acts::Vector3(0., 0., m_field.value()*_FCT)); + fit = ActsHelper::makeKalmanFitterFunction(recActsSvc->Geometry(), magneticField); + // fit = ActsHelper::makeGsfFitterFunction(recActsSvc->Geometry(), magneticField); (not working) + // fit = ActsHelper::makeGlobalChiSquareFitterFunction(recActsSvc->Geometry(), magneticField); (ok) + + _nEvt = -1; + return StatusCode::SUCCESS; +} + +StatusCode RecActsTrackReFitting::execute() +{ + _nEvt++; + + auto trkCol = _outColHdl.createAndPut(); + + const edm4hep::TrackCollection* trackCols = nullptr; + try { trackCols = _inTrackColHdl.get(); } + catch ( GaudiException &e ) + { debug() << "Collection " << _inTrackColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; } + + const edm4hep::MCRecoTrackerAssociationCollection* vtxHitAssCols = nullptr; + try { vtxHitAssCols = _inVTXAssColHdl.get(); } + catch ( GaudiException &e ) + { debug() << "Collection " << _inVTXAssColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; } + + std::map<int, int> hitNumbers; + + hitNumbers[UTIL::ILDDetID::VXD] = 0; + hitNumbers[UTIL::ILDDetID::SIT] = 0; + hitNumbers[UTIL::ILDDetID::FTD] = 0; + hitNumbers[UTIL::ILDDetID::TPC] = 0; + hitNumbers[UTIL::ILDDetID::SET] = 0; + hitNumbers[UTIL::ILDDetID::ETD] = 0; + + if(trackCols){ + int Track_count = 0; + for(auto track : *trackCols){ + recActsSvc->Clean(); + Track_count++; + unsigned int nHits = track.trackerHits_size(); + + std::vector<int> hit_indices; + std::vector<float> hit_radii; + for(int ielem = 0; ielem < nHits; ++ielem){ + const edm4hep::TrackerHit& hit = track.getTrackerHits(ielem); + float hit_r = std::hypot(hit.getPosition()[0], hit.getPosition()[1]); + hit_indices.push_back(ielem); + hit_radii.push_back(hit_r); + } + + std::sort(hit_indices.begin(), hit_indices.end(), + [&hit_radii](int i1, int i2) { return hit_radii[i1] < hit_radii[i2]; }); + + auto first_hit = track.getTrackerHits(hit_indices[0]); + + std::vector<edm4hep::SimTrackerHit> first_simHits; + for(auto ass : *vtxHitAssCols){ + if(ass.getRec().getObjectID().collectionID != first_hit.getObjectID().collectionID) break; + else if(ass.getRec()==first_hit) first_simHits.push_back(ass.getSim()); + } + + if(first_simHits.size() == 0){ + info() << "Skip: Not found VTX simHit in AssociationCollection for track " << Track_count << " at event " << _nEvt << endmsg; + continue; + } + + auto first_simhit = first_simHits[0]; + double px = first_simhit.getMomentum()[0]; + double py = first_simhit.getMomentum()[1]; + double pz = first_simhit.getMomentum()[2]; + + for(int i_hit : hit_indices){ + const edm4hep::TrackerHit& hit = track.getTrackerHits(i_hit); + auto cellid = hit.getCellID(); + UTIL::BitField64 encoder(UTIL::ILDCellID0::encoder_string); + encoder.setValue(cellid); + int subdet = encoder[UTIL::ILDCellID0::subdet]; + ++hitNumbers[subdet]; + + if(subdet==UTIL::ILDDetID::VXD) + { + uint64_t m_layer = vtx_decoder->get(cellid, "layer"); + uint64_t m_module = vtx_decoder->get(cellid, "module"); + + if(m_layer <= 3){ + uint64_t acts_volume = VXD_volume_ids[m_layer]; + uint64_t acts_layer = 2; + uint64_t acts_sensitive = 1; + bool buildSpacePoint = false; + int moduleType = 1; + double onSurfaceTolerance = 1e-4; + + if (!recActsSvc->ReadInput(hit, + acts_volume, acts_layer, acts_sensitive, + buildSpacePoint, moduleType, onSurfaceTolerance)) + { + info() << "Failed to read VXD hit: layer " << m_layer << ", module " << m_module << endmsg; + } + } else { + uint64_t acts_volume = VXD_volume_ids[4]; + uint64_t acts_layer = 2; + uint64_t acts_sensitive = (m_layer == 5) ? m_module*2 + 1 : m_module*2 + 2;; + + if (!recActsSvc->ReadInput(hit, + acts_volume, acts_layer, acts_sensitive)) + { + info() << "Failed to read VXD hit: layer " << m_layer << ", module " << m_module << endmsg; + } + } + } + else if(subdet==UTIL::ILDDetID::SIT) + { + uint64_t m_layer = ITKBarrel_decoder->get(cellid, "layer"); + uint64_t m_stave = ITKBarrel_decoder->get(cellid, "stave"); + + uint64_t acts_volume = ITKBarrel_volume_ids[m_layer]; + uint64_t acts_layer = 2; + uint64_t acts_sensitive = m_stave + 1; + if (!recActsSvc->ReadInput(hit, + acts_volume, acts_layer, acts_sensitive)) + { + info() << "Failed to read ITKBarrel hit: layer " << m_layer << ", stave " << m_stave << endmsg; + } + } + else if(subdet==UTIL::ILDDetID::FTD) + { + int m_side = ITKEndcap_decoder->get(cellid, "side"); + uint64_t m_layer = ITKEndcap_decoder->get(cellid, "layer"); + uint64_t m_module = ITKEndcap_decoder->get(cellid, "module"); + + uint64_t acts_volume = (m_side == 1) ? ITKEndcap_positive_volume_ids[m_layer] : ITKEndcap_negative_volume_ids[m_layer]; + uint64_t acts_layer = 2; + uint64_t acts_sensitive = m_module + 1; + if (!recActsSvc->ReadInput(hit, + acts_volume, acts_layer, acts_sensitive)) + { + info() << "Failed to read ITKEndcap hit: side " << m_side << ", layer " << m_layer << ", module " << m_module << endmsg; + } + } + else if(subdet==UTIL::ILDDetID::TPC) + { + uint64_t m_layer = tpc_decoder->get(cellid, "layer"); + + uint64_t acts_volume = TPC_volume_id; + uint64_t acts_layer = (m_layer + 1) * 2; + uint64_t acts_sensitive = 1; + bool buildSpacePoint = false; + int moduleType = 2; + double onSurfaceTolerance = 1e-4; + + if (!recActsSvc->ReadInput(hit, + acts_volume, acts_layer, acts_sensitive, + buildSpacePoint, moduleType, onSurfaceTolerance)) + { + info() << "Failed to read TPC hit: layer " << m_layer << endmsg; + } + } + else if(subdet==UTIL::ILDDetID::SET) + { + uint64_t m_module = OTKBarrel_decoder->get(cellid, "module"); + + uint64_t acts_volume = OTK_volume_id; + uint64_t acts_layer = 2; + uint64_t acts_sensitive = m_module + 1; + if (!recActsSvc->ReadInput(hit, + acts_volume, acts_layer, acts_sensitive)) + { + info() << "Failed to read OTKBarrel hit: module " << m_module << endmsg; + } + } + else + { + debug() << "not supported subdetector: " << subdet << endmsg; + } + } + + double p = sqrt(px*px + py*py + pz*pz); + double phi = atan2(py, px); + double theta = atan2(sqrt(px*px + py*py), pz); + double qop = -1 / p; + + Acts::BoundVector params = Acts::BoundVector::Zero(); + Acts::BoundSquareMatrix cov = Acts::BoundSquareMatrix::Zero(); + ActsHelper::IndexSourceLink::SurfaceAccessor surfaceAccessor{*recActsSvc->Geometry()}; + + // (TODO) assume the first hit is the first measurement + auto first_hit_meas = recActsSvc->Measurements()->at(0); + auto cur_meas_param = std::get<1>(first_hit_meas).parameters(); + auto cur_meas_sl = std::get<1>(first_hit_meas).sourceLink(); + const Acts::Surface* surface = surfaceAccessor(cur_meas_sl); + + params[Acts::eBoundLoc0] = cur_meas_param[Acts::eBoundLoc0]; + params[Acts::eBoundLoc1] = cur_meas_param[Acts::eBoundLoc1]; + params[Acts::eBoundPhi] = phi; + params[Acts::eBoundTheta] = theta; + params[Acts::eBoundQOverP] = qop; + params[Acts::eBoundTime] = 0; + + for (std::size_t i = Acts::eBoundLoc0; i < Acts::eBoundSize; ++i) { + double sigma = initialSigmas[i]; + sigma += abs(initialSimgaQoverPCoefficients[i] * params[Acts::eBoundQOverP]); + double var = sigma * sigma; + // var *= noTimeVarInflation.value(); + var *= initialVarInflation.value()[i]; + + cov(i, i) = var; + } + + recActsSvc->InitialParameters()->emplace_back(surface->getSharedPtr(), params, cov, particleHypothesis); + + auto measurements = recActsSvc->Measurements(); + auto trackSourceLinks = recActsSvc->SourceLinks(); + auto initialParams = recActsSvc->InitialParameters(); + + // info() << "debug: event " << _nEvt << ", track " << Track_count << endmsg; + // info() << "measurements size: " << measurements->size() << endmsg; + // info() << "trackSourceLinks size: " << trackSourceLinks->size() << endmsg; + // info() << "initialParams size: " << initialParams->size() << endmsg; + + if (initialParams->size() == 0) { + info() << "No initial parameters found for track " << Track_count << " at event " << _nEvt << endmsg; + continue; + } + + auto pSurface = Acts::Surface::makeShared<Acts::PerigeeSurface>(Acts::Vector3{0., 0., 0.}); + ActsHelper::PassThroughCalibrator pcalibrator; + ActsHelper::MeasurementCalibratorAdapter calibrator(pcalibrator, *measurements); + ActsHelper::TrackFitterFunction::GeneralFitterOptions options{ + geoContext, magFieldContext, calibContext, pSurface.get(), Acts::PropagatorPlainOptions()}; + + auto trackContainer = std::make_shared<Acts::VectorTrackContainer>(); + auto trackStateContainer = std::make_shared<Acts::VectorMultiTrajectory>(); + ActsHelper::TrackContainer tracks(trackContainer, trackStateContainer); + + std::vector<Acts::SourceLink> cur_trackSourceLinks; + for (const auto& sourceLink : *trackSourceLinks) { + cur_trackSourceLinks.push_back(Acts::SourceLink{sourceLink}); + } + + auto result = (*fit)(cur_trackSourceLinks, initialParams->at(0), options, calibrator, tracks); + if (!result.ok()) { + info() << "Track fit failed for track " << Track_count << " at event " << _nEvt << endmsg; + continue; + } + + // std::stringstream ss; + // trackStateContainer->statistics().toStream(ss); + // debug() << ss.str() << endmsg; + + ActsHelper::ConstTrackContainer constTracks + { + std::make_shared<Acts::ConstVectorTrackContainer>(std::move(*trackContainer)), + std::make_shared<Acts::ConstVectorMultiTrajectory>(std::move(*trackStateContainer)) + }; + + if (constTracks.size() == 0) { + info() << "No tracks fitted for track " << Track_count << " at event " << _nEvt << endmsg; + continue; + } else if (constTracks.size() > 1) { + info() << "Number of tracks fitted: " << constTracks.size() << " for track " << Track_count << " at event " << _nEvt << endmsg; + } + + for (const auto& cur_track : constTracks) + { + auto writeout_track = trkCol->create(); + + writeout_track.setChi2(cur_track.chi2()); + writeout_track.setNdf(cur_track.nDoF()); + writeout_track.setDEdx(cur_track.absoluteMomentum() / Acts::UnitConstants::GeV); + writeout_track.setDEdxError(0); + + // TODO: covmatrix need to be converted + std::array<float, 21> writeout_covMatrix; + auto cur_track_covariance = cur_track.covariance(); + for (int i = 0; i < 6; i++) { + for (int j = 0; j < 6-i; j++) { + writeout_covMatrix[int((13-i)*i/2 + j)] = cur_track_covariance(writeout_indices[i], writeout_indices[j]); + } + } + // location: At{Other|IP|FirstHit|LastHit|Calorimeter|Vertex}|LastLocation + // TrackState: location, d0, phi, omega, z0, tanLambda, time, referencePoint, covMatrix + edm4hep::TrackState writeout_trackState{ + 1, // location: AtOther + cur_track.loc0() / Acts::UnitConstants::mm, // d0 + cur_track.phi(), // phi + cur_track.qOverP() * _FCT * m_field / sin(cur_track.theta()) , // omega = qop * sin(theta) * _FCT * bf + cur_track.loc1() / Acts::UnitConstants::mm, // z0 + 1 / tan(cur_track.theta()), // tanLambda = 1 / tan(theta) + cur_track.time(), // time + ::edm4hep::Vector3f(0, 0, 0), // referencePoint + writeout_covMatrix + }; + + debug() << "Found track with momentum " << cur_track.absoluteMomentum() / Acts::UnitConstants::GeV << " GeV!" << endmsg; + writeout_track.addToTrackStates(writeout_trackState); + } + } + } + + return StatusCode::SUCCESS; +} + +StatusCode RecActsTrackReFitting::finalize() +{ + return StatusCode::SUCCESS; +} \ No newline at end of file diff --git a/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTrackReFitting.h b/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTrackReFitting.h new file mode 100644 index 00000000..97f091c5 --- /dev/null +++ b/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTrackReFitting.h @@ -0,0 +1,153 @@ +#ifndef RecActsTrackReFitting_H +#define RecActsTrackReFitting_H + +// gaudi framework +#include "k4FWCore/DataHandle.h" +#include "GaudiAlg/GaudiAlgorithm.h" + +#include "UTIL/ILDConf.h" +#include "DataHelper/Navigation.h" + +// services +#include "RecActsSvc/IRecActsSvc.h" +#include "DetInterface/IGeomSvc.h" + +// DD4hep +#include "DD4hep/Detector.h" +#include "DDRec/ISurface.h" +#include "DDRec/SurfaceManager.h" + +// edm4hep +#include "edm4hep/MCParticle.h" +#include "edm4hep/MCParticleCollection.h" +#include "edm4hep/TrackerHitCollection.h" +#include "edm4hep/SimTrackerHitCollection.h" +#include "edm4hep/EventHeaderCollection.h" + +#include "edm4hep/Track.h" +#include "edm4hep/MutableTrack.h" +#include "edm4hep/TrackState.h" +#include "edm4hep/TrackCollection.h" +// Acts +#include "Acts/Definitions/Algebra.hpp" +#include "Acts/EventData/GenericBoundTrackParameters.hpp" +#include "Acts/EventData/SourceLink.hpp" +#include "Acts/EventData/TrackProxy.hpp" +#include "Acts/EventData/VectorMultiTrajectory.hpp" +#include "Acts/EventData/VectorTrackContainer.hpp" +#include "Acts/Propagator/Propagator.hpp" +#include "Acts/Surfaces/PerigeeSurface.hpp" +#include "Acts/Surfaces/Surface.hpp" +#include "Acts/Utilities/Result.hpp" + +#include "Acts/Definitions/Direction.hpp" +#include "Acts/Definitions/TrackParametrization.hpp" +#include "Acts/EventData/MultiTrajectory.hpp" +#include "Acts/EventData/TrackContainer.hpp" +#include "Acts/EventData/TrackStatePropMask.hpp" +#include "Acts/EventData/detail/CorrectedTransformationFreeToBound.hpp" +#include "Acts/Geometry/GeometryIdentifier.hpp" +#include "Acts/Propagator/DirectNavigator.hpp" +#include "Acts/Propagator/EigenStepper.hpp" +#include "Acts/Propagator/Navigator.hpp" +#include "Acts/TrackFitting/GlobalChiSquareFitter.hpp" +#include "Acts/TrackFitting/KalmanFitter.hpp" +#include "Acts/Utilities/Delegate.hpp" +#include "Acts/Utilities/Logger.hpp" + +namespace Acts +{ + class MagneticFieldProvider; + class TrackingGeometry; +} + +class RecActsTrackReFitting : public GaudiAlgorithm +{ + public: + RecActsTrackReFitting(const std::string& name, ISvcLocator* svcLoc); + + StatusCode initialize(); + StatusCode execute(); + StatusCode finalize(); + + private: + // Input collections + DataHandle<edm4hep::TrackCollection> _inTrackColHdl{"CompleteTracks", Gaudi::DataHandle::Reader, this}; + + // associations + DataHandle<edm4hep::MCRecoTrackerAssociationCollection> _inVTXAssColHdl{"VXDTrackerHitAssociation", Gaudi::DataHandle::Reader, this}; + + // Output collections + DataHandle<edm4hep::TrackCollection> _outColHdl{"ACTSRefitTracks", Gaudi::DataHandle::Writer, this}; + + Gaudi::Property<std::string> m_particle{this, "AssumeParticle", "muon"}; + Gaudi::Property<double> m_field{this, "bFieldInZ", 3.0}; // tesla + Gaudi::Property<std::vector<double>> initialVarInflation{this, "initialVarInflation", {1, 1, 1, 1, 1, 1}}; + Gaudi::Property<double> noTimeVarInflation{this, "noTimeVarInflation", 1.}; + + // services + // SmartIF<IGeomSvc> m_geosvc; + SmartIF<IRecActsSvc> recActsSvc; + SmartIF<IChronoStatSvc> chronoStatSvc; + + // Decoders + dd4hep::DDSegmentation::BitFieldCoder *vtx_decoder; + dd4hep::DDSegmentation::BitFieldCoder *ITKBarrel_decoder; + dd4hep::DDSegmentation::BitFieldCoder *ITKEndcap_decoder; + dd4hep::DDSegmentation::BitFieldCoder *tpc_decoder; + dd4hep::DDSegmentation::BitFieldCoder *OTKBarrel_decoder; + + std::shared_ptr<ActsHelper::TrackFitterFunction> fit; + std::shared_ptr<const Acts::MagneticFieldProvider> magneticField; + // std::shared_ptr<ActsHelper::MeasurementCalibrator> m_calibrator; + + // globalChiSquareFitter config + bool multipleScattering = false; + bool energyLoss = false; + Acts::FreeToBoundCorrection freeToBoundCorrection; + std::size_t nUpdateMax = 5; + double relChi2changeCutOff = 1e-7; + + // context + Acts::GeometryContext geoContext; + Acts::MagneticFieldContext magFieldContext; + Acts::CalibrationContext calibContext; + + // double noTimeVarInflation = 10.; + std::array<double, 6> initialSigmas = { + 5 * Acts::UnitConstants::um, + 5 * Acts::UnitConstants::um, + 2e-2 * Acts::UnitConstants::degree, + 2e-2 * Acts::UnitConstants::degree, + 1e-1 * Acts::UnitConstants::e / Acts::UnitConstants::GeV, + 1 * Acts::UnitConstants::s + }; + std::array<double, 6> initialSimgaQoverPCoefficients = { + 0 * Acts::UnitConstants::mm / (Acts::UnitConstants::e * Acts::UnitConstants::GeV), + 0 * Acts::UnitConstants::mm / (Acts::UnitConstants::e * Acts::UnitConstants::GeV), + 0 * Acts::UnitConstants::degree / (Acts::UnitConstants::e * Acts::UnitConstants::GeV), + 0 * Acts::UnitConstants::degree / (Acts::UnitConstants::e * Acts::UnitConstants::GeV), + 1e-1, + 0 * Acts::UnitConstants::ns / (Acts::UnitConstants::e * Acts::UnitConstants::GeV) + }; + + std::array<std::string, 8> particleNames = {"muon", "pion", "electron", "kaon", "proton", "photon", "geantino", "chargedgeantino"}; + + // constants + const double _FCT = 2.99792458E-4; + uint64_t TPC_volume_id = 43; + uint64_t OTK_volume_id = 45; + std::vector<uint64_t> VXD_volume_ids{26, 27, 28, 29, 30}; + std::vector<uint64_t> ITKBarrel_volume_ids{33, 36, 39}; + std::vector<uint64_t> ITKEndcap_positive_volume_ids{34, 37, 40, 41}; + std::vector<uint64_t> ITKEndcap_negative_volume_ids{32, 15, 10, 8}; + std::vector<uint64_t> ITKBarrel_module_nums{7, 10, 14}; + const std::array<Acts::BoundIndices, 6> writeout_indices{ + Acts::BoundIndices::eBoundLoc0, Acts::BoundIndices::eBoundPhi, + Acts::BoundIndices::eBoundQOverP, Acts::BoundIndices::eBoundLoc1, + Acts::BoundIndices::eBoundTheta, Acts::BoundIndices::eBoundTime}; + Acts::ParticleHypothesis particleHypothesis = Acts::ParticleHypothesis::muon(); + int _nEvt; +}; + +#endif // RecActsTrackReFitting_H \ No newline at end of file diff --git a/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTruthInput.cpp b/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTruthInput.cpp new file mode 100644 index 00000000..1418bc48 --- /dev/null +++ b/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTruthInput.cpp @@ -0,0 +1,473 @@ +// dependence +#include "RecActsTruthInput.h" + +DECLARE_COMPONENT(RecActsTruthInput) + +RecActsTruthInput::RecActsTruthInput(const std::string& name, ISvcLocator* svcLoc) + : GaudiAlgorithm(name, svcLoc) +{ +} + +StatusCode RecActsTruthInput::initialize() +{ + // -------------------------------- + // ---- initialize properties ----- + // -------------------------------- + + vtx_decoder = new dd4hep::DDSegmentation::BitFieldCoder("system:5,side:-2,layer:9,module:8,sensor:32:16"); + if(!vtx_decoder){ + info() << "Failed to create vtx_decoder" << endmsg; + return StatusCode::FAILURE; + } + + ITKBarrel_decoder = new dd4hep::DDSegmentation::BitFieldCoder("system:5,side:-2,layer:9,stave:8,module:8,sensor:5"); + if(!ITKBarrel_decoder){ + info() << "Failed to create ITKBarrel_decoder" << endmsg; + return StatusCode::FAILURE; + } + + ITKEndcap_decoder = new dd4hep::DDSegmentation::BitFieldCoder("system:5,side:-2,layer:9,module:8,sensor:8"); + if(!ITKEndcap_decoder){ + info() << "Failed to create ITKEndcap_decoder" << endmsg; + return StatusCode::FAILURE; + } + + tpc_decoder = new dd4hep::DDSegmentation::BitFieldCoder("system:5,side:-2,layer:13,module:6,sensor:6"); + if(!tpc_decoder){ + info() << "Failed to create TPC_decoder" << endmsg; + return StatusCode::FAILURE; + } + + OTKBarrel_decoder = new dd4hep::DDSegmentation::BitFieldCoder("system:5,side:-2,layer:9,module:8,iladder:32:4,oladder:-4,mmodule:-6"); + if(!OTKBarrel_decoder){ + info() << "Failed to create OTKBarrel_decoder" << endmsg; + return StatusCode::FAILURE; + } + + // -------------------------------- + // ---- initialize recActsSvc ---- + // -------------------------------- + + recActsSvc = service<IRecActsSvc>("RecActsSvc"); + if (!recActsSvc) { + error() << "Failed to get RecActsSvc" << endmsg; + return StatusCode::FAILURE; + } + + _nEvt = -1; + return StatusCode::SUCCESS; +} + +StatusCode RecActsTruthInput::execute() +{ + _nEvt++; + + recActsSvc->Clean(); + + if (useVTX.value()) { + if (!ReadInputVTX()) { + debug() << "VTX input failed at event " << _nEvt << endmsg; + } + } + + if (useITKBarrel.value()) { + if (!ReadInputITKBarrel()) { + debug() << "ITKBarrel input failed at event " << _nEvt << endmsg; + } + } + + if (useITKEndcap.value()) { + if (!ReadInputITKEndcap()) { + debug() << "ITKEndcap input failed at event " << _nEvt << endmsg; + } + } + + if (useTPC.value()) { + if (!ReadInputTPC()) { + debug() << "TPC input failed at event " << _nEvt << endmsg; + } + } + + if (useOTKBarrel.value()) { + if (!ReadInputOTKBarrel()) { + debug() << "OTKBarrel input failed at event " << _nEvt << endmsg; + } + } + + return StatusCode::SUCCESS; +} + +StatusCode RecActsTruthInput::finalize() +{ + return StatusCode::SUCCESS; +} + +bool RecActsTruthInput::ReadInputVTX() +{ + const edm4hep::TrackerHitCollection* hitVTXCol = nullptr; + const edm4hep::SimTrackerHitCollection* SimhitVTXCol = nullptr; + const edm4hep::MCRecoTrackerAssociationCollection* vtxAssCol = nullptr; + + try { + hitVTXCol = _inVTXTrackHdl.get(); + } catch (GaudiException& e) { + fatal() << "Collection " << _inVTXTrackHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; + return false; + } + + try { + SimhitVTXCol = _inVTXColHdl.get(); + } catch (GaudiException& e) { + fatal() << "Sim Collection " << _inVTXColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; + return false; + } + + try { + vtxAssCol = _inVTXAssColHdl.get(); + } catch (GaudiException& e) { + fatal() << "Association Collection " << _inVTXAssColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; + return false; + } + + if(hitVTXCol && SimhitVTXCol) + { + int nelem = hitVTXCol->size(); + + for(int ielem = 0; ielem < nelem; ++ielem){ + auto hit = hitVTXCol->at(ielem); + + std::vector<edm4hep::SimTrackerHit> simHits; + for(auto ass : *vtxAssCol){ + if(ass.getRec().getObjectID().collectionID != hit.getObjectID().collectionID) break; + else if(ass.getRec()==hit) simHits.push_back(ass.getSim()); + } + + if(simHits.size() == 0){ + info() << "Skip: Not found VTX simHit in AssociationCollection at event " << _nEvt << endmsg; + continue; + } + + auto simhit = simHits[0]; + + if (simhit.isProducedBySecondary()) { + continue; + } + + auto cellid = hit.getCellID(); + uint64_t m_layer = vtx_decoder->get(cellid, "layer"); + uint64_t m_module = vtx_decoder->get(cellid, "module"); + uint64_t m_sensor = vtx_decoder->get(cellid, "sensor"); + + if(m_layer <= 3){ + uint64_t acts_volume = VXD_volume_ids[m_layer]; + uint64_t acts_layer = 2; + uint64_t acts_sensitive = 1; + bool buildSpacePoint = true; + int moduleType = 1; + double onSurfaceTolerance = 1e-4; + + if (!recActsSvc->ReadInput(hit, + acts_volume, acts_layer, acts_sensitive, + buildSpacePoint, moduleType, onSurfaceTolerance)) + { return false; } + } else { + uint64_t acts_volume = VXD_volume_ids[4]; + uint64_t acts_layer = 2; + uint64_t acts_sensitive = (m_layer == 5) ? m_module*2 + 1 : m_module*2 + 2; + bool buildSpacePoint = true; + int moduleType = 0; + double onSurfaceTolerance = 1e-4; + + if (!recActsSvc->ReadInput(hit, + acts_volume, acts_layer, acts_sensitive, + buildSpacePoint, moduleType, onSurfaceTolerance)) + { return false; } + } + } + } + + return true; +} + +bool RecActsTruthInput::ReadInputITKBarrel() +{ + const edm4hep::TrackerHitCollection* hitITKBarrelCol = nullptr; + const edm4hep::SimTrackerHitCollection* SimhitITKBarrelCol = nullptr; + const edm4hep::MCRecoTrackerAssociationCollection* itkBarrelAssCol = nullptr; + + try { + hitITKBarrelCol = _inITKBarrelTrackHdl.get(); + } catch (GaudiException& e) { + fatal() << "Collection " << _inITKBarrelTrackHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; + return false; + } + + try { + SimhitITKBarrelCol = _inITKBarrelColHdl.get(); + } catch (GaudiException& e) { + fatal() << "Sim Collection " << _inITKBarrelColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; + return false; + } + + try { + itkBarrelAssCol = _inITKBarrelAssColHdl.get(); + } catch (GaudiException& e) { + fatal() << "Association Collection " << _inITKBarrelAssColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; + return false; + } + + if(hitITKBarrelCol) + { + int nelem = hitITKBarrelCol->size(); + + for (int ielem = 0; ielem < nelem; ++ielem) + { + auto hit = hitITKBarrelCol->at(ielem); + + std::vector<edm4hep::SimTrackerHit> simHits; + for(auto ass : *itkBarrelAssCol){ + if(ass.getRec().getObjectID().collectionID != hit.getObjectID().collectionID) break; + else if(ass.getRec()==hit) simHits.push_back(ass.getSim()); + } + + if(simHits.size() == 0){ + info() << "Skip: Not found ITKBarrel simHit in AssociationCollection at event " << _nEvt << endmsg; + continue; + } + + auto simhit = simHits[0]; + + if (simhit.isProducedBySecondary()) { + continue; + } + + auto cellid = hit.getCellID(); + uint64_t m_layer = ITKBarrel_decoder->get(cellid, "layer"); + uint64_t m_stave = ITKBarrel_decoder->get(cellid, "stave"); + + uint64_t acts_volume = ITKBarrel_volume_ids[m_layer]; + uint64_t acts_layer = 2; + uint64_t acts_sensitive = m_stave + 1; + bool buildSpacePoint = true; + int moduleType = 0; + double onSurfaceTolerance = 1e-4; + + if (!recActsSvc->ReadInput(hit, + acts_volume, acts_layer, acts_sensitive, + buildSpacePoint, moduleType, onSurfaceTolerance)) + { return false; } + } + } + + return true; +} + +bool RecActsTruthInput::ReadInputITKEndcap() +{ + const edm4hep::TrackerHitCollection* hitITKEndcapCol = nullptr; + const edm4hep::SimTrackerHitCollection* SimhitITKEndcapCol = nullptr; + const edm4hep::MCRecoTrackerAssociationCollection* itkEndcapAssCol = nullptr; + + try { + hitITKEndcapCol = _inITKEndcapTrackHdl.get(); + } catch (GaudiException& e) { + debug() << "Collection " << _inITKEndcapTrackHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; + return false; + } + + try { + SimhitITKEndcapCol = _inITKEndcapColHdl.get(); + } catch (GaudiException& e) { + debug() << "Sim Collection " << _inITKEndcapColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; + return false; + } + + try { + itkEndcapAssCol = _inITKEndcapAssColHdl.get(); + } catch (GaudiException& e) { + fatal() << "Association Collection " << _inITKEndcapAssColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; + return false; + } + + if (hitITKEndcapCol) + { + int nelem = hitITKEndcapCol->size(); + + for (int ielem = 0; ielem < nelem; ++ielem) + { + auto hit = hitITKEndcapCol->at(ielem); + + std::vector<edm4hep::SimTrackerHit> simHits; + for(auto ass : *itkEndcapAssCol){ + if(ass.getRec().getObjectID().collectionID != hit.getObjectID().collectionID) break; + else if(ass.getRec()==hit) simHits.push_back(ass.getSim()); + } + + if(simHits.size() == 0){ + info() << "Skip: Not found ITKEndcap simHit in AssociationCollection at event " << _nEvt << endmsg; + continue; + } + + auto simhit = simHits[0]; + + if (simhit.isProducedBySecondary()) { + continue; + } + + auto cellid = hit.getCellID(); + int m_side = ITKEndcap_decoder->get(cellid, "side"); + uint64_t m_layer = ITKEndcap_decoder->get(cellid, "layer"); + uint64_t m_module = ITKEndcap_decoder->get(cellid, "module"); + + uint64_t acts_volume = (m_side == 1) ? ITKEndcap_positive_volume_ids[m_layer] : ITKEndcap_negative_volume_ids[m_layer]; + uint64_t acts_layer = 2; + uint64_t acts_sensitive = m_module + 1; + + if (!recActsSvc->ReadInput(hit, + acts_volume, acts_layer, acts_sensitive)) + { return false; } + } + } + + return true; +} + + +bool RecActsTruthInput::ReadInputTPC() +{ + const edm4hep::TrackerHitCollection* hitTPCCol = nullptr; + const edm4hep::SimTrackerHitCollection* SimhitTPCCol = nullptr; + const edm4hep::MCRecoTrackerAssociationCollection* tpcAssCol = nullptr; + + try { + hitTPCCol = _inTPCTrackHdl.get(); + } catch (GaudiException& e) { + debug() << "Collection " << _inTPCTrackHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; + return false; + } + + try { + SimhitTPCCol = _inTPCColHdl.get(); + } catch (GaudiException& e) { + debug() << "Sim Collection " << _inTPCColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; + return false; + } + + try { + tpcAssCol = _inTPCAssColHdl.get(); + } catch (GaudiException& e) { + fatal() << "Association Collection " << _inTPCAssColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; + return false; + } + + if(hitTPCCol) + { + int nelem = hitTPCCol->size(); + + for (int ielem = 0; ielem < nelem; ++ielem) + { + auto hit = hitTPCCol->at(ielem); + + std::vector<edm4hep::SimTrackerHit> simHits; + for(auto ass : *tpcAssCol){ + if(ass.getRec().getObjectID().collectionID != hit.getObjectID().collectionID) break; + else if(ass.getRec()==hit) simHits.push_back(ass.getSim()); + } + + if(simHits.size() == 0){ + info() << "Skip: Not found TPC simHit in AssociationCollection at event " << _nEvt << endmsg; + continue; + } + + auto simhit = simHits[0]; + + if (simhit.isProducedBySecondary()) { + continue; + } + + auto cellid = hit.getCellID(); + uint64_t m_layer = tpc_decoder->get(cellid, "layer"); + + uint64_t acts_volume = TPC_volume_id; + uint64_t acts_layer = (m_layer + 1) * 2; + uint64_t acts_sensitive = 1; + bool buildSpacePoint = false; + int moduleType = 2; + double onSurfaceTolerance = 1e-4; + + if (!recActsSvc->ReadInput(hit, + acts_volume, acts_layer, acts_sensitive, + buildSpacePoint, moduleType, onSurfaceTolerance)) + { return false; } + } + } + + return true; +} + +bool RecActsTruthInput::ReadInputOTKBarrel() +{ + const edm4hep::TrackerHitCollection* hitOTKBarrelCol = nullptr; + const edm4hep::SimTrackerHitCollection* SimhitOTKBarrelCol = nullptr; + const edm4hep::MCRecoTrackerAssociationCollection* otkBarrelAssCol = nullptr; + + try { + hitOTKBarrelCol = _inOTKBarrelTrackHdl.get(); + } catch (GaudiException& e) { + debug() << "Collection " << _inOTKBarrelTrackHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; + return false; + } + + try { + SimhitOTKBarrelCol = _inOTKBarrelColHdl.get(); + } catch (GaudiException& e) { + debug() << "Sim Collection " << _inOTKBarrelColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; + return false; + } + + try { + otkBarrelAssCol = _inOTKBarrelAssColHdl.get(); + } catch (GaudiException& e) { + fatal() << "Association Collection " << _inOTKBarrelAssColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; + return false; + } + + if(hitOTKBarrelCol) + { + int nelem = hitOTKBarrelCol->size(); + + for (int ielem = 0; ielem < nelem; ++ielem) + { + auto hit = hitOTKBarrelCol->at(ielem); + + std::vector<edm4hep::SimTrackerHit> simHits; + for(auto ass : *otkBarrelAssCol){ + if(ass.getRec().getObjectID().collectionID != hit.getObjectID().collectionID) break; + else if(ass.getRec()==hit) simHits.push_back(ass.getSim()); + } + + if(simHits.size() == 0){ + info() << "Skip: Not found OTKBarrel simHit in AssociationCollection at event " << _nEvt << endmsg; + continue; + } + + auto simhit = simHits[0]; + + if (simhit.isProducedBySecondary()) { + continue; + } + + auto cellid = hit.getCellID(); + uint64_t m_module = OTKBarrel_decoder->get(cellid, "module"); + + uint64_t acts_volume = OTK_volume_id; + uint64_t acts_layer = 2; + uint64_t acts_sensitive = m_module + 1; + + if (!recActsSvc->ReadInput(hit, + acts_volume, acts_layer, acts_sensitive)) + { return false; } + } + } + return true; +} \ No newline at end of file diff --git a/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTruthInput.h b/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTruthInput.h new file mode 100644 index 00000000..bd390199 --- /dev/null +++ b/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTruthInput.h @@ -0,0 +1,100 @@ +#ifndef RecActsTruthInput_H +#define RecActsTruthInput_H + +// gaudi framework +#include "k4FWCore/DataHandle.h" +#include "GaudiAlg/GaudiAlgorithm.h" + +// services +#include "RecActsSvc/IRecActsSvc.h" +// #include "DetInterface/IGeomSvc.h" + +// DD4hep +#include "DD4hep/Detector.h" +#include "DDRec/ISurface.h" +#include "DDRec/SurfaceManager.h" + +#include "UTIL/ILDConf.h" +#include "DataHelper/Navigation.h" + +// edm4hep +#include "edm4hep/MCParticle.h" +#include "edm4hep/MCParticleCollection.h" +#include "edm4hep/TrackerHitCollection.h" +#include "edm4hep/SimTrackerHitCollection.h" +#include "edm4hep/EventHeaderCollection.h" + +#include "edm4hep/Track.h" +#include "edm4hep/MutableTrack.h" +#include "edm4hep/TrackState.h" +#include "edm4hep/TrackCollection.h" + + +class RecActsTruthInput : public GaudiAlgorithm +{ + public: + RecActsTruthInput(const std::string& name, ISvcLocator* svcLoc); + + StatusCode initialize(); + StatusCode execute(); + StatusCode finalize(); + + private: + // Input collections + DataHandle<edm4hep::TrackerHitCollection> _inVTXTrackHdl{"VXDTrackerHits", Gaudi::DataHandle::Reader, this}; + DataHandle<edm4hep::TrackerHitCollection> _inITKBarrelTrackHdl{"ITKBarrelTrackerHits", Gaudi::DataHandle::Reader, this}; + DataHandle<edm4hep::TrackerHitCollection> _inITKEndcapTrackHdl{"ITKEndcapTrackerHits", Gaudi::DataHandle::Reader, this}; + DataHandle<edm4hep::TrackerHitCollection> _inOTKBarrelTrackHdl{"OTKBarrelTrackerHits", Gaudi::DataHandle::Reader, this}; + DataHandle<edm4hep::TrackerHitCollection> _inTPCTrackHdl{"TPCTrackerHits", Gaudi::DataHandle::Reader, this}; + + DataHandle<edm4hep::SimTrackerHitCollection> _inVTXColHdl{"VXDCollection", Gaudi::DataHandle::Reader, this}; + DataHandle<edm4hep::SimTrackerHitCollection> _inITKBarrelColHdl{"ITKBarrelCollection", Gaudi::DataHandle::Reader, this}; + DataHandle<edm4hep::SimTrackerHitCollection> _inITKEndcapColHdl{"ITKEndcapCollection", Gaudi::DataHandle::Reader, this}; + DataHandle<edm4hep::SimTrackerHitCollection> _inOTKBarrelColHdl{"OTKBarrelCollection", Gaudi::DataHandle::Reader, this}; + DataHandle<edm4hep::SimTrackerHitCollection> _inTPCColHdl{"TPCCollection", Gaudi::DataHandle::Reader, this}; + + // associations + DataHandle<edm4hep::MCRecoTrackerAssociationCollection> _inVTXAssColHdl{"VXDTrackerHitAssociation", Gaudi::DataHandle::Reader, this}; + DataHandle<edm4hep::MCRecoTrackerAssociationCollection> _inITKBarrelAssColHdl{"ITKBarrelTrackerHitAssociation", Gaudi::DataHandle::Reader, this}; + DataHandle<edm4hep::MCRecoTrackerAssociationCollection> _inITKEndcapAssColHdl{"ITKEndcapTrackerHitAssociation", Gaudi::DataHandle::Reader, this}; + DataHandle<edm4hep::MCRecoTrackerAssociationCollection> _inOTKBarrelAssColHdl{"OTKBarrelTrackerHitAssociation", Gaudi::DataHandle::Reader, this}; + DataHandle<edm4hep::MCRecoTrackerAssociationCollection> _inTPCAssColHdl{"TPCTrackerHitAss", Gaudi::DataHandle::Reader, this}; + + // properties + Gaudi::Property<bool> useVTX{this, "useVTX", true}; + Gaudi::Property<bool> useITKBarrel{this, "useITKBarrel", true}; + Gaudi::Property<bool> useITKEndcap{this, "useITKEndcap", true}; + Gaudi::Property<bool> useTPC{this, "useTPC", true}; + Gaudi::Property<bool> useOTKBarrel{this, "useOTKBarrel", true}; + + // read input + bool ReadInputVTX(); + bool ReadInputITKBarrel(); + bool ReadInputITKEndcap(); + bool ReadInputTPC(); + bool ReadInputOTKBarrel(); + + // services + // SmartIF<IGeomSvc> m_geosvc; + SmartIF<IRecActsSvc> recActsSvc; + SmartIF<IChronoStatSvc> chronoStatSvc; + + dd4hep::DDSegmentation::BitFieldCoder *vtx_decoder; + dd4hep::DDSegmentation::BitFieldCoder *ITKBarrel_decoder; + dd4hep::DDSegmentation::BitFieldCoder *ITKEndcap_decoder; + dd4hep::DDSegmentation::BitFieldCoder *tpc_decoder; + dd4hep::DDSegmentation::BitFieldCoder *OTKBarrel_decoder; + + // constants + int _nEvt; + uint64_t TPC_volume_id = 43; + uint64_t OTK_volume_id = 45; + std::vector<uint64_t> VXD_volume_ids{26, 27, 28, 29, 30}; + std::vector<uint64_t> ITKBarrel_volume_ids{33, 36, 39}; + std::vector<uint64_t> ITKEndcap_positive_volume_ids{34, 37, 40, 41}; + std::vector<uint64_t> ITKEndcap_negative_volume_ids{32, 15, 10, 8}; + std::vector<uint64_t> ITKBarrel_module_nums{7, 10, 14}; + +}; + +#endif // RecActsTruthInput_H \ No newline at end of file diff --git a/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTruthTracking.cpp b/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTruthTracking.cpp new file mode 100644 index 00000000..8a58b67c --- /dev/null +++ b/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTruthTracking.cpp @@ -0,0 +1,796 @@ +// dependence +#include "RecActsTruthTracking.h" + +DECLARE_COMPONENT(RecActsTruthTracking) + +RecActsTruthTracking::RecActsTruthTracking(const std::string& name, ISvcLocator* svcLoc) + : GaudiAlgorithm(name, svcLoc) +{ +} + +StatusCode RecActsTruthTracking::initialize() +{ + // -------------------------------- + // ---- initialize properties ----- + // -------------------------------- + + info() << "Assume Particle: " << m_particle.value() << endmsg; + if(m_particle.value() == "muon"){ + particleHypothesis = Acts::ParticleHypothesis::muon(); + } + else if(m_particle.value() == "pion"){ + particleHypothesis = Acts::ParticleHypothesis::pion(); + } + else if(m_particle.value() == "electron"){ + particleHypothesis = Acts::ParticleHypothesis::electron(); + } + else if(m_particle.value() == "kaon"){ + particleHypothesis = Acts::ParticleHypothesis::kaon(); + } + else if(m_particle.value() == "proton"){ + particleHypothesis = Acts::ParticleHypothesis::proton(); + } + else if(m_particle.value() == "photon"){ + particleHypothesis = Acts::ParticleHypothesis::photon(); + } + else if(m_particle.value() == "geantino"){ + particleHypothesis = Acts::ParticleHypothesis::geantino(); + } + else if(m_particle.value() == "chargedgeantino"){ + particleHypothesis = Acts::ParticleHypothesis::chargedGeantino(); + } + else{ + info() << "Supported Assumed Particle: " << particleNames[0] << ", " << particleNames[1] << ", " << particleNames[2] << ", " + << particleNames[3] << ", " << particleNames[4] << ", " << particleNames[5] << ", " + << particleNames[6] << ", " << particleNames[7] << endmsg; + error() << "Unsupported particle name " << m_particle.value() << endmsg; + return StatusCode::FAILURE; + } + + // m_geosvc = service<IGeomSvc>("GeomSvc"); + // if (!m_geosvc) { + // error() << "Failed to get GeomSvc" << endmsg; + // return StatusCode::FAILURE; + // } + + // m_vtx_surfaces = m_geosvc->getSurfaceMap("VXD"); + // debug() << "VXD Surface map size: " << m_vtx_surfaces->size() << endmsg; + + // m_ITKBarrel_surfaces = m_geosvc->getSurfaceMap("ITKBarrel"); + // debug() << "ITKBarrel Surface map size: " << m_ITKBarrel_surfaces->size() << endmsg; + + // m_ITKEndcap_surfaces = m_geosvc->getSurfaceMap("ITKEndcap"); + // debug() << "ITKEndcap Surface map size: " << m_ITKEndcap_surfaces->size() << endmsg; + + // m_tpc_surfaces = m_geosvc->getSurfaceMap("TPC"); + // debug() << "TPC Surface map size: " << m_tpc_surfaces->size() << endmsg; + + // m_OTKBarrel_surfaces = m_geosvc->getSurfaceMap("OTKBarrel"); + // debug() << "OTK Barrel Surface map size: " << m_OTKBarrel_surfaces->size() << endmsg; + + // vtx_decoder = m_geosvc->getDecoder("VXDCollection"); + // if(!vtx_decoder){ + // return StatusCode::FAILURE; + // } + + // ITKBarrel_decoder = m_geosvc->getDecoder("ITKBarrelCollection"); + // if(!ITKBarrel_decoder){ + // return StatusCode::FAILURE; + // } + + // tpc_decoder = m_geosvc->getDecoder("TPCCollection"); + // if(!tpc_decoder){ + // return StatusCode::FAILURE; + // } + + // ITKEndcap_decoder = m_geosvc->getDecoder("ITKEndcapCollection"); + // if(!ITKEndcap_decoder){ + // return StatusCode::FAILURE; + // } + + // OTKBarrel_decoder = m_geosvc->getDecoder("OTKBarrelCollection"); + // if(!OTKBarrel_decoder){ + // return StatusCode::FAILURE; + // } + + vtx_decoder = new dd4hep::DDSegmentation::BitFieldCoder("system:5,side:-2,layer:9,module:8,sensor:32:16"); + if(!vtx_decoder){ + info() << "Failed to create vtx_decoder" << endmsg; + return StatusCode::FAILURE; + } + + ITKBarrel_decoder = new dd4hep::DDSegmentation::BitFieldCoder("system:5,side:-2,layer:9,stave:8,module:8,sensor:5"); + if(!ITKBarrel_decoder){ + info() << "Failed to create ITKBarrel_decoder" << endmsg; + return StatusCode::FAILURE; + } + + ITKEndcap_decoder = new dd4hep::DDSegmentation::BitFieldCoder("system:5,side:-2,layer:9,module:8,sensor:8"); + if(!ITKEndcap_decoder){ + info() << "Failed to create ITKEndcap_decoder" << endmsg; + return StatusCode::FAILURE; + } + + tpc_decoder = new dd4hep::DDSegmentation::BitFieldCoder("system:5,side:-2,layer:13,module:6,sensor:6"); + if(!tpc_decoder){ + info() << "Failed to create TPC_decoder" << endmsg; + return StatusCode::FAILURE; + } + + OTKBarrel_decoder = new dd4hep::DDSegmentation::BitFieldCoder("system:5,side:-2,layer:9,module:8,iladder:32:4,oladder:-4,mmodule:-6"); + if(!OTKBarrel_decoder){ + info() << "Failed to create OTKBarrel_decoder" << endmsg; + return StatusCode::FAILURE; + } + + recActsSvc = service<IRecActsSvc>("RecActsSvc"); + if (!recActsSvc) { + error() << "Failed to get RecActsSvc" << endmsg; + return StatusCode::FAILURE; + } + + // -------------------------------- + // ---- initialize recActsSvc ---- + // -------------------------------- + + recActsSvc = service<IRecActsSvc>("RecActsSvc"); + if (!recActsSvc) { + error() << "Failed to get RecActsSvc" << endmsg; + return StatusCode::FAILURE; + } + + chronoStatSvc = service<IChronoStatSvc>("ChronoStatSvc"); + + magneticField = std::make_shared<Acts::ConstantBField>(Acts::Vector3(0., 0., m_field.value()*_FCT)); + fit = ActsHelper::makeKalmanFitterFunction(recActsSvc->Geometry(), magneticField); + // fit = ActsHelper::makeGsfFitterFunction(recActsSvc->Geometry(), magneticField); (not working) + // fit = ActsHelper::makeGlobalChiSquareFitterFunction(recActsSvc->Geometry(), magneticField); (ok) + + _nEvt = -1; + return StatusCode::SUCCESS; +} + +StatusCode RecActsTruthTracking::execute() +{ + _nEvt++; + + chronoStatSvc->chronoStart("Truth Tracking"); + + auto trkCol = _outColHdl.createAndPut(); + + const edm4hep::MCParticleCollection* mcCols = nullptr; + try { mcCols = _inMCColHdl.get(); } + catch ( GaudiException &e ) { + debug() << "Collection " << _inMCColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; + } + + if(mcCols){ + for(const auto& mc : *mcCols){ + if (mc.getGeneratorStatus() != 1){ + info() << "MCParticle " << mc.getPDG() << " is not primary at event " << _nEvt << endmsg; + continue; + } + + recActsSvc->Clean(); + debug() << "Processing MCParticle " << mc.getPDG() << " at event " << _nEvt << endmsg; + + if(!ReadHits(mc)){ + info() << "Fit MCParticle " << mc.getPDG() << " failed at event " << _nEvt << endmsg; + continue; + } + + auto measurements = recActsSvc->Measurements(); + auto trackSourceLinks = recActsSvc->SourceLinks(); + auto initialParams = recActsSvc->InitialParameters(); + + if (initialParams->size() == 0) { + info() << "No initial parameters found for MCParticle " << mc.getPDG() << " at event " << _nEvt << endmsg; + continue; + } + + auto pSurface = Acts::Surface::makeShared<Acts::PerigeeSurface>(Acts::Vector3{0., 0., 0.}); + ActsHelper::PassThroughCalibrator pcalibrator; + ActsHelper::MeasurementCalibratorAdapter calibrator(pcalibrator, *measurements); + ActsHelper::TrackFitterFunction::GeneralFitterOptions options{ + geoContext, magFieldContext, calibContext, pSurface.get(), Acts::PropagatorPlainOptions()}; + + auto trackContainer = std::make_shared<Acts::VectorTrackContainer>(); + auto trackStateContainer = std::make_shared<Acts::VectorMultiTrajectory>(); + ActsHelper::TrackContainer tracks(trackContainer, trackStateContainer); + + std::vector<Acts::SourceLink> cur_trackSourceLinks; + for (const auto& sourceLink : *trackSourceLinks) { + cur_trackSourceLinks.push_back(Acts::SourceLink{sourceLink}); + } + auto result = (*fit)(cur_trackSourceLinks, initialParams->at(0), options, calibrator, tracks); + if (!result.ok()) { + info() << "Track fit failed for MCParticle " << mc.getPDG() << " at event " << _nEvt << endmsg; + continue; + } + + std::stringstream ss; + trackStateContainer->statistics().toStream(ss); + debug() << ss.str() << endmsg; + + ActsHelper::ConstTrackContainer constTracks + { + std::make_shared<Acts::ConstVectorTrackContainer>(std::move(*trackContainer)), + std::make_shared<Acts::ConstVectorMultiTrajectory>(std::move(*trackStateContainer)) + }; + + if (constTracks.size() == 0) { + info() << "No tracks fitted for MCParticle " << mc.getPDG() << " at event " << _nEvt << endmsg; + continue; + } else if (constTracks.size() > 1) { + info() << "Number of tracks fitted: " << constTracks.size() << " for MCParticle " << mc.getPDG() << " at event " << _nEvt << endmsg; + } + + for (const auto& cur_track : constTracks) + { + auto writeout_track = trkCol->create(); + + writeout_track.setChi2(cur_track.chi2()); + writeout_track.setNdf(cur_track.nDoF()); + writeout_track.setDEdx(cur_track.absoluteMomentum() / Acts::UnitConstants::GeV); + writeout_track.setDEdxError(mc.getPDG()); + + // TODO: covmatrix need to be converted + std::array<float, 21> writeout_covMatrix; + auto cur_track_covariance = cur_track.covariance(); + for (int i = 0; i < 6; i++) { + for (int j = 0; j < 6-i; j++) { + writeout_covMatrix[int((13-i)*i/2 + j)] = cur_track_covariance(writeout_indices[i], writeout_indices[j]); + } + } + // location: At{Other|IP|FirstHit|LastHit|Calorimeter|Vertex}|LastLocation + // TrackState: location, d0, phi, omega, z0, tanLambda, time, referencePoint, covMatrix + edm4hep::TrackState writeout_trackState{ + 1, // location: AtOther + cur_track.loc0() / Acts::UnitConstants::mm, // d0 + cur_track.phi(), // phi + cur_track.qOverP() * _FCT * m_field.value() / sin(cur_track.theta()) , // omega = qop * sin(theta) * _FCT * bf + cur_track.loc1() / Acts::UnitConstants::mm, // z0 + 1 / tan(cur_track.theta()), // tanLambda = 1 / tan(theta) + cur_track.time(), // time + ::edm4hep::Vector3f(0, 0, 0), // referencePoint + writeout_covMatrix + }; + + debug() << "Found track with momentum " << cur_track.absoluteMomentum() / Acts::UnitConstants::GeV << " GeV!" << endmsg; + writeout_track.addToTrackStates(writeout_trackState); + } + + if (!useMCTruth.value()) { break; } + } + } + + chronoStatSvc->chronoStop("Truth Tracking"); + + return StatusCode::SUCCESS; +} + +StatusCode RecActsTruthTracking::finalize() +{ + return StatusCode::SUCCESS; +} + +bool RecActsTruthTracking::ReadHits(const edm4hep::MCParticle& mc) +{ + double px = 0; + double py = 0; + double pz = 0; + + if (useVTX.value()) + { + const edm4hep::TrackerHitCollection* hitVTXCol = nullptr; + const edm4hep::SimTrackerHitCollection* SimhitVTXCol = nullptr; + const edm4hep::MCRecoTrackerAssociationCollection* vtxAssCol = nullptr; + + try { + hitVTXCol = _inVTXTrackHdl.get(); + } catch (GaudiException& e) { + fatal() << "Collection " << _inVTXTrackHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; + return false; + } + + try { + SimhitVTXCol = _inVTXColHdl.get(); + } catch (GaudiException& e) { + fatal() << "Sim Collection " << _inVTXColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; + return false; + } + + try { + vtxAssCol = _inVTXAssColHdl.get(); + } catch (GaudiException& e) { + fatal() << "Association Collection " << _inVTXAssColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; + return false; + } + + if(hitVTXCol && SimhitVTXCol) + { + int nelem = hitVTXCol->size(); + debug() << "Number of VTX hits = " << nelem << endmsg; + + std::vector<int> hit_indices; + std::vector<float> hit_radii; + for(int ielem = 0; ielem < nelem; ++ielem){ + auto hit = hitVTXCol->at(ielem); + + std::vector<edm4hep::SimTrackerHit> simHits; + for(auto ass : *vtxAssCol){ + if(ass.getRec().getObjectID().collectionID != hit.getObjectID().collectionID) break; + else if(ass.getRec()==hit) simHits.push_back(ass.getSim()); + } + + if(simHits.size() == 0){ + info() << "Skip: Not found VTX simHit in AssociationCollection at event " << _nEvt << endmsg; + continue; + } + + auto simhit = simHits[0]; + + if (simhit.isProducedBySecondary()) { + continue; + } + + if (useMCTruth.value() && !(simhit.getMCParticle() == mc)) { + continue; + } + + float hit_r = std::hypot(hit.getPosition()[0], hit.getPosition()[1]); + hit_indices.push_back(ielem); + hit_radii.push_back(hit_r); + } + + std::sort(hit_indices.begin(), hit_indices.end(), + [&hit_radii](int i1, int i2) { return hit_radii[i1] < hit_radii[i2]; }); + + for(int i_hit : hit_indices){ + auto hit = hitVTXCol->at(i_hit); + + auto cellid = hit.getCellID(); + uint64_t m_layer = vtx_decoder->get(cellid, "layer"); + uint64_t m_module = vtx_decoder->get(cellid, "module"); + + if(m_layer <= 3){ + uint64_t acts_volume = VXD_volume_ids[m_layer]; + uint64_t acts_layer = 2; + uint64_t acts_sensitive = 1; + bool buildSpacePoint = true; + int moduleType = 1; + double onSurfaceTolerance = 1e-4; + + if (!recActsSvc->ReadInput(hit, + acts_volume, acts_layer, acts_sensitive, + buildSpacePoint, moduleType, onSurfaceTolerance)) + { return false; } + } else { + uint64_t acts_volume = VXD_volume_ids[4]; + uint64_t acts_layer = 2; + uint64_t acts_sensitive = (m_layer == 5) ? m_module*2 + 1 : m_module*2 + 2;; + + if (!recActsSvc->ReadInput(hit, + acts_volume, acts_layer, acts_sensitive)) + { return false; } + } + } + + if (hit_indices.size() == 0) { + info() << "Skip: Not found VTX simHit at event " << _nEvt << endmsg; + return false; + } + + auto first_hit = hitVTXCol->at(hit_indices[0]); + std::vector<edm4hep::SimTrackerHit> simHits; + for(auto ass : *vtxAssCol){ + if(ass.getRec().getObjectID().collectionID != first_hit.getObjectID().collectionID) break; + else if(ass.getRec()==first_hit) simHits.push_back(ass.getSim()); + } + auto simhit = simHits[0]; + px = simhit.getMomentum()[0]; + py = simhit.getMomentum()[1]; + pz = simhit.getMomentum()[2]; + } + } + + if (useITKBarrel.value()) + { + const edm4hep::TrackerHitCollection* hitITKBarrelCol = nullptr; + const edm4hep::SimTrackerHitCollection* SimhitITKBarrelCol = nullptr; + const edm4hep::MCRecoTrackerAssociationCollection* itkBarrelAssCol = nullptr; + + try { + hitITKBarrelCol = _inITKBarrelTrackHdl.get(); + } catch (GaudiException& e) { + fatal() << "Collection " << _inITKBarrelTrackHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; + return false; + } + + try { + SimhitITKBarrelCol = _inITKBarrelColHdl.get(); + } catch (GaudiException& e) { + fatal() << "Sim Collection " << _inITKBarrelColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; + return false; + } + + try { + itkBarrelAssCol = _inITKBarrelAssColHdl.get(); + } catch (GaudiException& e) { + fatal() << "Association Collection " << _inITKBarrelAssColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; + return false; + } + + if(hitITKBarrelCol && SimhitITKBarrelCol) + { + int nelem = hitITKBarrelCol->size(); + debug() << "Number of ITKBarrel hits = " << nelem << endmsg; + + std::vector<int> hit_indices; + std::vector<float> hit_radii; + for(int ielem = 0; ielem < nelem; ++ielem){ + auto hit = hitITKBarrelCol->at(ielem); + + std::vector<edm4hep::SimTrackerHit> simHits; + for(auto ass : *itkBarrelAssCol){ + if(ass.getRec().getObjectID().collectionID != hit.getObjectID().collectionID) break; + else if(ass.getRec()==hit) simHits.push_back(ass.getSim()); + } + + if(simHits.size() == 0){ + info() << "Skip: Not found ITKBarrel simHit in AssociationCollection at event " << _nEvt << endmsg; + continue; + } + + auto simhit = simHits[0]; + + if (simhit.isProducedBySecondary()) { + continue; + } + + if (useMCTruth.value() && !(simhit.getMCParticle() == mc)) { + continue; + } + + float hit_r = std::hypot(hit.getPosition()[0], hit.getPosition()[1]); + hit_indices.push_back(ielem); + hit_radii.push_back(hit_r); + } + + std::sort(hit_indices.begin(), hit_indices.end(), + [&hit_radii](int i1, int i2) { return hit_radii[i1] < hit_radii[i2]; }); + + for (int i_hit : hit_indices) + { + auto hit = hitITKBarrelCol->at(i_hit); + + auto cellid = hit.getCellID(); + uint64_t m_layer = ITKBarrel_decoder->get(cellid, "layer"); + uint64_t m_stave = ITKBarrel_decoder->get(cellid, "stave"); + + uint64_t acts_volume = ITKBarrel_volume_ids[m_layer]; + uint64_t acts_layer = 2; + uint64_t acts_sensitive = m_stave + 1; + + if (!recActsSvc->ReadInput(hit, + acts_volume, acts_layer, acts_sensitive)) + { return false; } + } + } + } + + if (useITKEndcap.value()) + { + const edm4hep::TrackerHitCollection* hitITKEndcapCol = nullptr; + const edm4hep::SimTrackerHitCollection* SimhitITKEndcapCol = nullptr; + const edm4hep::MCRecoTrackerAssociationCollection* itkEndcapAssCol = nullptr; + + try { + hitITKEndcapCol = _inITKEndcapTrackHdl.get(); + } catch (GaudiException& e) { + debug() << "Collection " << _inITKEndcapTrackHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; + return false; + } + + try { + SimhitITKEndcapCol = _inITKEndcapColHdl.get(); + } catch (GaudiException& e) { + debug() << "Sim Collection " << _inITKEndcapColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; + return false; + } + + try { + itkEndcapAssCol = _inITKEndcapAssColHdl.get(); + } catch (GaudiException& e) { + fatal() << "Association Collection " << _inITKEndcapAssColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; + return false; + } + + if (hitITKEndcapCol && SimhitITKEndcapCol) + { + int nelem = hitITKEndcapCol->size(); + debug() << "Number of ITKEndcap hits = " << nelem << endmsg; + + std::vector<int> hit_indices; + std::vector<float> hit_radii; + for(int ielem = 0; ielem < nelem; ++ielem){ + auto hit = hitITKEndcapCol->at(ielem); + + std::vector<edm4hep::SimTrackerHit> simHits; + for(auto ass : *itkEndcapAssCol){ + if(ass.getRec().getObjectID().collectionID != hit.getObjectID().collectionID) break; + else if(ass.getRec()==hit) simHits.push_back(ass.getSim()); + } + + if(simHits.size() == 0){ + info() << "Skip: Not found ITKEndcap simHit in AssociationCollection at event " << _nEvt << endmsg; + continue; + } + + auto simhit = simHits[0]; + + if (simhit.isProducedBySecondary()) { + continue; + } + + if (useMCTruth.value() && !(simhit.getMCParticle() == mc)) { + continue; + } + + float hit_r = std::hypot(hit.getPosition()[0], hit.getPosition()[1]); + hit_indices.push_back(ielem); + hit_radii.push_back(hit_r); + } + + std::sort(hit_indices.begin(), hit_indices.end(), + [&hit_radii](int i1, int i2) { return hit_radii[i1] < hit_radii[i2]; }); + + for (int i_hit : hit_indices) + { + auto hit = hitITKEndcapCol->at(i_hit); + + std::vector<edm4hep::SimTrackerHit> simHits; + for(auto ass : *itkEndcapAssCol){ + if(ass.getRec().getObjectID().collectionID != hit.getObjectID().collectionID) break; + else if(ass.getRec()==hit) simHits.push_back(ass.getSim()); + } + + if(simHits.size() == 0){ + info() << "Skip: Not found ITKEndcap simHit in AssociationCollection at event " << _nEvt << endmsg; + continue; + } + + auto simhit = simHits[0]; + + if (simhit.isProducedBySecondary()) { + continue; + } + + if (useMCTruth.value() && !(simhit.getMCParticle() == mc)) { + continue; + } + + auto cellid = hit.getCellID(); + int m_side = ITKEndcap_decoder->get(cellid, "side"); + uint64_t m_layer = ITKEndcap_decoder->get(cellid, "layer"); + uint64_t m_module = ITKEndcap_decoder->get(cellid, "module"); + + uint64_t acts_volume = (m_side == 1) ? ITKEndcap_positive_volume_ids[m_layer] : ITKEndcap_negative_volume_ids[m_layer]; + uint64_t acts_layer = 2; + uint64_t acts_sensitive = m_module + 1; + + if (!recActsSvc->ReadInput(hit, + acts_volume, acts_layer, acts_sensitive)) + { return false; } + } + } + } + + if (useTPC.value()) + { + + const edm4hep::TrackerHitCollection* hitTPCCol = nullptr; + const edm4hep::SimTrackerHitCollection* SimhitTPCCol = nullptr; + const edm4hep::MCRecoTrackerAssociationCollection* tpcAssCol = nullptr; + + try { + hitTPCCol = _inTPCTrackHdl.get(); + } catch (GaudiException& e) { + debug() << "Collection " << _inTPCTrackHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; + return false; + } + + try { + SimhitTPCCol = _inTPCColHdl.get(); + } catch (GaudiException& e) { + debug() << "Sim Collection " << _inTPCColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; + return false; + } + + try { + tpcAssCol = _inTPCAssColHdl.get(); + } catch (GaudiException& e) { + fatal() << "Association Collection " << _inTPCAssColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; + return false; + } + + if(hitTPCCol && SimhitTPCCol) + { + int nelem = hitTPCCol->size(); + debug() << "Number of TPC hits = " << nelem << endmsg; + + std::vector<int> hit_indices; + std::vector<float> hit_radii; + for(int ielem = 0; ielem < nelem; ++ielem){ + auto hit = hitTPCCol->at(ielem); + + std::vector<edm4hep::SimTrackerHit> simHits; + for(auto ass : *tpcAssCol){ + if(ass.getRec().getObjectID().collectionID != hit.getObjectID().collectionID) break; + else if(ass.getRec()==hit) simHits.push_back(ass.getSim()); + } + + if(simHits.size() == 0){ + info() << "Skip: Not found TPC simHit in AssociationCollection at event " << _nEvt << endmsg; + continue; + } + + auto simhit = simHits[0]; + + if (simhit.isProducedBySecondary()) { + continue; + } + + if (useMCTruth.value() && !(simhit.getMCParticle() == mc)) { + continue; + } + + float hit_r = std::hypot(hit.getPosition()[0], hit.getPosition()[1]); + hit_indices.push_back(ielem); + hit_radii.push_back(hit_r); + } + + std::sort(hit_indices.begin(), hit_indices.end(), + [&hit_radii](int i1, int i2) { return hit_radii[i1] < hit_radii[i2]; }); + + for (int i_hit : hit_indices) + { + auto hit = hitTPCCol->at(i_hit); + + auto cellid = hit.getCellID(); + uint64_t m_layer = tpc_decoder->get(cellid, "layer"); + + uint64_t acts_volume = TPC_volume_id; + uint64_t acts_layer = (m_layer + 1) * 2; + uint64_t acts_sensitive = 1; + bool buildSpacePoint = false; + int moduleType = 2; + double onSurfaceTolerance = 1e-4; + + if (!recActsSvc->ReadInput(hit, + acts_volume, acts_layer, acts_sensitive, + buildSpacePoint, moduleType, onSurfaceTolerance)) + { return false; } + } + } + } + + if (useOTKBarrel.value()) + { + const edm4hep::TrackerHitCollection* hitOTKBarrelCol = nullptr; + const edm4hep::SimTrackerHitCollection* SimhitOTKBarrelCol = nullptr; + const edm4hep::MCRecoTrackerAssociationCollection* otkBarrelAssCol = nullptr; + + try { + hitOTKBarrelCol = _inOTKBarrelTrackHdl.get(); + } catch (GaudiException& e) { + debug() << "Collection " << _inOTKBarrelTrackHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; + return false; + } + + try { + SimhitOTKBarrelCol = _inOTKBarrelColHdl.get(); + } catch (GaudiException& e) { + debug() << "Sim Collection " << _inOTKBarrelColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; + return false; + } + + try { + otkBarrelAssCol = _inOTKBarrelAssColHdl.get(); + } catch (GaudiException& e) { + fatal() << "Association Collection " << _inOTKBarrelAssColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; + return false; + } + + if(hitOTKBarrelCol && SimhitOTKBarrelCol) + { + int nelem = hitOTKBarrelCol->size(); + debug() << "Number of OTKBarrel hits = " << nelem << endmsg; + + std::vector<int> hit_indices; + std::vector<float> hit_radii; + for(int ielem = 0; ielem < nelem; ++ielem) + { + auto hit = hitOTKBarrelCol->at(ielem); + + std::vector<edm4hep::SimTrackerHit> simHits; + for(auto ass : *otkBarrelAssCol){ + if(ass.getRec().getObjectID().collectionID != hit.getObjectID().collectionID) break; + else if(ass.getRec()==hit) simHits.push_back(ass.getSim()); + } + + if(simHits.size() == 0){ + info() << "Skip: Not found OTKBarrel simHit in AssociationCollection at event " << _nEvt << endmsg; + continue; + } + + auto simhit = simHits[0]; + + if (simhit.isProducedBySecondary()) { + continue; + } + + if (useMCTruth.value() && !(simhit.getMCParticle() == mc)) { + continue; + } + + float hit_r = std::hypot(hit.getPosition()[0], hit.getPosition()[1]); + hit_indices.push_back(ielem); + hit_radii.push_back(hit_r); + } + + std::sort(hit_indices.begin(), hit_indices.end(), + [&hit_radii](int i1, int i2) { return hit_radii[i1] < hit_radii[i2]; }); + + for (int i_hit : hit_indices) + { + auto hit = hitOTKBarrelCol->at(i_hit); + + auto cellid = hit.getCellID(); + uint64_t m_module = OTKBarrel_decoder->get(cellid, "module"); + + uint64_t acts_volume = OTK_volume_id; + uint64_t acts_layer = 2; + uint64_t acts_sensitive = m_module + 1; + + if (!recActsSvc->ReadInput(hit, + acts_volume, acts_layer, acts_sensitive)) + { return false; } + } + } + } + + double p = sqrt(px*px + py*py + pz*pz); + double phi = atan2(py, px); + double theta = atan2(sqrt(px*px + py*py), pz); + double qop = -1 / p; + + Acts::BoundVector params = Acts::BoundVector::Zero(); + Acts::BoundSquareMatrix cov = Acts::BoundSquareMatrix::Zero(); + ActsHelper::IndexSourceLink::SurfaceAccessor surfaceAccessor{*recActsSvc->Geometry()}; + + auto first_hit_meas = recActsSvc->Measurements()->at(0); + auto cur_meas_param = std::get<1>(first_hit_meas).parameters(); + auto cur_meas_sl = std::get<1>(first_hit_meas).sourceLink(); + const Acts::Surface* surface = surfaceAccessor(cur_meas_sl); + + params[Acts::eBoundLoc0] = cur_meas_param[Acts::eBoundLoc0]; + params[Acts::eBoundLoc1] = cur_meas_param[Acts::eBoundLoc1]; + params[Acts::eBoundPhi] = phi; + params[Acts::eBoundTheta] = theta; + params[Acts::eBoundQOverP] = qop; + params[Acts::eBoundTime] = 0; + for (std::size_t i = Acts::eBoundLoc0; i < Acts::eBoundSize; ++i) { + double sigma = initialSigmas[i]; + sigma += initialSimgaQoverPCoefficients[i] * params[Acts::eBoundQOverP]; + double var = sigma * sigma; + // var *= noTimeVarInflation.value(); + var *= initialVarInflation.value()[i]; + + cov(i, i) = var; + } + + recActsSvc->InitialParameters()->emplace_back(surface->getSharedPtr(), params, cov, particleHypothesis); + + return true; +} \ No newline at end of file diff --git a/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTruthTracking.h b/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTruthTracking.h new file mode 100644 index 00000000..19672f3b --- /dev/null +++ b/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTruthTracking.h @@ -0,0 +1,183 @@ +#ifndef RecActsTruthTracking_H +#define RecActsTruthTracking_H + +// gaudi framework +#include "k4FWCore/DataHandle.h" +#include "GaudiAlg/GaudiAlgorithm.h" + +#include "UTIL/ILDConf.h" +#include "DataHelper/Navigation.h" + +// services +#include "RecActsSvc/IRecActsSvc.h" +#include "DetInterface/IGeomSvc.h" + +// DD4hep +#include "DD4hep/Detector.h" +#include "DDRec/ISurface.h" +#include "DDRec/SurfaceManager.h" + +// edm4hep +#include "edm4hep/MCParticle.h" +#include "edm4hep/MCParticleCollection.h" +#include "edm4hep/TrackerHitCollection.h" +#include "edm4hep/SimTrackerHitCollection.h" +#include "edm4hep/EventHeaderCollection.h" + +#include "edm4hep/Track.h" +#include "edm4hep/MutableTrack.h" +#include "edm4hep/TrackState.h" +#include "edm4hep/TrackCollection.h" +// Acts +#include "Acts/Definitions/Algebra.hpp" +#include "Acts/EventData/GenericBoundTrackParameters.hpp" +#include "Acts/EventData/SourceLink.hpp" +#include "Acts/EventData/TrackProxy.hpp" +#include "Acts/EventData/VectorMultiTrajectory.hpp" +#include "Acts/EventData/VectorTrackContainer.hpp" +#include "Acts/Propagator/Propagator.hpp" +#include "Acts/Surfaces/PerigeeSurface.hpp" +#include "Acts/Surfaces/Surface.hpp" +#include "Acts/Utilities/Result.hpp" + +#include "Acts/Definitions/Direction.hpp" +#include "Acts/Definitions/TrackParametrization.hpp" +#include "Acts/EventData/MultiTrajectory.hpp" +#include "Acts/EventData/TrackContainer.hpp" +#include "Acts/EventData/TrackStatePropMask.hpp" +#include "Acts/EventData/detail/CorrectedTransformationFreeToBound.hpp" +#include "Acts/Geometry/GeometryIdentifier.hpp" +#include "Acts/Propagator/DirectNavigator.hpp" +#include "Acts/Propagator/EigenStepper.hpp" +#include "Acts/Propagator/Navigator.hpp" +#include "Acts/TrackFitting/GlobalChiSquareFitter.hpp" +#include "Acts/TrackFitting/KalmanFitter.hpp" +#include "Acts/Utilities/Delegate.hpp" +#include "Acts/Utilities/Logger.hpp" + +namespace Acts +{ + class MagneticFieldProvider; + class TrackingGeometry; +} + +class RecActsTruthTracking : public GaudiAlgorithm +{ + public: + RecActsTruthTracking(const std::string& name, ISvcLocator* svcLoc); + + StatusCode initialize(); + StatusCode execute(); + StatusCode finalize(); + + private: + // Input collections + DataHandle<edm4hep::MCParticleCollection> _inMCColHdl{"MCParticle", Gaudi::DataHandle::Reader, this}; + + DataHandle<edm4hep::TrackerHitCollection> _inVTXTrackHdl{"VXDTrackerHits", Gaudi::DataHandle::Reader, this}; + DataHandle<edm4hep::TrackerHitCollection> _inITKBarrelTrackHdl{"ITKBarrelTrackerHits", Gaudi::DataHandle::Reader, this}; + DataHandle<edm4hep::TrackerHitCollection> _inITKEndcapTrackHdl{"ITKEndcapTrackerHits", Gaudi::DataHandle::Reader, this}; + DataHandle<edm4hep::TrackerHitCollection> _inOTKBarrelTrackHdl{"OTKBarrelTrackerHits", Gaudi::DataHandle::Reader, this}; + DataHandle<edm4hep::TrackerHitCollection> _inTPCTrackHdl{"TPCTrackerHits", Gaudi::DataHandle::Reader, this}; + + DataHandle<edm4hep::SimTrackerHitCollection> _inVTXColHdl{"VXDCollection", Gaudi::DataHandle::Reader, this}; + DataHandle<edm4hep::SimTrackerHitCollection> _inITKBarrelColHdl{"ITKBarrelCollection", Gaudi::DataHandle::Reader, this}; + DataHandle<edm4hep::SimTrackerHitCollection> _inITKEndcapColHdl{"ITKEndcapCollection", Gaudi::DataHandle::Reader, this}; + DataHandle<edm4hep::SimTrackerHitCollection> _inOTKBarrelColHdl{"OTKBarrelCollection", Gaudi::DataHandle::Reader, this}; + DataHandle<edm4hep::SimTrackerHitCollection> _inTPCColHdl{"TPCCollection", Gaudi::DataHandle::Reader, this}; + + // associations + DataHandle<edm4hep::MCRecoTrackerAssociationCollection> _inVTXAssColHdl{"VXDTrackerHitAssociation", Gaudi::DataHandle::Reader, this}; + DataHandle<edm4hep::MCRecoTrackerAssociationCollection> _inITKBarrelAssColHdl{"ITKBarrelTrackerHitAssociation", Gaudi::DataHandle::Reader, this}; + DataHandle<edm4hep::MCRecoTrackerAssociationCollection> _inITKEndcapAssColHdl{"ITKEndcapTrackerHitAssociation", Gaudi::DataHandle::Reader, this}; + DataHandle<edm4hep::MCRecoTrackerAssociationCollection> _inOTKBarrelAssColHdl{"OTKBarrelTrackerHitAssociation", Gaudi::DataHandle::Reader, this}; + DataHandle<edm4hep::MCRecoTrackerAssociationCollection> _inTPCAssColHdl{"TPCTrackerHitAss", Gaudi::DataHandle::Reader, this}; + + // Output collections + DataHandle<edm4hep::TrackCollection> _outColHdl{"ACTSTruthTracks", Gaudi::DataHandle::Writer, this}; + + Gaudi::Property<std::string> m_particle{this, "AssumeParticle", "muon"}; + Gaudi::Property<double> m_field{this, "bFieldInZ", 3.0}; // tesla + Gaudi::Property<std::vector<double>> initialVarInflation{this, "initialVarInflation", {1, 1, 1, 1, 1, 1}}; + Gaudi::Property<double> noTimeVarInflation{this, "noTimeVarInflation", 1.}; + + Gaudi::Property<bool> useMCTruth{this, "useMCTruth", false}; + Gaudi::Property<bool> useVTX{this, "useVTX", true}; + Gaudi::Property<bool> useITKBarrel{this, "useITKBarrel", true}; + Gaudi::Property<bool> useITKEndcap{this, "useITKEndcap", true}; + Gaudi::Property<bool> useTPC{this, "useTPC", true}; + Gaudi::Property<bool> useOTKBarrel{this, "useOTKBarrel", true}; + // Gaudi::Property<bool> useOTKEndcap{this, "useOTKEndcap", true}; + + // services + // SmartIF<IGeomSvc> m_geosvc; + SmartIF<IRecActsSvc> recActsSvc; + SmartIF<IChronoStatSvc> chronoStatSvc; + + bool ReadHits(const edm4hep::MCParticle& mc); + + // Decoders + dd4hep::DDSegmentation::BitFieldCoder *vtx_decoder; + dd4hep::DDSegmentation::BitFieldCoder *ITKBarrel_decoder; + dd4hep::DDSegmentation::BitFieldCoder *ITKEndcap_decoder; + dd4hep::DDSegmentation::BitFieldCoder *tpc_decoder; + dd4hep::DDSegmentation::BitFieldCoder *OTKBarrel_decoder; + + std::shared_ptr<ActsHelper::TrackFitterFunction> fit; + std::shared_ptr<const Acts::MagneticFieldProvider> magneticField; + // std::shared_ptr<ActsHelper::MeasurementCalibrator> m_calibrator; + + // globalChiSquareFitter config + bool multipleScattering = false; + bool energyLoss = false; + Acts::FreeToBoundCorrection freeToBoundCorrection; + std::size_t nUpdateMax = 5; + double relChi2changeCutOff = 1e-7; + + // context + Acts::GeometryContext geoContext; + Acts::MagneticFieldContext magFieldContext; + Acts::CalibrationContext calibContext; + + // double noTimeVarInflation = 10.; + std::array<double, 6> initialSigmas = { + 5 * Acts::UnitConstants::um, + 5 * Acts::UnitConstants::um, + 2e-2 * Acts::UnitConstants::degree, + 2e-2 * Acts::UnitConstants::degree, + 0 * Acts::UnitConstants::e / Acts::UnitConstants::GeV, + 1 * Acts::UnitConstants::s + }; + std::array<double, 6> initialSimgaQoverPCoefficients = { + 0 * Acts::UnitConstants::mm / (Acts::UnitConstants::e * Acts::UnitConstants::GeV), + 0 * Acts::UnitConstants::mm / (Acts::UnitConstants::e * Acts::UnitConstants::GeV), + 0 * Acts::UnitConstants::degree / (Acts::UnitConstants::e * Acts::UnitConstants::GeV), + 0 * Acts::UnitConstants::degree / (Acts::UnitConstants::e * Acts::UnitConstants::GeV), + 0.1, + 0 * Acts::UnitConstants::ns / (Acts::UnitConstants::e * Acts::UnitConstants::GeV) + }; + + std::array<std::string, 8> particleNames = {"muon", "pion", "electron", "kaon", "proton", "photon", "geantino", "chargedgeantino"}; + + // constants + const double _FCT = 2.99792458E-4; + uint64_t TPC_volume_id = 45; + uint64_t OTKBarrel_volume_id = 47; + uint64_t OTKEndcap_positive_volume_id = 2; + uint64_t OTKEndcap_negative_volume_id = 48; + std::vector<uint64_t> VXD_volume_ids{28, 29, 30, 31, 32}; + std::vector<uint64_t> ITKBarrel_volume_ids{35, 38, 41}; + std::vector<uint64_t> ITKEndcap_positive_volume_ids{36, 39, 42, 43}; + std::vector<uint64_t> ITKEndcap_negative_volume_ids{34, 17, 12, 10}; + std::vector<std::vector<uint64_t>> ITKEndcap_modules_per_ring{{13, 20, 0}, {16, 24, 28}, {24, 36, 44}, {24, 36, 44}}; + std::vector<uint64_t> ITKBarrel_module_nums{7, 10, 14}; + + const std::array<Acts::BoundIndices, 6> writeout_indices{ + Acts::BoundIndices::eBoundLoc0, Acts::BoundIndices::eBoundPhi, + Acts::BoundIndices::eBoundQOverP, Acts::BoundIndices::eBoundLoc1, + Acts::BoundIndices::eBoundTheta, Acts::BoundIndices::eBoundTime}; + Acts::ParticleHypothesis particleHypothesis = Acts::ParticleHypothesis::muon(); + int _nEvt; +}; + +#endif // RecActsTruthTracking_H \ No newline at end of file diff --git a/Reconstruction/RecActsTracking/options/RecActsTracking.py b/Reconstruction/RecActsTracking/options/RecActsTracking.py deleted file mode 100644 index 1ba576f9..00000000 --- a/Reconstruction/RecActsTracking/options/RecActsTracking.py +++ /dev/null @@ -1,92 +0,0 @@ -#!/usr/bin/env python -import os - -from Gaudi.Configuration import * - -NTupleSvc().Output = ["MyTuples DATAFILE='test.root' OPT='NEW' TYP='ROOT'"] - -from Configurables import k4DataSvc -dsvc = k4DataSvc("EventDataSvc", input="rec00.root") - -from Configurables import PodioInput -podioinput = PodioInput("PodioReader", collections=[ - "MCParticle", - "VXDCollection", - "SITCollection", - "VXDTrackerHits", - "SITTrackerHits", -]) - -############################################################################## -# Geometry Svc -############################################################################## - -# geometry_option = "TDR_o1_v01/TDR_o1_v01-onlyTracker.xml" -geometry_option = "TDR_o1_v01/TDR_o1_v01.xml" - -if not os.getenv("DETCRDROOT"): - print("Can't find the geometry. Please setup envvar DETCRDROOT." ) - sys.exit(-1) - -geometry_path = os.path.join(os.getenv("DETCRDROOT"), "compact", geometry_option) -if not os.path.exists(geometry_path): - print("Can't find the compact geometry file: %s"%geometry_path) - sys.exit(-1) - -from Configurables import DetGeomSvc -geosvc = DetGeomSvc("GeomSvc") -geosvc.compact = geometry_path - -from Configurables import MarlinEvtSeeder -evtseeder = MarlinEvtSeeder("EventSeeder") - -from Configurables import GearSvc -gearsvc = GearSvc("GearSvc") - -from Configurables import TrackSystemSvc -tracksystemsvc = TrackSystemSvc("TrackSystemSvc") - -############################################################################## -# CEPCSWData -############################################################################## -cepcswdatatop ="/cvmfs/cepcsw.ihep.ac.cn/prototype/releases/data/latest" - -############################################################################## -# RecActsTracking -############################################################################## - -from Configurables import RecActsTracking -actstracking = RecActsTracking("RecActsTracking") -actstracking.TGeoFile = os.path.join(cepcswdatatop, "CEPCSWData/offline-data/Reconstruction/RecActsTracking/data/tdr25.1.0/SiTrack-tgeo.root") -actstracking.TGeoConfigFile = os.path.join(cepcswdatatop, "CEPCSWData/offline-data/Reconstruction/RecActsTracking/data/tdr25.1.0/SiTrack-tgeo-config.json") -actstracking.MaterialMapFile = os.path.join(cepcswdatatop, "CEPCSWData/offline-data/Reconstruction/RecActsTracking/data/tdr25.1.0/SiTrack-material-maps.json") - -# config for acts tracking -actstracking.onSurfaceTolerance = 2e-1 -# actstracking.ExtendSeedRange = True -# actstracking.SeedDeltaRMin = 10 -# actstracking.SeedDeltaRMax = 200 -# actstracking.SeedRMax = 600 -# actstracking.SeedRMin = 80 -# actstracking.SeedImpactMax = 4 -# actstracking.SeedRMinMiddle = 340 -# actstracking.SeedRMaxMiddle = 380 -actstracking.numMeasurementsCutOff = 2 -actstracking.CKFchi2Cut = 1 - -############################################################################## -# output -############################################################################## -from Configurables import PodioOutput -out = PodioOutput("out") -out.filename = "ACTS_rec00.root" -out.outputCommands = ["keep *"] - -# ApplicationMgr -from Configurables import ApplicationMgr -ApplicationMgr( TopAlg = [podioinput, actstracking, out], - EvtSel = 'NONE', - EvtMax = 5, - ExtSvc = [dsvc, geosvc, evtseeder, gearsvc], - # OutputLevel=DEBUG -) diff --git a/Reconstruction/RecActsTracking/src/RecActsTracking.cpp b/Reconstruction/RecActsTracking/src/RecActsTracking.cpp deleted file mode 100644 index ba125e91..00000000 --- a/Reconstruction/RecActsTracking/src/RecActsTracking.cpp +++ /dev/null @@ -1,1208 +0,0 @@ -#include <iostream> -#include <fstream> -#include <cstdlib> -#include <sstream> - -// dependence -#include "RecActsTracking.h" - -#include "GearSvc/IGearSvc.h" - -// csv parser -// #include "csv2/writer.hpp" - -// MC -#include "CLHEP/Units/SystemOfUnits.h" - - -using namespace Acts::UnitLiterals; - -DECLARE_COMPONENT(RecActsTracking) - -RecActsTracking::RecActsTracking(const std::string& name, ISvcLocator* svcLoc) - : GaudiAlgorithm(name, svcLoc) -{ -} - -StatusCode RecActsTracking::initialize() -{ - chronoStatSvc = service<IChronoStatSvc>("ChronoStatSvc"); - _nEvt = 0; - - if (!std::filesystem::exists(TGeo_path.value())) { - error() << "CEPC TGeo file: " << TGeo_path.value() << " does not exist!" << endmsg; - return StatusCode::FAILURE; - } - - if (!std::filesystem::exists(TGeo_config_path.value())) { - error() << "CEPC TGeo config file: " << TGeo_config_path.value() << " does not exist!" << endmsg; - return StatusCode::FAILURE; - } - - if (!std::filesystem::exists(MaterialMap_path.value())) { - error() << "CEPC Material map file: " << MaterialMap_path.value() << " does not exist!" << endmsg; - return StatusCode::FAILURE; - } - - if(!m_particle.value().empty()){ - info() << "Assume Particle: " << m_particle.value() << endmsg; - if(m_particle.value() == "muon"){ - particleHypothesis = Acts::ParticleHypothesis::muon(); - } - else if(m_particle.value() == "pion"){ - particleHypothesis = Acts::ParticleHypothesis::pion(); - } - else if(m_particle.value() == "electron"){ - particleHypothesis = Acts::ParticleHypothesis::electron(); - } - else if(m_particle.value() == "kaon"){ - particleHypothesis = Acts::ParticleHypothesis::kaon(); - } - else if(m_particle.value() == "proton"){ - particleHypothesis = Acts::ParticleHypothesis::proton(); - } - else if(m_particle.value() == "photon"){ - particleHypothesis = Acts::ParticleHypothesis::photon(); - } - else if(m_particle.value() == "geantino"){ - particleHypothesis = Acts::ParticleHypothesis::geantino(); - } - else if(m_particle.value() == "chargedgeantino"){ - particleHypothesis = Acts::ParticleHypothesis::chargedGeantino(); - } - else{ - info() << "Supported Assumed Particle: " << particleNames[0] << ", " << particleNames[1] << ", " << particleNames[2] << ", " - << particleNames[3] << ", " << particleNames[4] << ", " << particleNames[5] << ", " - << particleNames[6] << ", " << particleNames[7] << endmsg; - error() << "Unsupported particle name " << m_particle.value() << endmsg; - return StatusCode::FAILURE; - } - } - - TGeo_ROOTFilePath = TGeo_path.value(); - TGeoConfig_jFilePath = TGeo_config_path.value(); - MaterialMap_jFilePath = MaterialMap_path.value(); - - chronoStatSvc->chronoStart("read geometry"); - m_geosvc = service<IGeomSvc>("GeomSvc"); - if (!m_geosvc) { - error() << "Failed to find GeomSvc." << endmsg; - return StatusCode::FAILURE; - } - - if(m_geosvc){ - const dd4hep::Direction& field = m_geosvc->lcdd()->field().magneticField(dd4hep::Position(0,0,0)); - m_field = field.z()/dd4hep::tesla; - } - - m_vtx_surfaces = m_geosvc->getSurfaceMap("VXD"); - debug() << "Surface map size: " << m_vtx_surfaces->size() << endmsg; - - m_sit_surfaces = m_geosvc->getSurfaceMap("SIT"); - debug() << "Surface map size: " << m_sit_surfaces->size() << endmsg; - - m_ftd_surfaces = m_geosvc->getSurfaceMap("FTD"); - debug() << "Surface map size: " << m_ftd_surfaces->size() << endmsg; - - vxd_decoder = m_geosvc->getDecoder("VXDCollection"); - if(!vxd_decoder){ - return StatusCode::FAILURE; - } - - sit_decoder = m_geosvc->getDecoder("SITCollection"); - if(!sit_decoder){ - return StatusCode::FAILURE; - } - - ftd_decoder = m_geosvc->getDecoder("FTDCollection"); - if(!ftd_decoder){ - return StatusCode::FAILURE; - } - - info() << "ACTS Tracking Geometry initialized successfully!" << endmsg; - // initialize tgeo detector - auto logger = Acts::getDefaultLogger("TGeoDetector", Acts::Logging::INFO); - trackingGeometry = buildTGeoDetector(geoContext, detElementStore, TGeo_ROOTFilePath, TGeoConfig_jFilePath, MaterialMap_jFilePath, *logger); - - info() << "Seeding tools initialized successfully!" << endmsg; - - // configure the acts tools - seed_cfg.seedFinderOptions.bFieldInZ = m_field.value(); - seed_cfg.seedFinderConfig.deltaRMin = SeedDeltaRMin.value(); - seed_cfg.seedFinderConfig.deltaRMax = SeedDeltaRMax.value(); - seed_cfg.seedFinderConfig.rMax = SeedRMax.value(); - seed_cfg.seedFinderConfig.rMin = SeedRMin.value(); - seed_cfg.seedFinderConfig.impactMax = SeedImpactMax.value(); - seed_cfg.seedFinderConfig.useVariableMiddleSPRange = false; - seed_cfg.seedFinderConfig.rMinMiddle = SeedRMinMiddle.value(); - seed_cfg.seedFinderConfig.rMaxMiddle = SeedRMaxMiddle.value(); - - // initialize the acts tools - seed_cfg.seedFilterConfig = seed_cfg.seedFilterConfig.toInternalUnits(); - seed_cfg.seedFinderConfig.seedFilter = - std::make_unique<Acts::SeedFilter<SimSpacePoint>>(seed_cfg.seedFilterConfig); - seed_cfg.seedFinderConfig = - seed_cfg.seedFinderConfig.toInternalUnits().calculateDerivedQuantities(); - seed_cfg.seedFinderOptions = - seed_cfg.seedFinderOptions.toInternalUnits().calculateDerivedQuantities(seed_cfg.seedFinderConfig); - seed_cfg.gridConfig = seed_cfg.gridConfig.toInternalUnits(); - seed_cfg.gridOptions = seed_cfg.gridOptions.toInternalUnits(); - - if (std::isnan(seed_cfg.seedFinderConfig.deltaRMaxTopSP)) { - seed_cfg.seedFinderConfig.deltaRMaxTopSP = seed_cfg.seedFinderConfig.deltaRMax;} - if (std::isnan(seed_cfg.seedFinderConfig.deltaRMinTopSP)) { - seed_cfg.seedFinderConfig.deltaRMinTopSP = seed_cfg.seedFinderConfig.deltaRMin;} - if (std::isnan(seed_cfg.seedFinderConfig.deltaRMaxBottomSP)) { - seed_cfg.seedFinderConfig.deltaRMaxBottomSP = seed_cfg.seedFinderConfig.deltaRMax;} - if (std::isnan(seed_cfg.seedFinderConfig.deltaRMinBottomSP)) { - seed_cfg.seedFinderConfig.deltaRMinBottomSP = seed_cfg.seedFinderConfig.deltaRMin;} - - m_bottomBinFinder = std::make_unique<const Acts::GridBinFinder<2ul>>( - seed_cfg.numPhiNeighbors, seed_cfg.zBinNeighborsBottom); - m_topBinFinder = std::make_unique<const Acts::GridBinFinder<2ul>>( - seed_cfg.numPhiNeighbors, seed_cfg.zBinNeighborsTop); - - seed_cfg.seedFinderConfig.seedFilter = - std::make_unique<Acts::SeedFilter<SimSpacePoint>>(seed_cfg.seedFilterConfig); - m_seedFinder = - Acts::SeedFinder<SimSpacePoint, Acts::CylindricalSpacePointGrid<SimSpacePoint>>(seed_cfg.seedFinderConfig); - - // initialize the ckf - findTracks = makeTrackFinderFunction(trackingGeometry, magneticField); - - info() << "CKF Track Finder initialized successfully!" << endmsg; - chronoStatSvc->chronoStop("read geometry"); - - return GaudiAlgorithm::initialize(); -} - -StatusCode RecActsTracking::execute() -{ - auto trkCol = _outColHdl.createAndPut(); - - SpacePointPtrs.clear(); - sourceLinks.clear(); - measurements.clear(); - initialParameters.clear(); - Selected_Seeds.clear(); - - chronoStatSvc->chronoStart("read input hits"); - - int successVTX = InitialiseVTX(); - if (successVTX == 0) - { - _nEvt++; - return StatusCode::SUCCESS; - } - - int successSIT = InitialiseSIT(); - if (successSIT == 0) - { - _nEvt++; - return StatusCode::SUCCESS; - } - - int successFTD = InitialiseFTD(); - if(successFTD == 0){ - _nEvt++; - return StatusCode::SUCCESS; - } - - chronoStatSvc->chronoStop("read input hits"); - // info() << "Generated " << SpacePointPtrs.size() << " spacepoints for event " << _nEvt << "!" << endmsg; - // info() << "Generated " << measurements.size() << " measurements for event " << _nEvt << "!" << endmsg; - - // -------------------------------------------- - // Seeding - // -------------------------------------------- - chronoStatSvc->chronoStart("seeding"); - - // construct the seeding tools - // covariance tool, extracts covariances per spacepoint as required - auto extractGlobalQuantities = [=](const SimSpacePoint& sp, float, float, float) - { - Acts::Vector3 position{sp.x(), sp.y(), sp.z()}; - Acts::Vector2 covariance{sp.varianceR(), sp.varianceZ()}; - return std::make_tuple(position, covariance, sp.t()); - }; - - // extent used to store r range for middle spacepoint - Acts::Extent rRangeSPExtent; - - // construct the seeding tool - Acts::CylindricalSpacePointGrid<SimSpacePoint> grid = - Acts::CylindricalSpacePointGridCreator::createGrid<SimSpacePoint>(seed_cfg.gridConfig, seed_cfg.gridOptions); - Acts::CylindricalSpacePointGridCreator::fillGrid( - seed_cfg.seedFinderConfig, seed_cfg.seedFinderOptions, grid, - SpacePointPtrs.begin(), SpacePointPtrs.end(), extractGlobalQuantities, rRangeSPExtent); - - std::array<std::vector<std::size_t>, 2ul> navigation; - navigation[1ul] = seed_cfg.seedFinderConfig.zBinsCustomLooping; - - auto spacePointsGrouping = Acts::CylindricalBinnedGroup<SimSpacePoint>( - std::move(grid), *m_bottomBinFinder, *m_topBinFinder, std::move(navigation)); - - // safely clamp double to float - float up = Acts::clampValue<float>( - std::floor(rRangeSPExtent.max(Acts::binR) / 2) * 2); - - /// variable middle SP radial region of interest - const Acts::Range1D<float> rMiddleSPRange( - std::floor(rRangeSPExtent.min(Acts::binR) / 2) * 2 + - seed_cfg.seedFinderConfig.deltaRMiddleMinSPRange, - up - seed_cfg.seedFinderConfig.deltaRMiddleMaxSPRange); - - // run the seeding - static thread_local SimSeedContainer seeds; - seeds.clear(); - static thread_local decltype(m_seedFinder)::SeedingState state; - state.spacePointData.resize( - SpacePointPtrs.size(), - seed_cfg.seedFinderConfig.useDetailedDoubleMeasurementInfo); - - // use double stripe measurement - if (seed_cfg.seedFinderConfig.useDetailedDoubleMeasurementInfo) - { - for (std::size_t grid_glob_bin(0); grid_glob_bin < spacePointsGrouping.grid().size(); ++grid_glob_bin) - { - const auto& collection = spacePointsGrouping.grid().at(grid_glob_bin); - for (const auto& sp : collection) - { - std::size_t index = sp->index(); - const float topHalfStripLength = - seed_cfg.seedFinderConfig.getTopHalfStripLength(sp->sp()); - const float bottomHalfStripLength = - seed_cfg.seedFinderConfig.getBottomHalfStripLength(sp->sp()); - const Acts::Vector3 topStripDirection = - seed_cfg.seedFinderConfig.getTopStripDirection(sp->sp()); - const Acts::Vector3 bottomStripDirection = - seed_cfg.seedFinderConfig.getBottomStripDirection(sp->sp()); - - state.spacePointData.setTopStripVector( - index, topHalfStripLength * topStripDirection); - state.spacePointData.setBottomStripVector( - index, bottomHalfStripLength * bottomStripDirection); - state.spacePointData.setStripCenterDistance( - index, seed_cfg.seedFinderConfig.getStripCenterDistance(sp->sp())); - state.spacePointData.setTopStripCenterPosition( - index, seed_cfg.seedFinderConfig.getTopStripCenterPosition(sp->sp())); - } - } - } - - for (const auto [bottom, middle, top] : spacePointsGrouping) - { - m_seedFinder.createSeedsForGroup( - seed_cfg.seedFinderOptions, state, spacePointsGrouping.grid(), - std::back_inserter(seeds), bottom, middle, top, rMiddleSPRange); - } - - // int seed_counter = 0; - // for (const auto& seed : seeds) - // { - // for (const auto& sp : seed.sp()) - // { - // info() << "found seed #" << seed_counter << ": x:" << sp->x() << " y: " << sp->y() << " z: " << sp->z() << endmsg; - // } - // seed_counter++; - // } - - chronoStatSvc->chronoStop("seeding"); - debug() << "Found " << seeds.size() << " seeds for event " << _nEvt << "!" << endmsg; - - // -------------------------------------------- - // track estimation - // -------------------------------------------- - chronoStatSvc->chronoStart("track_param"); - - IndexSourceLink::SurfaceAccessor surfaceAccessor{*trackingGeometry}; - - for (std::size_t iseed = 0; iseed < seeds.size(); ++iseed) - { - const auto& seed = seeds[iseed]; - // Get the bottom space point and its reference surface - const auto bottomSP = seed.sp().front(); - const auto& sourceLink = bottomSP->sourceLinks()[0]; - const Acts::Surface* surface = surfaceAccessor(sourceLink); - if (surface == nullptr) { - debug() << "Surface from source link is not found in the tracking geometry: iseed " << iseed << endmsg; - continue; - } - - auto optParams = Acts::estimateTrackParamsFromSeed( - geoContext, seed.sp().begin(), seed.sp().end(), *surface, acts_field_value, bFieldMin); - - if (!optParams.has_value()) { - debug() << "Estimation of track parameters for seed " << iseed << " failed." << endmsg; - continue; - } - - const auto& params = optParams.value(); - Acts::BoundSquareMatrix cov = Acts::BoundSquareMatrix::Zero(); - for (std::size_t i = Acts::eBoundLoc0; i < Acts::eBoundSize; ++i) { - double sigma = initialSigmas[i]; - sigma += abs(initialSimgaQoverPCoefficients[i] * params[Acts::eBoundQOverP]); - double var = sigma * sigma; - if (i == Acts::eBoundTime && !bottomSP->t().has_value()) { var *= noTimeVarInflation; } - var *= initialVarInflation.value()[i]; - - cov(i, i) = var; - } - initialParameters.emplace_back(surface->getSharedPtr(), params, cov, particleHypothesis); - Selected_Seeds.push_back(seed); - } - - chronoStatSvc->chronoStop("track_param"); - debug() << "Found " << initialParameters.size() << " tracks for event " << _nEvt << "!" << endmsg; - - // -------------------------------------------- - // CKF track finding - // -------------------------------------------- - chronoStatSvc->chronoStart("ckf_findTracks"); - - // Construct a perigee surface as the target surface - auto pSurface = Acts::Surface::makeShared<Acts::PerigeeSurface>(Acts::Vector3{0., 0., 0.}); - PassThroughCalibrator pcalibrator; - MeasurementCalibratorAdapter calibrator(pcalibrator, measurements); - Acts::GainMatrixUpdater kfUpdater; - Acts::MeasurementSelector::Config measurementSelectorCfg = - { - {Acts::GeometryIdentifier(), {{}, {CKFchi2Cut.value()}, {numMeasurementsCutOff.value()}}}, - }; - - MeasurementSelector measSel{ Acts::MeasurementSelector(measurementSelectorCfg) }; - using Extensions = Acts::CombinatorialKalmanFilterExtensions<Acts::VectorMultiTrajectory>; - BranchStopper branchStopper(trackSelectorCfg); - - // Construct the CKF - Extensions extensions; - extensions.calibrator.connect<&MeasurementCalibratorAdapter::calibrate>(&calibrator); - extensions.updater.connect<&Acts::GainMatrixUpdater::operator()<Acts::VectorMultiTrajectory>>(&kfUpdater); - extensions.measurementSelector.connect<&MeasurementSelector::select>(&measSel); - extensions.branchStopper.connect<&BranchStopper::operator()>(&branchStopper); - - IndexSourceLinkAccessor slAccessor; - slAccessor.container = &sourceLinks; - Acts::SourceLinkAccessorDelegate<IndexSourceLinkAccessor::Iterator> slAccessorDelegate; - slAccessorDelegate.connect<&IndexSourceLinkAccessor::range>(&slAccessor); - - Acts::PropagatorPlainOptions firstPropOptions; - firstPropOptions.maxSteps = maxSteps; - firstPropOptions.direction = Acts::Direction::Forward; - - Acts::PropagatorPlainOptions secondPropOptions; - secondPropOptions.maxSteps = maxSteps; - secondPropOptions.direction = firstPropOptions.direction.invert(); - - // Set the CombinatorialKalmanFilter options - TrackFinderOptions firstOptions( - geoContext, magFieldContext, calibContext, - slAccessorDelegate, extensions, firstPropOptions); - - TrackFinderOptions secondOptions( - geoContext, magFieldContext, calibContext, - slAccessorDelegate, extensions, secondPropOptions); - secondOptions.targetSurface = pSurface.get(); - - Acts::Propagator<Acts::EigenStepper<>, Acts::Navigator> extrapolator( - Acts::EigenStepper<>(magneticField), Acts::Navigator({trackingGeometry})); - - Acts::PropagatorOptions<Acts::ActionList<Acts::MaterialInteractor>, Acts::AbortList<Acts::EndOfWorldReached>> - extrapolationOptions(geoContext, magFieldContext); - - auto trackContainer = std::make_shared<Acts::VectorTrackContainer>(); - auto trackStateContainer = std::make_shared<Acts::VectorMultiTrajectory>(); - auto trackContainerTemp = std::make_shared<Acts::VectorTrackContainer>(); - auto trackStateContainerTemp = std::make_shared<Acts::VectorMultiTrajectory>(); - TrackContainer tracks(trackContainer, trackStateContainer); - TrackContainer tracksTemp(trackContainerTemp, trackStateContainerTemp); - - tracks.addColumn<unsigned int>("trackGroup"); - tracksTemp.addColumn<unsigned int>("trackGroup"); - Acts::ProxyAccessor<unsigned int> seedNumber("trackGroup"); - - unsigned int nSeed = 0; - // A map indicating whether a seed has been discovered already - std::unordered_map<SeedIdentifier, bool> discoveredSeeds; - auto addTrack = [&](const TrackProxy& track) - { - ++m_nFoundTracks; - // flag seeds which are covered by the track - visitSeedIdentifiers(track, [&](const SeedIdentifier& seedIdentifier) - { - if (auto it = discoveredSeeds.find(seedIdentifier); it != discoveredSeeds.end()) - { - it->second = true; - } - }); - - if (m_trackSelector.has_value() && !m_trackSelector->isValidTrack(track)) { return; } - - ++m_nSelectedTracks; - auto destProxy = tracks.makeTrack(); - // make sure we copy track states! - destProxy.copyFrom(track, true); - }; - - for (const auto& seed : Selected_Seeds) { - SeedIdentifier seedIdentifier = makeSeedIdentifier(seed); - discoveredSeeds.emplace(seedIdentifier, false); - } - - for (std::size_t iSeed = 0; iSeed < initialParameters.size(); ++iSeed) - { - m_nTotalSeeds++; - const auto& seed = Selected_Seeds[iSeed]; - - SeedIdentifier seedIdentifier = makeSeedIdentifier(seed); - // check if the seed has been discovered already - if (auto it = discoveredSeeds.find(seedIdentifier); it != discoveredSeeds.end() && it->second) - { - m_nDeduplicatedSeeds++; - continue; - } - - /// Whether to stick on the seed measurements during track finding. - // measSel.setSeed(seed); - - // Clear trackContainerTemp and trackStateContainerTemp - tracksTemp.clear(); - - const Acts::BoundTrackParameters& firstInitialParameters = initialParameters.at(iSeed); - auto firstResult = (*findTracks)(firstInitialParameters, firstOptions, tracksTemp); - - nSeed++; - if (!firstResult.ok()) - { - m_nFailedSeeds++; - continue; - } - - auto& firstTracksForSeed = firstResult.value(); - for (auto& firstTrack : firstTracksForSeed) - { - auto trackCandidate = tracksTemp.makeTrack(); - trackCandidate.copyFrom(firstTrack, true); - - auto firstSmoothingResult = Acts::smoothTrack(geoContext, trackCandidate); - - if (!firstSmoothingResult.ok()) - { - m_nFailedSmoothing++; - debug() << "First smoothing for seed " - << iSeed << " and track " << firstTrack.index() - << " failed with error " << firstSmoothingResult.error() << endmsg; - continue; - } - - seedNumber(trackCandidate) = nSeed - 1; - - // second way track finding - std::size_t nSecond = 0; - if (CKFtwoWay) - { - std::optional<Acts::VectorMultiTrajectory::TrackStateProxy> firstMeasurement; - for (auto trackState : trackCandidate.trackStatesReversed()) - { - bool isMeasurement = trackState.typeFlags().test(Acts::TrackStateFlag::MeasurementFlag); - bool isOutlier = trackState.typeFlags().test(Acts::TrackStateFlag::OutlierFlag); - if (isMeasurement && !isOutlier) { firstMeasurement = trackState; } - } - - if (firstMeasurement.has_value()) - { - Acts::BoundTrackParameters secondInitialParameters = trackCandidate.createParametersFromState(*firstMeasurement); - auto secondResult = (*findTracks)(secondInitialParameters, secondOptions, tracksTemp); - if (!secondResult.ok()) - { - debug() << "Second track finding failed for seed " - << iSeed << " with error" << secondResult.error() << endmsg; - } else { - auto firstState = *std::next(trackCandidate.trackStatesReversed().begin(), trackCandidate.nTrackStates() - 1); - auto& secondTracksForSeed = secondResult.value(); - for (auto& secondTrack : secondTracksForSeed) - { - if (secondTrack.nTrackStates() < 2) { continue; } - auto secondTrackCopy = tracksTemp.makeTrack(); - secondTrackCopy.copyFrom(secondTrack, true); - secondTrackCopy.reverseTrackStates(true); - - firstState.previous() = (*std::next(secondTrackCopy.trackStatesReversed().begin())).index(); - Acts::calculateTrackQuantities(trackCandidate); - auto secondExtrapolationResult = Acts::extrapolateTrackToReferenceSurface( - trackCandidate, *pSurface, extrapolator, - extrapolationOptions, extrapolationStrategy); - if (!secondExtrapolationResult.ok()) - { - m_nFailedExtrapolation++; - debug() << "Second extrapolation for seed " - << iSeed << " and track " << secondTrack.index() - << " failed with error " - << secondExtrapolationResult.error() << endmsg; - continue; - } - - addTrack(trackCandidate); - - ++nSecond; - } - - firstState.previous() = Acts::kTrackIndexInvalid; - Acts::calculateTrackQuantities(trackCandidate); - } - } - } - - // if no second track was found, we will use only the first track - if (nSecond == 0) { - auto firstExtrapolationResult = Acts::extrapolateTrackToReferenceSurface( - trackCandidate, *pSurface, extrapolator, extrapolationOptions, extrapolationStrategy); - - if (!firstExtrapolationResult.ok()) - { - m_nFailedExtrapolation++; - continue; - } - - addTrack(trackCandidate); - } - } - } - - chronoStatSvc->chronoStop("ckf_findTracks"); - debug() << "CKF found " << tracks.size() << " tracks for event " << _nEvt << "!" << endmsg; - - m_memoryStatistics.local().hist += tracks.trackStateContainer().statistics().hist; - auto constTrackStateContainer = std::make_shared<Acts::ConstVectorMultiTrajectory>(std::move(*trackStateContainer)); - auto constTrackContainer = std::make_shared<Acts::ConstVectorTrackContainer>(std::move(*trackContainer)); - ConstTrackContainer constTracks{constTrackContainer, constTrackStateContainer}; - - chronoStatSvc->chronoStart("writeout tracks"); - - if (constTracks.size() == 0) { - chronoStatSvc->chronoStop("writeout tracks"); - _nEvt++; - return StatusCode::SUCCESS; - } - for (const auto& cur_track : constTracks) - { - auto writeout_track = trkCol->create(); - int nVTXHit = 0, nFTDHit = 0, nSITHit = 0, nlayerHits = 9; - int getFirstHit = 0; - - writeout_track.setChi2(cur_track.chi2()); - writeout_track.setNdf(cur_track.nDoF()); - writeout_track.setDEdx(cur_track.absoluteMomentum() / Acts::UnitConstants::GeV); - // writeout_track.setDEdxError(cur_track.qOverP()); - std::array<int, 6> nlayer_VTX{0, 0, 0, 0, 0, 0}; - std::array<int, 3> nlayer_SIT{0, 0, 0}; - std::array<int, 3> nlayer_FTD{0, 0, 0}; - - for (auto trackState : cur_track.trackStates()) - { - if (trackState.hasUncalibratedSourceLink()) - { - auto cur_measurement_sl = trackState.getUncalibratedSourceLink(); - const auto& MeasSourceLink = cur_measurement_sl.get<IndexSourceLink>(); - auto cur_measurement = measurements[MeasSourceLink.index()]; - auto cur_measurement_gid = MeasSourceLink.geometryId(); - - for (int i = 0; i < 5; i++) - { - if (cur_measurement_gid.volume() == VXD_volume_ids[i]) - { - if (i == 4){ - if (cur_measurement_gid.sensitive() & 1 == 1) - { - nlayer_VTX[5]++; - } else{ - nlayer_VTX[4]++; - } - } else { - nlayer_VTX[i]++; - } - nVTXHit++; - break; - } - } - - for (int i = 0; i < 3; i++){ - if (cur_measurement_gid.volume() == SIT_volume_ids[i]){ - nlayer_SIT[i]++; - nSITHit++; - break; - } - } - - for (int i = 0; i < 3; i++){ - if (cur_measurement_gid.volume() == FTD_positive_volume_ids[i]){ - nlayer_FTD[i]++; - nFTDHit++; - break; - } - - if (cur_measurement_gid.volume() == FTD_negative_volume_ids[i]){ - nlayer_FTD[i]++; - nFTDHit++; - break; - } - } - - writeout_track.addToTrackerHits(MeasSourceLink.getTrackerHit()); - - if (!getFirstHit){ - const auto& par = std::get<1>(cur_measurement).parameters(); - const Acts::Surface* surface = surfaceAccessor(cur_measurement_sl); - auto acts_global_postion = surface->localToGlobal(geoContext, par, globalFakeMom); - writeout_track.setRadiusOfInnermostHit( - std::sqrt(acts_global_postion[0] * acts_global_postion[0] + - acts_global_postion[1] * acts_global_postion[1] + - acts_global_postion[2] * acts_global_postion[2]) - ); - getFirstHit = 1; - } - } - } - for (int i = 0; i < 6; i++){ - m_nRec_VTX[i] += nlayer_VTX[i]; - if (nlayer_VTX[i] == 0) { - m_n0EventHits[i]++; - nlayerHits--; - } else if (nlayer_VTX[i] == 1) { - m_n1EventHits[i]++; - } else if (nlayer_VTX[i] == 2) { - m_n2EventHits[i]++; - } else if (nlayer_VTX[i] >= 3) { - m_n3EventHits[i]++; - } - } - for (int i = 0; i < 3; i++){ - m_nRec_SIT[i] += nlayer_SIT[i]; - if (nlayer_SIT[i] == 0) { - m_n0EventHits[i+6]++; - nlayerHits--; - } else if (nlayer_SIT[i] == 1) { - m_n1EventHits[i+6]++; - } else if (nlayer_SIT[i] == 2) { - m_n2EventHits[i+6]++; - } else if (nlayer_SIT[i] >= 3) { - m_n3EventHits[i+6]++; - } - } - - for (int i = 0; i < 3; i++){ - m_nRec_FTD[i] += nlayer_FTD[i]; - } - - // SubdetectorHitNumbers: VXD = 0, FTD = 1, SIT = 2 - writeout_track.setDEdxError(nlayerHits); - writeout_track.addToSubdetectorHitNumbers(nVTXHit); - writeout_track.addToSubdetectorHitNumbers(nFTDHit); - writeout_track.addToSubdetectorHitNumbers(nSITHit); - - // TODO: covmatrix need to be converted - std::array<float, 21> writeout_covMatrix; - auto cur_track_covariance = cur_track.covariance(); - for (int i = 0; i < 6; i++) { - for (int j = 0; j < 6-i; j++) { - writeout_covMatrix[int((13-i)*i/2 + j)] = cur_track_covariance(writeout_indices[i], writeout_indices[j]); - } - } - // location: At{Other|IP|FirstHit|LastHit|Calorimeter|Vertex}|LastLocation - // TrackState: location, d0, phi, omega, z0, tanLambda, time, referencePoint, covMatrix - edm4hep::TrackState writeout_trackState{ - 1, // location: AtOther - cur_track.loc0() / Acts::UnitConstants::mm, // d0 - cur_track.phi(), // phi - cur_track.qOverP() * sin(cur_track.theta()) * _FCT * m_field, // omega = qop * sin(theta) * _FCT * bf - cur_track.loc1() / Acts::UnitConstants::mm, // z0 - 1 / tan(cur_track.theta()), // tanLambda = 1 / tan(theta) - cur_track.time(), // time - ::edm4hep::Vector3f(0, 0, 0), // referencePoint - writeout_covMatrix - }; - - debug() << "Found track with momentum " << cur_track.absoluteMomentum() / Acts::UnitConstants::GeV << " !" << endmsg; - writeout_track.addToTrackStates(writeout_trackState); - } - - chronoStatSvc->chronoStop("writeout tracks"); - - _nEvt++; - return StatusCode::SUCCESS; -} - -StatusCode RecActsTracking::finalize() -{ - debug() << "finalize RecActsTracking" << endmsg; - info() << "Total number of events processed: " << _nEvt << endmsg; - info() << "Total number of **TotalSeeds** processed: " << m_nTotalSeeds << endmsg; - info() << "Total number of **FoundTracks** processed: " << m_nFoundTracks << endmsg; - info() << "Total number of **SelectedTracks** processed: " << m_nSelectedTracks << endmsg; - info() << "Total number of **LayerHits** processed: " << m_nLayerHits << endmsg; - info() << "Total number of **Rec_VTX** processed: " << m_nRec_VTX << endmsg; - info() << "Total number of **Rec_SIT** processed: " << m_nRec_SIT << endmsg; - info() << "Total number of **Rec_FTD** processed: " << m_nRec_FTD << endmsg; - info() << "Total number of **EventHits0** processed: " << m_n0EventHits << endmsg; - info() << "Total number of **EventHits1** processed: " << m_n1EventHits << endmsg; - info() << "Total number of **EventHits2** processed: " << m_n2EventHits << endmsg; - info() << "Total number of **EventHitsmore** processed: " << m_n3EventHits << endmsg; - - return GaudiAlgorithm::finalize(); -} - -int RecActsTracking::InitialiseVTX() -{ - int success = 1; - - const edm4hep::TrackerHitCollection* hitVTXCol = nullptr; - const edm4hep::SimTrackerHitCollection* SimhitVTXCol = nullptr; - - try { - hitVTXCol = _inVTXTrackHdl.get(); - } catch (GaudiException& e) { - debug() << "Collection " << _inVTXTrackHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; - success = 0; - } - - try { - SimhitVTXCol = _inVTXColHdl.get(); - } catch (GaudiException& e) { - debug() << "Sim Collection " << _inVTXColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; - success = 0; - } - - if(hitVTXCol && SimhitVTXCol) - { - int nelem = hitVTXCol->size(); - debug() << "Number of VTX hits = " << nelem << endmsg; - if ((nelem < 3) or (nelem > 10)) { success = 0; } - - // std::string truth_file = "obj/vtx/truth/event" + std::to_string(_nEvt) + ".csv"; - // std::ofstream truth_stream(truth_file); - // csv2::Writer<csv2::delimiter<','>> truth_writer(truth_stream); - // std::vector<std::string> truth_header = {"layer", "x", "y", "z"}; - // truth_writer.write_row(truth_header); - - // std::string converted_file = "obj/vtx/converted/event" + std::to_string(_nEvt) + ".csv"; - // std::ofstream converted_stream(converted_file); - // csv2::Writer<csv2::delimiter<','>> converted_writer(converted_stream); - // std::vector<std::string> converted_header = {"layer", "x", "y", "z"}; - // converted_writer.write_row(converted_header); - - for (int ielem = 0; ielem < nelem; ++ielem) - { - auto hit = hitVTXCol->at(ielem); - auto simhit = SimhitVTXCol->at(ielem); - - auto simcellid = simhit.getCellID(); - // system:5,side:-2,layer:9,module:8,sensor:32:8 - uint64_t m_layer = vxd_decoder->get(simcellid, "layer"); - uint64_t m_module = vxd_decoder->get(simcellid, "module"); - uint64_t m_sensor = vxd_decoder->get(simcellid, "sensor"); - double acts_x = simhit.getPosition()[0]; - double acts_y = simhit.getPosition()[1]; - double acts_z = simhit.getPosition()[2]; - - double momentum_x = simhit.getMomentum()[0]; - double momentum_y = simhit.getMomentum()[1]; - double momentum_z = simhit.getMomentum()[2]; - - const Acts::Vector3 globalmom{momentum_x, momentum_y, momentum_z}; - std::array<float, 6> m_covMatrix = hit.getCovMatrix(); - - dd4hep::rec::ISurface* surface = nullptr; - auto it = m_vtx_surfaces->find(simcellid); - if (it != m_vtx_surfaces->end()) { - surface = it->second; - if (!surface) { - fatal() << "found surface for VTX cell id " << simcellid << ", but NULL" << endmsg; - return 0; - } - } - else { - fatal() << "not found surface for VTX cell id " << simcellid << endmsg; - return 0; - } - - // dd4hep::rec::Vector3D oldPos(simhit.getPosition()[0]*dd4hep::mm/CLHEP::mm, simhit.getPosition()[1]*dd4hep::mm/CLHEP::mm, simhit.getPosition()[2]*dd4hep::mm/CLHEP::mm); - // dd4hep::rec::Vector2D localPoint = surface->globalToLocal(oldPos); - - // if (m_layer < current_layer){ - // info() << "ring hits happend in layer " << m_layer << " before layer " << current_layer << ", at event " << _nEvt << endmsg; - // success = 0; - // break; - // } - // current_layer = m_layer; - - if (m_layer <= 3){ - // set acts geometry identifier - uint64_t acts_volume = VXD_volume_ids[m_layer]; - uint64_t acts_boundary = 0; - uint64_t acts_layer = 2; - uint64_t acts_approach = 0; - // uint64_t acts_sensitive = m_module + 1; - uint64_t acts_sensitive = 1; - - Acts::GeometryIdentifier moduleGeoId; - moduleGeoId.setVolume(acts_volume); - moduleGeoId.setBoundary(acts_boundary); - moduleGeoId.setLayer(acts_layer); - moduleGeoId.setApproach(acts_approach); - moduleGeoId.setSensitive(acts_sensitive); - - // create and store the source link - uint32_t measurementIdx = measurements.size(); - IndexSourceLink sourceLink{moduleGeoId, measurementIdx, hit}; - sourceLinks.insert(sourceLinks.end(), sourceLink); - Acts::SourceLink sl{sourceLink}; - boost::container::static_vector<Acts::SourceLink, 2> slinks; - slinks.emplace_back(sl); - - // get the surface of the hit - IndexSourceLink::SurfaceAccessor surfaceAccessor{*trackingGeometry}; - const Acts::Surface* acts_surface = surfaceAccessor(sl); - - // get the local position of the hit - const Acts::Vector3 globalPos{acts_x, acts_y, acts_z}; - auto acts_local_postion = acts_surface->globalToLocal(geoContext, globalPos, globalmom, onSurfaceTolerance); - if (!acts_local_postion.ok()){ - info() << "Error: failed to get local position for VTX hit " << simcellid << endmsg; - acts_local_postion = acts_surface->globalToLocal(geoContext, globalPos, globalmom, 100*onSurfaceTolerance); - } - const std::array<Acts::BoundIndices, 2> indices{Acts::BoundIndices::eBoundLoc0, Acts::BoundIndices::eBoundLoc1}; - const Acts::Vector2 par{acts_local_postion.value()[0], acts_local_postion.value()[1]}; - - // *** debug *** - debug() << "VXD measurements global position(x,y,z): " << simhit.getPosition()[0] << ", " << simhit.getPosition()[1] << ", " << simhit.getPosition()[2] - << "; local position(loc0, loc1): "<< acts_local_postion.value()[0] << ", " << acts_local_postion.value()[1] << endmsg; - auto acts_global_postion = acts_surface->localToGlobal(geoContext, par, globalFakeMom); - debug() << "debug surface at: x:" << acts_global_postion[0] << ", y:" << acts_global_postion[1] << ", z:" << acts_global_postion[2] << endmsg; - - // SimSpacePoint *hitExt = new SimSpacePoint(hit, simhit, slinks); - SimSpacePoint *hitExt = new SimSpacePoint(hit, acts_global_postion[0], acts_global_postion[1], acts_global_postion[2], 0.002, slinks); - // debug() << "debug hitExt at: x:" << hitExt->x() << ", y:" << hitExt->y() << ", z:" << hitExt->z() << endmsg; - SpacePointPtrs.push_back(hitExt); - - // create and store the measurement - // Cylinder covMatrix[6] = {resU*resU/2, 0, resU*resU/2, 0, 0, resV*resV} - Acts::ActsSquareMatrix<2> cov = Acts::ActsSquareMatrix<2>::Identity(); - cov(0, 0) = std::max<double>(double(std::sqrt(m_covMatrix[2]*2)), eps.value()); - cov(1, 1) = std::max<double>(double(std::sqrt(m_covMatrix[5])), eps.value()); - measurements.emplace_back(Acts::Measurement<Acts::BoundIndices, 2>(sl, indices, par, cov)); - - // std::vector<std::string> truth_col = {std::to_string(m_layer*2 + m_module), std::to_string(simhit.getPosition()[0]), std::to_string(simhit.getPosition()[1]), std::to_string(simhit.getPosition()[2])}; - // truth_writer.write_row(truth_col); - // std::vector<std::string> converted_col = {std::to_string(m_layer*2 + m_module), std::to_string(acts_global_postion[0]), std::to_string(acts_global_postion[1]), std::to_string(acts_global_postion[2])}; - // converted_writer.write_row(converted_col); - - } else { - // set acts geometry identifier - uint64_t acts_volume = VXD_volume_ids[4]; - uint64_t acts_boundary = 0; - uint64_t acts_layer = 2; - uint64_t acts_approach = 0; - uint64_t acts_sensitive = (m_layer == 5) ? m_module*2 + 1 : m_module*2 + 2; - - Acts::GeometryIdentifier moduleGeoId; - moduleGeoId.setVolume(acts_volume); - moduleGeoId.setBoundary(acts_boundary); - moduleGeoId.setLayer(acts_layer); - moduleGeoId.setApproach(acts_approach); - moduleGeoId.setSensitive(acts_sensitive); - - // create and store the source link - uint32_t measurementIdx = measurements.size(); - IndexSourceLink sourceLink{moduleGeoId, measurementIdx, hit}; - sourceLinks.insert(sourceLinks.end(), sourceLink); - Acts::SourceLink sl{sourceLink}; - boost::container::static_vector<Acts::SourceLink, 2> slinks; - slinks.emplace_back(sl); - - // get the local position of the hit - IndexSourceLink::SurfaceAccessor surfaceAccessor{*trackingGeometry}; - const Acts::Surface* acts_surface = surfaceAccessor(sl); - const Acts::Vector3 globalPos{acts_x, acts_y, acts_z}; - auto acts_local_postion = acts_surface->globalToLocal(geoContext, globalPos, globalmom, onSurfaceTolerance); - if (!acts_local_postion.ok()){ - info() << "Error: failed to get local position for VTX hit " << simcellid << endmsg; - acts_local_postion = acts_surface->globalToLocal(geoContext, globalPos, globalmom, 100*onSurfaceTolerance); - } - const std::array<Acts::BoundIndices, 2> indices{Acts::BoundIndices::eBoundLoc0, Acts::BoundIndices::eBoundLoc1}; - const Acts::Vector2 par{acts_local_postion.value()[0], acts_local_postion.value()[1]}; - - // *** debug *** - debug() << "VXD measurements global position(x,y,z): " << simhit.getPosition()[0] << ", " << simhit.getPosition()[1] << ", " << simhit.getPosition()[2] - << "; local position(loc0, loc1): "<< acts_local_postion.value()[0] << ", " << acts_local_postion.value()[1] << endmsg; - auto acts_global_postion = acts_surface->localToGlobal(geoContext, par, globalFakeMom); - debug() << "debug surface at: x:" << acts_global_postion[0] << ", y:" << acts_global_postion[1] << ", z:" << acts_global_postion[2] << endmsg; - - if (ExtendSeedRange.value()) { - SimSpacePoint *hitExt = new SimSpacePoint(hit, acts_global_postion[0], acts_global_postion[1], acts_global_postion[2], 0.002, slinks); - SpacePointPtrs.push_back(hitExt); - } - - // create and store the measurement - // Plane covMatrix[6] = {u_direction[0], u_direction[1], resU, v_direction[0], v_direction[1], resV} - Acts::ActsSquareMatrix<2> cov = Acts::ActsSquareMatrix<2>::Identity(); - cov(0, 0) = std::max<double>(double(m_covMatrix[2]), eps.value()); - cov(1, 1) = std::max<double>(double(m_covMatrix[5]), eps.value()); - measurements.emplace_back(Acts::Measurement<Acts::BoundIndices, 2>(sl, indices, par, cov)); - - // std::vector<std::string> truth_col = {std::to_string(m_layer+4), std::to_string(simhit.getPosition()[0]), std::to_string(simhit.getPosition()[1]), std::to_string(simhit.getPosition()[2])}; - // truth_writer.write_row(truth_col); - // std::vector<std::string> converted_col = {std::to_string(m_layer+4), std::to_string(acts_global_postion[0]), std::to_string(acts_global_postion[1]), std::to_string(acts_global_postion[2])}; - // converted_writer.write_row(converted_col); - } - } - } else { success = 0; } - - return success; -} - -int RecActsTracking::InitialiseSIT() -{ - int success = 1; - - const edm4hep::TrackerHitCollection* hitSITCol = nullptr; - const edm4hep::SimTrackerHitCollection* SimhitSITCol = nullptr; - - double min_z = 0; - try { - hitSITCol = _inSITTrackHdl.get(); - } catch (GaudiException& e) { - debug() << "Collection " << _inSITTrackHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; - success = 0; - } - - try { - SimhitSITCol = _inSITColHdl.get(); - } catch (GaudiException& e) { - debug() << "Sim Collection " << _inSITColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; - success = 0; - } - - if(hitSITCol && SimhitSITCol) - { - int nelem = hitSITCol->size(); - debug() << "Number of SIT hits = " << nelem << endmsg; - // SpacePointPtrs.resize(nelem); - - // std::string truth_file = "obj/sit/truth/event" + std::to_string(_nEvt) + ".csv"; - // std::ofstream truth_stream(truth_file); - // csv2::Writer<csv2::delimiter<','>> truth_writer(truth_stream); - // std::vector<std::string> truth_header = {"layer", "x", "y", "z"}; - // truth_writer.write_row(truth_header); - - // std::string converted_file = "obj/sit/converted/event" + std::to_string(_nEvt) + ".csv"; - // std::ofstream converted_stream(converted_file); - // csv2::Writer<csv2::delimiter<','>> converted_writer(converted_stream); - // std::vector<std::string> converted_header = {"layer", "x", "y", "z"}; - // converted_writer.write_row(converted_header); - - for (int ielem = 0; ielem < nelem; ++ielem) - { - auto hit = hitSITCol->at(ielem); - auto simhit = SimhitSITCol->at(ielem); - - auto simcellid = simhit.getCellID(); - // <id>system:5,side:-2,layer:9,stave:8,module:8,sensor:5,y:-11,z:-11</id> - uint64_t m_layer = sit_decoder->get(simcellid, "layer"); - uint64_t m_stave = sit_decoder->get(simcellid, "stave"); - uint64_t m_module = sit_decoder->get(simcellid, "module"); - uint64_t m_sensor = sit_decoder->get(simcellid, "sensor"); - double acts_x = simhit.getPosition()[0]; - double acts_y = simhit.getPosition()[1]; - double acts_z = simhit.getPosition()[2]; - double momentum_x = simhit.getMomentum()[0]; - double momentum_y = simhit.getMomentum()[1]; - double momentum_z = simhit.getMomentum()[2]; - const Acts::Vector3 globalmom{momentum_x, momentum_y, momentum_z}; - std::array<float, 6> m_covMatrix = hit.getCovMatrix(); - - dd4hep::rec::ISurface* surface = nullptr; - auto it = m_sit_surfaces->find(simcellid); - if (it != m_sit_surfaces->end()) { - surface = it->second; - if (!surface) { - fatal() << "found surface for SIT cell id " << simcellid << ", but NULL" << endmsg; - return 0; - } - } - else { - fatal() << "not found surface for SIT cell id " << simcellid << endmsg; - return 0; - } - - // set acts geometry identifier - uint64_t acts_volume = SIT_volume_ids[m_layer]; - uint64_t acts_boundary = 0; - uint64_t acts_layer = 2; - uint64_t acts_approach = 0; - uint64_t acts_sensitive = m_stave*SIT_module_nums[m_layer] + m_module + 1; - - Acts::GeometryIdentifier moduleGeoId; - moduleGeoId.setVolume(acts_volume); - moduleGeoId.setBoundary(acts_boundary); - moduleGeoId.setLayer(acts_layer); - moduleGeoId.setApproach(acts_approach); - moduleGeoId.setSensitive(acts_sensitive); - - // create and store the source link - uint32_t measurementIdx = measurements.size(); - IndexSourceLink sourceLink{moduleGeoId, measurementIdx, hit}; - sourceLinks.insert(sourceLinks.end(), sourceLink); - Acts::SourceLink sl{sourceLink}; - boost::container::static_vector<Acts::SourceLink, 2> slinks; - slinks.emplace_back(sl); - - // get the local position of the hit - IndexSourceLink::SurfaceAccessor surfaceAccessor{*trackingGeometry}; - const Acts::Surface* acts_surface = surfaceAccessor(sl); - const Acts::Vector3 globalPos{acts_x, acts_y, acts_z}; - auto acts_local_postion = acts_surface->globalToLocal(geoContext, globalPos, globalmom, onSurfaceTolerance); - if (!acts_local_postion.ok()){ - info() << "Error: failed to get local position for SIT hit " << simcellid << endmsg; - acts_local_postion = acts_surface->globalToLocal(geoContext, globalPos, globalmom, 100*onSurfaceTolerance); - } - const std::array<Acts::BoundIndices, 2> indices{Acts::BoundIndices::eBoundLoc0, Acts::BoundIndices::eBoundLoc1}; - const Acts::Vector2 par{acts_local_postion.value()[0], acts_local_postion.value()[1]}; - - // *** debug *** - debug() << "SIT measurements global position(x,y,z): " << simhit.getPosition()[0] << ", " << simhit.getPosition()[1] << ", " << simhit.getPosition()[2] - << "; local position(loc0, loc1): "<< acts_local_postion.value()[0] << ", " << acts_local_postion.value()[1] << endmsg; - auto acts_global_postion = acts_surface->localToGlobal(geoContext, par, globalFakeMom); - debug() << "debug surface at: x:" << acts_global_postion[0] << ", y:" << acts_global_postion[1] << ", z:" << acts_global_postion[2] << endmsg; - - if (ExtendSeedRange.value()) { - SimSpacePoint *hitExt = new SimSpacePoint(hit, acts_global_postion[0], acts_global_postion[1], acts_global_postion[2], 0.002, slinks); - SpacePointPtrs.push_back(hitExt); - } - - // create and store the measurement - Acts::ActsSquareMatrix<2> cov = Acts::ActsSquareMatrix<2>::Identity(); - cov(0, 0) = std::max<double>(double(m_covMatrix[2]), eps.value()); - cov(1, 1) = std::max<double>(double(m_covMatrix[5]), eps.value()); - measurements.emplace_back(Acts::Measurement<Acts::BoundIndices, 2>(sl, indices, par, cov)); - - // std::vector<std::string> truth_col = {std::to_string(m_layer), std::to_string(simhit.getPosition()[0]), std::to_string(simhit.getPosition()[1]), std::to_string(simhit.getPosition()[2])}; - // truth_writer.write_row(truth_col); - // std::vector<std::string> converted_col = {std::to_string(m_layer), std::to_string(acts_global_postion[0]), std::to_string(acts_global_postion[1]), std::to_string(acts_global_postion[2])}; - // converted_writer.write_row(converted_col); - } - } else { success = 0; } - - return success; -} - -int RecActsTracking::InitialiseFTD() -{ - const edm4hep::TrackerHitCollection* hitFTDCol = nullptr; - const edm4hep::SimTrackerHitCollection* SimhitFTDCol = nullptr; - - try { - hitFTDCol = _inFTDTrackHdl.get(); - } catch (GaudiException& e) { - debug() << "Collection " << _inFTDTrackHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; - return 0; - } - - try { - SimhitFTDCol = _inFTDColHdl.get(); - } catch (GaudiException& e) { - debug() << "Collection " << _inFTDColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; - return 0; - } - - if (hitFTDCol && SimhitFTDCol) - { - int nelem = hitFTDCol->size(); - debug() << "Number of FTD hits = " << nelem << endmsg; - for (int ielem = 0; ielem < nelem; ++ielem) - { - auto hit = hitFTDCol->at(ielem); - auto simhit = SimhitFTDCol->at(ielem); - auto simcellid = simhit.getCellID(); - uint64_t m_system = ftd_decoder->get(simcellid, "system"); - uint64_t m_side = ftd_decoder->get(simcellid, "side"); - uint64_t m_layer = ftd_decoder->get(simcellid, "layer"); - uint64_t m_module = ftd_decoder->get(simcellid, "module"); - uint64_t m_sensor = ftd_decoder->get(simcellid, "sensor"); - double acts_x = simhit.getPosition()[0]; - double acts_y = simhit.getPosition()[1]; - double acts_z = simhit.getPosition()[2]; - double momentum_x = simhit.getMomentum()[0]; - double momentum_y = simhit.getMomentum()[1]; - double momentum_z = simhit.getMomentum()[2]; - const Acts::Vector3 globalmom{momentum_x, momentum_y, momentum_z}; - std::array<float, 6> m_covMatrix = hit.getCovMatrix(); - - if (m_layer > 2) { - continue; - } - - dd4hep::rec::ISurface* surface = nullptr; - auto it = m_ftd_surfaces->find(simcellid); - if (it != m_ftd_surfaces->end()) { - surface = it->second; - if (!surface) { - fatal() << "found surface for FTD cell id " << simcellid << ", but NULL" << endmsg; - return 0; - } - } - - // set acts geometry identifier - uint64_t acts_volume = (acts_z > 0) ? FTD_positive_volume_ids[m_layer] : FTD_negative_volume_ids[m_layer]; - uint64_t acts_boundary = 0; - uint64_t acts_layer = 2; - uint64_t acts_approach = 0; - uint64_t acts_sensitive = m_module + 1; - - Acts::GeometryIdentifier moduleGeoId; - moduleGeoId.setVolume(acts_volume); - moduleGeoId.setBoundary(acts_boundary); - moduleGeoId.setLayer(acts_layer); - moduleGeoId.setApproach(acts_approach); - moduleGeoId.setSensitive(acts_sensitive); - - // create and store the source link - uint32_t measurementIdx = measurements.size(); - IndexSourceLink sourceLink{moduleGeoId, measurementIdx, hit}; - sourceLinks.insert(sourceLinks.end(), sourceLink); - Acts::SourceLink sl{sourceLink}; - boost::container::static_vector<Acts::SourceLink, 2> slinks; - slinks.emplace_back(sl); - - // get the local position of the hit - IndexSourceLink::SurfaceAccessor surfaceAccessor{*trackingGeometry}; - const Acts::Surface* acts_surface = surfaceAccessor(sl); - const Acts::Vector3 globalPos{acts_x, acts_y, acts_z}; - auto acts_local_postion = acts_surface->globalToLocal(geoContext, globalPos, globalmom, onSurfaceTolerance); - if (!acts_local_postion.ok()){ - info() << "Error: failed to get local position for FTD layer " << m_layer << " module " << m_module << " sensor " << m_sensor << endmsg; - acts_local_postion = acts_surface->globalToLocal(geoContext, globalPos, globalmom, 100*onSurfaceTolerance); - } - const std::array<Acts::BoundIndices, 2> indices{Acts::BoundIndices::eBoundLoc0, Acts::BoundIndices::eBoundLoc1}; - const Acts::Vector2 par{acts_local_postion.value()[0], acts_local_postion.value()[1]}; - - // debug - debug() << "FTD measurements global position(x,y,z): " << simhit.getPosition()[0] << ", " << simhit.getPosition()[1] << ", " << simhit.getPosition()[2] - << "; local position(loc0, loc1): "<< acts_local_postion.value()[0] << ", " << acts_local_postion.value()[1] << endmsg; - auto acts_global_postion = acts_surface->localToGlobal(geoContext, par, globalFakeMom); - debug() << "debug surface at: x:" << acts_global_postion[0] << ", y:" << acts_global_postion[1] << ", z:" << acts_global_postion[2] << endmsg; - - if (ExtendSeedRange.value()) { - SimSpacePoint *hitExt = new SimSpacePoint(hit, acts_global_postion[0], acts_global_postion[1], acts_global_postion[2], 0.002, slinks); - SpacePointPtrs.push_back(hitExt); - } - - // create and store the measurement - Acts::ActsSquareMatrix<2> cov = Acts::ActsSquareMatrix<2>::Identity(); - cov(0, 0) = std::max<double>(double(m_covMatrix[2]), eps.value()); - cov(1, 1) = std::max<double>(double(m_covMatrix[5]), eps.value()); - measurements.emplace_back(Acts::Measurement<Acts::BoundIndices, 2>(sl, indices, par, cov)); - } - } - - return 1; -} \ No newline at end of file diff --git a/Reconstruction/RecActsTracking/src/RecActsTracking.h b/Reconstruction/RecActsTracking/src/RecActsTracking.h deleted file mode 100644 index f7d44417..00000000 --- a/Reconstruction/RecActsTracking/src/RecActsTracking.h +++ /dev/null @@ -1,320 +0,0 @@ -#ifndef RecActsTracking_H -#define RecActsTracking_H - -#include <iostream> -#include <fstream> -#include <cstdlib> -#include <sstream> -#include <filesystem> - -#include "k4FWCore/DataHandle.h" -#include "GaudiAlg/GaudiAlgorithm.h" -#include "DD4hep/Detector.h" -#include "DDRec/DetectorData.h" -#include "DDRec/ISurface.h" -#include "DDRec/SurfaceManager.h" -#include "DDRec/Vector3D.h" - -#include "UTIL/ILDConf.h" -#include "GaudiKernel/NTuple.h" -#include "DetInterface/IGeomSvc.h" - -// gear -#include "GearSvc/IGearSvc.h" -#include <gear/GEAR.h> -#include <gear/GearMgr.h> -#include <gear/GearParameters.h> -#include <gear/VXDLayerLayout.h> -#include <gear/VXDParameters.h> -#include "gear/FTDLayerLayout.h" -#include "gear/FTDParameters.h" -#include <gear/BField.h> - -// edm4hep -#include "edm4hep/MCParticle.h" -#include "edm4hep/Track.h" -#include "edm4hep/MutableTrack.h" -// #include "edm4hep/TrackerHit.h" -// #include "edm4hep/SimTrackerHit.h" -#include "edm4hep/TrackState.h" -#include "edm4hep/EventHeaderCollection.h" -#include "edm4hep/MCParticleCollection.h" -#include "edm4hep/SimTrackerHitCollection.h" -#include "edm4hep/TrackerHitCollection.h" -#include "edm4hep/TrackCollection.h" -#include "edm4hep/MCRecoTrackerAssociationCollection.h" - -// acts -#include "Acts/Definitions/Algebra.hpp" -#include "Acts/Definitions/Direction.hpp" -#include "Acts/Definitions/TrackParametrization.hpp" - -#include "Acts/EventData/MultiTrajectory.hpp" -#include "Acts/EventData/ProxyAccessor.hpp" -#include "Acts/EventData/SpacePointData.hpp" -#include <Acts/EventData/Measurement.hpp> -#include "Acts/EventData/TrackParameters.hpp" -#include "Acts/EventData/TrackContainer.hpp" -#include "Acts/EventData/VectorMultiTrajectory.hpp" -#include "Acts/EventData/VectorTrackContainer.hpp" -#include "Acts/EventData/ParticleHypothesis.hpp" - -#include "Acts/Propagator/AbortList.hpp" -#include "Acts/Propagator/EigenStepper.hpp" -#include "Acts/Propagator/MaterialInteractor.hpp" -#include "Acts/Propagator/Navigator.hpp" -#include "Acts/Propagator/Propagator.hpp" -#include "Acts/Propagator/StandardAborters.hpp" - -#include "Acts/Geometry/Extent.hpp" -#include "Acts/Geometry/GeometryIdentifier.hpp" -#include <Acts/Geometry/GeometryContext.hpp> - -#include "Acts/Seeding/BinnedGroup.hpp" -#include "Acts/Seeding/EstimateTrackParamsFromSeed.hpp" -#include "Acts/Seeding/InternalSpacePoint.hpp" -#include "Acts/Seeding/SeedFilter.hpp" -#include "Acts/Seeding/SeedFilterConfig.hpp" -#include "Acts/Seeding/SeedFinder.hpp" -#include "Acts/Seeding/SeedFinderConfig.hpp" -#include "Acts/Seeding/SpacePointGrid.hpp" - -#include "Acts/TrackFinding/CombinatorialKalmanFilter.hpp" -#include "Acts/TrackFitting/GainMatrixSmoother.hpp" -#include "Acts/TrackFitting/GainMatrixUpdater.hpp" -#include "Acts/TrackFitting/KalmanFitter.hpp" - -#include "Acts/Surfaces/PerigeeSurface.hpp" -#include "Acts/Surfaces/Surface.hpp" - -#include "Acts/Utilities/BinningType.hpp" -#include "Acts/Utilities/Delegate.hpp" -#include "Acts/Utilities/Grid.hpp" -#include "Acts/Utilities/GridBinFinder.hpp" -#include "Acts/Utilities/Helpers.hpp" -#include "Acts/Utilities/Logger.hpp" -#include "Acts/Utilities/Enumerate.hpp" -#include "Acts/Utilities/TrackHelpers.hpp" - -// local include -#include "utils/TGeoDetector.hpp" -#include "utils/CKFhelper.hpp" -#include "utils/MagneticField.hpp" - -namespace gear{ - class GearMgr; -} - -namespace dd4hep { - namespace DDSegmentation { - class BitFieldCoder; - } - namespace rec{ - class ISurface; - } -} - -// Seeding: Construct track seeds from space points. -// config for seed finding -struct SeedingConfig -{ - /// Input space point collections. - /// - /// We allow multiple space point collections to allow different parts of - /// the detector to use different algorithms for space point construction, - /// e.g. single-hit space points for pixel-like detectors or double-hit - /// space points for strip-like detectors. - std::vector<std::string> inputSpacePoints; - - /// Output track seed collection. - std::string outputSeeds; - - - Acts::SeedFilterConfig seedFilterConfig; - Acts::SeedFinderConfig<SimSpacePoint> seedFinderConfig; - Acts::CylindricalSpacePointGridConfig gridConfig; - Acts::CylindricalSpacePointGridOptions gridOptions; - Acts::SeedFinderOptions seedFinderOptions; - - // allow for different values of rMax in gridConfig and seedFinderConfig - bool allowSeparateRMax = false; - - // vector containing the map of z bins in the top and bottom layers - std::vector<std::pair<int, int>> zBinNeighborsTop; - std::vector<std::pair<int, int>> zBinNeighborsBottom; - - // number of phiBin neighbors at each side of the current bin that will be - // used to search for SPs - int numPhiNeighbors = 1; -}; - -class RecActsTracking : public GaudiAlgorithm -{ - - public : - - RecActsTracking(const std::string& name, ISvcLocator* svcLoc); - - virtual StatusCode initialize(); - - virtual StatusCode execute(); - - virtual StatusCode finalize(); - - private : - - // Input collections - DataHandle<edm4hep::TrackerHitCollection> _inVTXTrackHdl{"VXDTrackerHits", Gaudi::DataHandle::Reader, this}; - DataHandle<edm4hep::TrackerHitCollection> _inSITTrackHdl{"SITTrackerHits", Gaudi::DataHandle::Reader, this}; - DataHandle<edm4hep::TrackerHitCollection> _inFTDTrackHdl{"FTDTrackerHits", Gaudi::DataHandle::Reader, this}; - - DataHandle<edm4hep::SimTrackerHitCollection> _inVTXColHdl{"VXDCollection", Gaudi::DataHandle::Reader, this}; - DataHandle<edm4hep::SimTrackerHitCollection> _inSITColHdl{"SITCollection", Gaudi::DataHandle::Reader, this}; - DataHandle<edm4hep::SimTrackerHitCollection> _inFTDColHdl{"FTDCollection", Gaudi::DataHandle::Reader, this}; - - DataHandle<edm4hep::MCParticleCollection> _inMCColHdl{"MCParticle", Gaudi::DataHandle::Reader, this}; - - // Output collections - DataHandle<edm4hep::TrackCollection> _outColHdl{"ACTSSiTracks", Gaudi::DataHandle::Writer, this}; - - // properties - Gaudi::Property<std::string> TGeo_path{this, "TGeoFile"}; - Gaudi::Property<std::string> TGeo_config_path{this, "TGeoConfigFile"}; - Gaudi::Property<std::string> MaterialMap_path{this, "MaterialMapFile"}; - Gaudi::Property<std::string> m_particle{this, "AssumeParticle"}; - Gaudi::Property<double> m_field{this, "Field", 3.0}; // tesla - Gaudi::Property<double> onSurfaceTolerance{this, "onSurfaceTolerance", 1e-2}; // mm - Gaudi::Property<double> eps{this, "eps", 1e-5}; // mm - Gaudi::Property<bool> ExtendSeedRange{this, "ExtendSeedRange", false}; - - // seed finder config - Gaudi::Property<double> SeedDeltaRMin{this, "SeedDeltaRMin", 4}; // mm - Gaudi::Property<double> SeedDeltaRMax{this, "SeedDeltaRMax", 13}; // mm - Gaudi::Property<double> SeedRMax{this, "SeedRMax", 30}; // mm - Gaudi::Property<double> SeedRMin{this, "SeedRMin", 10}; // mm - Gaudi::Property<double> SeedImpactMax{this, "SeedImpactMax", 3}; // mm - Gaudi::Property<double> SeedRMinMiddle{this, "SeedRMinMiddle", 14}; // mm - Gaudi::Property<double> SeedRMaxMiddle{this, "SeedRMaxMiddle", 24}; // mm - Gaudi::Property<std::vector<double>> initialVarInflation{this, "initialVarInflation", {1, 1, 20, 20, 20, 20}}; - - // CKF config - Gaudi::Property<double> CKFchi2Cut{this, "CKFchi2Cut", std::numeric_limits<double>::max()}; - Gaudi::Property<std::size_t> numMeasurementsCutOff{this, "numMeasurementsCutOff", 1u}; - Gaudi::Property<bool> CKFtwoWay{this, "CKFtwoWay", true}; - - SmartIF<IGeomSvc> m_geosvc; - SmartIF<IChronoStatSvc> chronoStatSvc; - dd4hep::DDSegmentation::BitFieldCoder *vxd_decoder; - dd4hep::DDSegmentation::BitFieldCoder *sit_decoder; - dd4hep::DDSegmentation::BitFieldCoder *ftd_decoder; - const dd4hep::rec::SurfaceMap* m_vtx_surfaces; - const dd4hep::rec::SurfaceMap* m_sit_surfaces; - const dd4hep::rec::SurfaceMap* m_ftd_surfaces; - - // configs to build acts geometry - Acts::GeometryContext geoContext; - Acts::MagneticFieldContext magFieldContext; - Acts::CalibrationContext calibContext; - std::string TGeo_ROOTFilePath; - std::string TGeoConfig_jFilePath; - std::string MaterialMap_jFilePath; - std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry; - std::vector<std::shared_ptr<const Acts::TGeoDetectorElement>> detElementStore; - - // Store the space points & measurements & sourcelinks **per event** - // * only store the VXD tracker hits to the SpacePointPtrs - std::vector<const SimSpacePoint*> SpacePointPtrs; - IndexSourceLinkContainer sourceLinks; - std::vector<::Acts::BoundVariantMeasurement> measurements; - std::vector<::Acts::BoundTrackParameters> initialParameters; - SimSeedContainer Selected_Seeds; - - // seed finder - SeedingConfig seed_cfg; - std::unique_ptr<const Acts::GridBinFinder<2ul>> m_bottomBinFinder; - std::unique_ptr<const Acts::GridBinFinder<2ul>> m_topBinFinder; - Acts::SeedFinder<SimSpacePoint, Acts::CylindricalSpacePointGrid<SimSpacePoint>> m_seedFinder; - - int InitialiseVTX(); - int InitialiseSIT(); - int InitialiseFTD(); - const dd4hep::rec::ISurface* getISurface(edm4hep::TrackerHit* hit); - const Acts::GeometryIdentifier getVTXGid(uint64_t cellid); - const Acts::GeometryIdentifier getSITGid(uint64_t cellid); - - // utils - int _nEvt; - const double _FCT = 2.99792458E-4; - Acts::Vector3 acts_field_value = Acts::Vector3(0., 0., 3*_FCT); // tesla - // Acts::Vector3 acts_field_value = Acts::Vector3(0., 0., 3); // tesla - std::shared_ptr<const Acts::MagneticFieldProvider> magneticField - = std::make_shared<Acts::ConstantBField>(acts_field_value); - double bFieldMin = 0.3 * _FCT * Acts::UnitConstants::T; // tesla - // double bFieldMin = 0.1 * Acts::UnitConstants::T; // tesla - const Acts::Vector3 globalFakeMom{1.e6, 1.e6, 1.e6}; - const std::array<Acts::BoundIndices, 6> writeout_indices{ - Acts::BoundIndices::eBoundLoc0, Acts::BoundIndices::eBoundPhi, - Acts::BoundIndices::eBoundQOverP, Acts::BoundIndices::eBoundLoc1, - Acts::BoundIndices::eBoundTheta, Acts::BoundIndices::eBoundTime}; - - // param estimate configuration - double noTimeVarInflation = 100.; - std::array<double, 6> initialSigmas = { - 5 * Acts::UnitConstants::um, - 5 * Acts::UnitConstants::um, - 2e-2 * Acts::UnitConstants::degree, - 2e-2 * Acts::UnitConstants::degree, - 1e-1 * Acts::UnitConstants::e / Acts::UnitConstants::GeV, - 1 * Acts::UnitConstants::s}; - std::array<double, 6> initialSimgaQoverPCoefficients = { - 0 * Acts::UnitConstants::mm / (Acts::UnitConstants::e * Acts::UnitConstants::GeV), - 0 * Acts::UnitConstants::mm / (Acts::UnitConstants::e * Acts::UnitConstants::GeV), - 7.1e-2 * Acts::UnitConstants::degree / (Acts::UnitConstants::e * Acts::UnitConstants::GeV), - 2.1e-2 * Acts::UnitConstants::degree / (Acts::UnitConstants::e * Acts::UnitConstants::GeV), - 6.4e-2, - 0 * Acts::UnitConstants::ns / (Acts::UnitConstants::e * Acts::UnitConstants::GeV)}; - // std::array<double, 6> initialVarInflation = {10., 10., 10., 10., 10., 10.}; - Acts::ParticleHypothesis particleHypothesis = Acts::ParticleHypothesis::muon(); - std::array<std::string, 8> particleNames = {"muon", "pion", "electron", "kaon", "proton", "photon", "geantino", "chargedgeantino"}; - // Acts::ParticleHypothesis particleHypothesis = Acts::ParticleHypothesis::chargedGeantino(); - - // gid convert configuration - std::vector<uint64_t> VXD_volume_ids{20, 21, 22, 23, 24}; - std::vector<uint64_t> SIT_volume_ids{28, 31, 34}; - std::vector<uint64_t> FTD_positive_volume_ids{29, 32, 35}; - std::vector<uint64_t> FTD_negative_volume_ids{27, 7, 2}; - std::vector<uint64_t> SIT_module_nums{7, 10, 14}; - - // CKF configuration - // Acts::MeasurementSelector::Config measurementSelectorCfg; - std::shared_ptr<TrackFinderFunction> findTracks; - std::optional<Acts::TrackSelector> m_trackSelector; - std::optional<std::variant<Acts::TrackSelector::Config, Acts::TrackSelector::EtaBinnedConfig>> trackSelectorCfg = std::nullopt; - mutable std::atomic<std::size_t> m_nTotalSeeds{0}; - mutable std::atomic<std::size_t> m_nDeduplicatedSeeds{0}; - mutable std::atomic<std::size_t> m_nFailedSeeds{0}; - mutable std::atomic<std::size_t> m_nFailedSmoothing{0}; - mutable std::atomic<std::size_t> m_nFailedExtrapolation{0}; - mutable std::atomic<std::size_t> m_nFoundTracks{0}; - mutable std::atomic<std::size_t> m_nSelectedTracks{0}; - mutable std::atomic<std::size_t> m_nStoppedBranches{0}; - // layer hits, VXD (0-5) & SIT (6-8) - std::array<std::atomic<size_t>, 9> m_nLayerHits{0, 0, 0, 0, 0, 0, 0, 0, 0}; - std::array<std::atomic<size_t>, 6> m_nRec_VTX{0, 0, 0, 0, 0, 0}; - std::array<std::atomic<size_t>, 3> m_nRec_SIT{0, 0, 0}; - std::array<std::atomic<size_t>, 3> m_nRec_FTD{0, 0, 0}; - std::array<std::atomic<size_t>, 9> m_n0EventHits{0, 0, 0, 0, 0, 0, 0, 0, 0}; - std::array<std::atomic<size_t>, 9> m_n1EventHits{0, 0, 0, 0, 0, 0, 0, 0, 0}; - std::array<std::atomic<size_t>, 9> m_n2EventHits{0, 0, 0, 0, 0, 0, 0, 0, 0}; - std::array<std::atomic<size_t>, 9> m_n3EventHits{0, 0, 0, 0, 0, 0, 0, 0, 0}; - - mutable tbb::combinable<Acts::VectorMultiTrajectory::Statistics> m_memoryStatistics{[]() { - auto mtj = std::make_shared<Acts::VectorMultiTrajectory>(); - return mtj->statistics(); - }}; - bool twoWay = false; /// Run finding in two directions - Acts::TrackExtrapolationStrategy extrapolationStrategy = Acts::TrackExtrapolationStrategy::firstOrLast; /// Extrapolation strategy - unsigned int maxSteps = 100000; -}; - -#endif // RecActsTracking_H diff --git a/Reconstruction/RecActsTracking/src/utils/CKFhelper.hpp b/Reconstruction/RecActsTracking/src/utils/CKFhelper.hpp deleted file mode 100644 index 71dae438..00000000 --- a/Reconstruction/RecActsTracking/src/utils/CKFhelper.hpp +++ /dev/null @@ -1,388 +0,0 @@ -#include "Acts/Definitions/Algebra.hpp" -#include "Acts/Definitions/Direction.hpp" -#include "Acts/Definitions/TrackParametrization.hpp" - -#include "Acts/EventData/ProxyAccessor.hpp" -#include "Acts/EventData/TrackParameters.hpp" -#include "Acts/EventData/MultiTrajectory.hpp" -#include "Acts/EventData/SourceLink.hpp" -#include "Acts/EventData/TrackContainer.hpp" -#include "Acts/EventData/TrackProxy.hpp" -#include <Acts/EventData/Measurement.hpp> -#include "Acts/EventData/VectorMultiTrajectory.hpp" -#include "Acts/EventData/VectorTrackContainer.hpp" - -#include "ActsFatras/Digitization/Segmentizer.hpp" - -#include "Acts/Geometry/GeometryIdentifier.hpp" -#include "Acts/Geometry/TrackingGeometry.hpp" -#include "Acts/Geometry/GeometryContext.hpp" - -#include "Acts/Surfaces/PerigeeSurface.hpp" -#include "Acts/Surfaces/Surface.hpp" - -#include "Acts/Propagator/AbortList.hpp" -#include "Acts/Propagator/EigenStepper.hpp" -#include "Acts/Propagator/MaterialInteractor.hpp" -#include "Acts/Propagator/Navigator.hpp" -#include "Acts/Propagator/Propagator.hpp" -#include "Acts/Propagator/StandardAborters.hpp" - - -#include "Acts/TrackFinding/CombinatorialKalmanFilter.hpp" -#include "Acts/TrackFinding/MeasurementSelector.hpp" -#include "Acts/TrackFinding/TrackSelector.hpp" -#include "Acts/TrackFitting/GainMatrixSmoother.hpp" -#include "Acts/TrackFitting/GainMatrixUpdater.hpp" -#include "Acts/TrackFitting/KalmanFitter.hpp" - -#include "Acts/Utilities/Logger.hpp" -#include "Acts/Utilities/Result.hpp" -#include "Acts/Utilities/TrackHelpers.hpp" -#include "Acts/Utilities/Delegate.hpp" -#include "Acts/Utilities/Enumerate.hpp" -#include "Acts/Utilities/TrackHelpers.hpp" -#include "Acts/Utilities/CalibrationContext.hpp" - -#include <atomic> -#include <cstddef> -#include <functional> -#include <limits> -#include <memory> -#include <optional> -#include <string> -#include <variant> -#include <vector> -#include <cmath> -#include <ostream> -#include <stdexcept> -#include <system_error> -#include <unordered_map> -#include <utility> - -#include <tbb/combinable.h> -#include <boost/functional/hash.hpp> - -#include "SimSpacePoint.hpp" - -namespace Acts -{ - class MagneticFieldProvider; - class TrackingGeometry; -} - -using Updater = Acts::GainMatrixUpdater; -using Smoother = Acts::GainMatrixSmoother; -using Stepper = Acts::EigenStepper<>; -using Navigator = Acts::Navigator; -using Propagator = Acts::Propagator<Stepper, Navigator>; -using CKF = Acts::CombinatorialKalmanFilter<Propagator, Acts::VectorMultiTrajectory>; - -// track container types -using TrackContainer = Acts::TrackContainer<Acts::VectorTrackContainer, Acts::VectorMultiTrajectory, std::shared_ptr>; -using ConstTrackContainer = Acts::TrackContainer<Acts::ConstVectorTrackContainer, Acts::ConstVectorMultiTrajectory, std::shared_ptr>; -using TrackParameters = ::Acts::BoundTrackParameters; -using TrackParametersContainer = std::vector<TrackParameters>; -using TrackIndexType = TrackContainer::IndexType; -using TrackProxy = TrackContainer::TrackProxy; -using ConstTrackProxy = ConstTrackContainer::ConstTrackProxy; - -// track finder types -using TrackFinderOptions = Acts::CombinatorialKalmanFilterOptions<IndexSourceLinkAccessor::Iterator, Acts::VectorMultiTrajectory>; -using TrackFinderResult = Acts::Result<std::vector<TrackContainer::TrackProxy>>; - -// measurement types -using Measurement = ::Acts::BoundVariantMeasurement; -using MeasurementContainer = std::vector<Measurement>; - -class TrackFinderFunction -{ -public: - virtual ~TrackFinderFunction() = default; - virtual TrackFinderResult operator()(const TrackParameters&, const TrackFinderOptions&, TrackContainer&) const = 0; -}; - -static std::shared_ptr<TrackFinderFunction> makeTrackFinderFunction( - std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry, - std::shared_ptr<const Acts::MagneticFieldProvider> magneticField, - const Acts::Logger& logger); - -struct TrackFinderFunctionImpl : public TrackFinderFunction { - CKF trackFinder; - TrackFinderFunctionImpl(CKF&& f) : trackFinder(std::move(f)) {} - TrackFinderResult operator()( const TrackParameters& initialParameters, - const TrackFinderOptions& options, - TrackContainer& tracks) const override - { - return trackFinder.findTracks(initialParameters, options, tracks); - }; -}; - -std::shared_ptr<TrackFinderFunction> makeTrackFinderFunction( - std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry, - std::shared_ptr<const Acts::MagneticFieldProvider> magneticField) -{ - Stepper stepper(magneticField); - Navigator::Config cfg{trackingGeometry}; - cfg.resolvePassive = false; - cfg.resolveMaterial = true; - cfg.resolveSensitive = true; - Navigator navigator(cfg); - Propagator propagator(std::move(stepper), std::move(navigator)); - CKF trackFinder(std::move(propagator)); - - return std::make_shared<TrackFinderFunctionImpl>(std::move(trackFinder)); -} - -struct Cluster -{ - using Cell = ActsFatras::Segmentizer::ChannelSegment; - std::size_t sizeLoc0 = 0; - std::size_t sizeLoc1 = 0; - std::vector<Cell> channels; -}; - -using ClusterContainer = std::vector<Cluster>; - -/// Abstract base class for measurement-based calibration -class MeasurementCalibrator -{ - public: - virtual void calibrate( - const MeasurementContainer& measurements, const ClusterContainer* clusters, - const Acts::GeometryContext& gctx, const Acts::CalibrationContext& cctx, - const Acts::SourceLink& sourceLink, - Acts::VectorMultiTrajectory::TrackStateProxy& trackState) const = 0; - virtual ~MeasurementCalibrator() = default; - virtual bool needsClusters() const { return false; } -}; - -// Calibrator to convert an index source link to a measurement as-is -class PassThroughCalibrator : public MeasurementCalibrator -{ - public: - /// Find the measurement corresponding to the source link. - /// - /// @tparam parameters_t Track parameters type - /// @param gctx The geometry context (unused) - /// @param trackState The track state to calibrate - void calibrate( - const MeasurementContainer& measurements, - const ClusterContainer* clusters, const Acts::GeometryContext& gctx, - const Acts::CalibrationContext& cctx, const Acts::SourceLink& sourceLink, - Acts::VectorMultiTrajectory::TrackStateProxy& trackState) const override; -}; - -// Adapter class that wraps a MeasurementCalibrator to conform to the -// core ACTS calibration interface -class MeasurementCalibratorAdapter -{ - public: - MeasurementCalibratorAdapter(const MeasurementCalibrator& calibrator, - const MeasurementContainer& measurements, - const ClusterContainer* clusters = nullptr); - MeasurementCalibratorAdapter() = delete; - - void calibrate(const Acts::GeometryContext& gctx, - const Acts::CalibrationContext& cctx, - const Acts::SourceLink& sourceLink, - Acts::VectorMultiTrajectory::TrackStateProxy trackState) const; - - private: - const MeasurementCalibrator& m_calibrator; - const MeasurementContainer& m_measurements; - const ClusterContainer* m_clusters; -}; - -void PassThroughCalibrator::calibrate( - const MeasurementContainer& measurements, const ClusterContainer* /*clusters*/, - const Acts::GeometryContext& /*gctx*/, const Acts::CalibrationContext& /*cctx*/, - const Acts::SourceLink& sourceLink, Acts::VectorMultiTrajectory::TrackStateProxy& trackState) const -{ - trackState.setUncalibratedSourceLink(sourceLink); - const IndexSourceLink& idxSourceLink = sourceLink.get<IndexSourceLink>(); - - assert((idxSourceLink.index() < measurements.size()) && - "Source link index is outside the container bounds"); - - std::visit( - [&trackState](const auto& meas) { trackState.setCalibrated(meas); }, - measurements[idxSourceLink.index()]); -} - -MeasurementCalibratorAdapter::MeasurementCalibratorAdapter( - const MeasurementCalibrator& calibrator, const MeasurementContainer& measurements, - const ClusterContainer* clusters) : m_calibrator{calibrator}, m_measurements{measurements}, m_clusters{clusters} {} - -void MeasurementCalibratorAdapter::calibrate( - const Acts::GeometryContext& gctx, const Acts::CalibrationContext& cctx, const Acts::SourceLink& sourceLink, - Acts::VectorMultiTrajectory::TrackStateProxy trackState) const -{ - return m_calibrator.calibrate(m_measurements, m_clusters, gctx, cctx, sourceLink, trackState); -} - -// Specialize std::hash for SeedIdentifier -// This is required to use SeedIdentifier as a key in an `std::unordered_map`. -template <class T, std::size_t N> -struct std::hash<std::array<T, N>> -{ - std::size_t operator()(const std::array<T, N>& array) const - { - std::hash<T> hasher; - std::size_t result = 0; - for (auto&& element : array) { boost::hash_combine(result, hasher(element)); } - return result; - } -}; - -// Measurement selector for seed -class MeasurementSelector -{ - public: - using Traj = Acts::VectorMultiTrajectory; - explicit MeasurementSelector(Acts::MeasurementSelector selector) - : m_selector(std::move(selector)) {} - - void setSeed(const std::optional<SimSeed>& seed) { m_seed = seed; } - - Acts::Result<std::pair<std::vector<Traj::TrackStateProxy>::iterator, - std::vector<Traj::TrackStateProxy>::iterator>> - select(std::vector<Traj::TrackStateProxy>& candidates, - bool& isOutlier, const Acts::Logger& logger) const - { - if (m_seed.has_value()) - { - std::vector<Traj::TrackStateProxy> newCandidates; - for (const auto& candidate : candidates) - { - if (isSeedCandidate(candidate)) { newCandidates.push_back(candidate); } - } - - if (!newCandidates.empty()) { candidates = std::move(newCandidates); } - } - - return m_selector.select<Acts::VectorMultiTrajectory>(candidates, isOutlier, logger); - } - - private: - Acts::MeasurementSelector m_selector; - std::optional<SimSeed> m_seed; - - bool isSeedCandidate(const Traj::TrackStateProxy& candidate) const - { - assert(candidate.hasUncalibratedSourceLink()); - const Acts::SourceLink& sourceLink = candidate.getUncalibratedSourceLink(); - for (const auto& sp : m_seed->sp()) - { - for (const auto& sl : sp->sourceLinks()) - { - if (sourceLink.get<IndexSourceLink>() == sl.get<IndexSourceLink>()) { return true; } - } - } - return false; - } - -}; // class MeasurementSelector - -/// Source link indices of the bottom, middle, top measurements. -/// * In case of strip seeds only the first source link of the pair is used. -using SeedIdentifier = std::array<Index, 3>; - -/// Build a seed identifier from a seed. -/// -/// @param seed The seed to build the identifier from. -/// @return The seed identifier. -SeedIdentifier makeSeedIdentifier(const SimSeed& seed) -{ - SeedIdentifier result; - for (const auto& [i, sp] : Acts::enumerate(seed.sp())) - { - const Acts::SourceLink& firstSourceLink = sp->sourceLinks().front(); - result.at(i) = firstSourceLink.get<IndexSourceLink>().index(); - } - return result; -} - -/// Visit all possible seed identifiers of a track. -/// -/// @param track The track to visit the seed identifiers of. -/// @param visitor The visitor to call for each seed identifier. -template <typename Visitor> -void visitSeedIdentifiers(const TrackProxy& track, Visitor visitor) -{ - // first we collect the source link indices of the track states - std::vector<Index> sourceLinkIndices; - sourceLinkIndices.reserve(track.nMeasurements()); - for (const auto& trackState : track.trackStatesReversed()) - { - if (!trackState.hasUncalibratedSourceLink()) { continue; } - const Acts::SourceLink& sourceLink = trackState.getUncalibratedSourceLink(); - sourceLinkIndices.push_back(sourceLink.get<IndexSourceLink>().index()); - } - - // then we iterate over all possible triplets and form seed identifiers - for (std::size_t i = 0; i < sourceLinkIndices.size(); ++i) - { - for (std::size_t j = i + 1; j < sourceLinkIndices.size(); ++j) - { - for (std::size_t k = j + 1; k < sourceLinkIndices.size(); ++k) - { - // Putting them into reverse order (k, j, i) to compensate for the `trackStatesReversed` above. - visitor({sourceLinkIndices.at(k), sourceLinkIndices.at(j), sourceLinkIndices.at(i)}); - } - } - } -} - -class BranchStopper -{ - public: - using Config = std::optional<std::variant<Acts::TrackSelector::Config, Acts::TrackSelector::EtaBinnedConfig>>; - using BranchStopperResult = Acts::CombinatorialKalmanFilterBranchStopperResult; - - mutable std::atomic<std::size_t> m_nStoppedBranches{0}; - explicit BranchStopper(const Config& config) : m_config(config) {} - - BranchStopperResult operator()( const Acts::CombinatorialKalmanFilterTipState& tipState, - Acts::VectorMultiTrajectory::TrackStateProxy& trackState ) const - { - if (!m_config.has_value()) { return BranchStopperResult::Continue; } - - const Acts::TrackSelector::Config* singleConfig = std::visit - ( - [&](const auto& config) -> const Acts::TrackSelector::Config* - { - using T = std::decay_t<decltype(config)>; - if constexpr (std::is_same_v<T, Acts::TrackSelector::Config>) { return &config; } - else if constexpr (std::is_same_v<T, Acts::TrackSelector::EtaBinnedConfig>) - { - double theta = trackState.parameters()[Acts::eBoundTheta]; - double eta = -std::log(std::tan(0.5 * theta)); - return config.hasCuts(eta) ? &config.getCuts(eta) : nullptr; - } - }, *m_config - ); - - if (singleConfig == nullptr) - { - ++m_nStoppedBranches; - return BranchStopperResult::StopAndDrop; - } - - bool enoughMeasurements = - tipState.nMeasurements >= singleConfig->minMeasurements; - bool tooManyHoles = tipState.nHoles > singleConfig->maxHoles; - bool tooManyOutliers = tipState.nOutliers > singleConfig->maxOutliers; - - if (tooManyHoles || tooManyOutliers) { - ++m_nStoppedBranches; - return enoughMeasurements ? BranchStopperResult::StopAndKeep - : BranchStopperResult::StopAndDrop; - } - - return BranchStopperResult::Continue; - } - - private: - Config m_config; -}; \ No newline at end of file diff --git a/Reconstruction/RecActsTracking/src/utils/GeometryContainers.hpp b/Reconstruction/RecActsTracking/src/utils/GeometryContainers.hpp deleted file mode 100644 index 6d4b6dcc..00000000 --- a/Reconstruction/RecActsTracking/src/utils/GeometryContainers.hpp +++ /dev/null @@ -1,355 +0,0 @@ -// STL -#include <algorithm> -#include <cassert> -#include <cstddef> -#include <iostream> -#include <utility> -#include <iterator> - -// boost -#include <boost/container/flat_map.hpp> -#include <boost/container/flat_set.hpp> - -// acts -#include "Acts/EventData/SourceLink.hpp" -#include "Acts/Geometry/GeometryIdentifier.hpp" -#include "Acts/Surfaces/Surface.hpp" - -template <typename Iterator> -class Range -{ - public: - Range(Iterator b, Iterator e) : m_begin(b), m_end(e) {} - Range(Range&&) = default; - Range(const Range&) = default; - ~Range() = default; - Range& operator=(Range&&) = default; - Range& operator=(const Range&) = default; - - Iterator begin() const { return m_begin; } - Iterator end() const { return m_end; } - bool empty() const { return m_begin == m_end; } - std::size_t size() const { return std::distance(m_begin, m_end); } - - private: - Iterator m_begin; - Iterator m_end; -}; - -template <typename Iterator> -Range<Iterator> makeRange(Iterator begin, Iterator end) -{ return Range<Iterator>(begin, end); } - -template <typename Iterator> -Range<Iterator> makeRange(std::pair<Iterator, Iterator> range) -{ return Range<Iterator>(range.first, range.second); } - - -/// Proxy for iterating over groups of elements within a container. -/// -/// @note Each group will contain at least one element. -/// -/// Consecutive elements with the same key (as defined by the KeyGetter) are -/// placed in one group. The proxy should always be used as part of a -/// range-based for loop. In combination with structured bindings to reduce the -/// boilerplate, the group iteration can be written as -/// -/// for (auto&& [key, elements] : GroupBy<...>(...)) { -/// // do something with just the key -/// ... -/// -/// // iterate over the group elements -/// for (const auto& element : elements) { -/// ... -/// } -/// } -/// -template <typename Iterator, typename KeyGetter> -class GroupBy { - public: - /// The key type that identifies elements within a group. - using Key = std::decay_t<decltype(KeyGetter()(*Iterator()))>; - /// A Group is an iterator range with the associated key. - using Group = std::pair<Key, Range<Iterator>>; - /// Iterator type representing the end of the groups. - /// - /// The end iterator will not be dereferenced in C++17 range-based loops. It - /// can thus be a simpler type without the overhead of the full group iterator - /// below. - using GroupEndIterator = Iterator; - /// Iterator type representing a group of elements. - class GroupIterator { - public: - using iterator_category = std::input_iterator_tag; - using value_type = Group; - using difference_type = std::ptrdiff_t; - using pointer = Group*; - using reference = Group&; - - constexpr GroupIterator(const GroupBy& groupBy, Iterator groupBegin) - : m_groupBy(groupBy), - m_groupBegin(groupBegin), - m_groupEnd(groupBy.findEndOfGroup(groupBegin)) {} - /// Pre-increment operator to advance to the next group. - constexpr GroupIterator& operator++() { - // make the current end the new group beginning - std::swap(m_groupBegin, m_groupEnd); - // find the end of the next group starting from the new beginning - m_groupEnd = m_groupBy.findEndOfGroup(m_groupBegin); - return *this; - } - /// Post-increment operator to advance to the next group. - constexpr GroupIterator operator++(int) { - GroupIterator retval = *this; - ++(*this); - return retval; - } - /// Dereference operator that returns the pointed-to group of elements. - constexpr Group operator*() const { - const Key key = (m_groupBegin != m_groupEnd) - ? m_groupBy.m_keyGetter(*m_groupBegin) - : Key(); - return {key, makeRange(m_groupBegin, m_groupEnd)}; - } - - private: - const GroupBy& m_groupBy; - Iterator m_groupBegin; - Iterator m_groupEnd; - - friend constexpr bool operator==(const GroupIterator& lhs, - const GroupEndIterator& rhs) { - return lhs.m_groupBegin == rhs; - } - friend constexpr bool operator!=(const GroupIterator& lhs, - const GroupEndIterator& rhs) { - return !(lhs == rhs); - } - }; - - /// Construct the group-by proxy for an iterator range. - constexpr GroupBy(Iterator begin, Iterator end, - KeyGetter keyGetter = KeyGetter()) - : m_begin(begin), m_end(end), m_keyGetter(std::move(keyGetter)) {} - constexpr GroupIterator begin() const { - return GroupIterator(*this, m_begin); - } - constexpr GroupEndIterator end() const { return m_end; } - constexpr bool empty() const { return m_begin == m_end; } - - private: - Iterator m_begin; - Iterator m_end; - KeyGetter m_keyGetter; - - /// Find the end of the group that starts at the given position. - /// - /// This uses a linear search from the start position and thus has linear - /// complexity in the group size. It does not assume any ordering of the - /// underlying container and is a cache-friendly access pattern. - constexpr Iterator findEndOfGroup(Iterator start) const { - // check for end so we can safely dereference the start iterator. - if (start == m_end) { - return start; - } - // search the first element that does not share a key with the start. - return std::find_if_not(std::next(start), m_end, - [this, start](const auto& x) { - return m_keyGetter(x) == m_keyGetter(*start); - }); - } -}; - -/// Construct the group-by proxy for a container. -template <typename Container, typename KeyGetter> -auto makeGroupBy(const Container& container, KeyGetter keyGetter) - -> GroupBy<decltype(std::begin(container)), KeyGetter> { - return {std::begin(container), std::end(container), std::move(keyGetter)}; -} - -// extract the geometry identifier from a variety of types -struct GeometryIdGetter -{ - // explicit geometry identifier are just forwarded - constexpr Acts::GeometryIdentifier operator()( - Acts::GeometryIdentifier geometryId) const { return geometryId; } - - // encoded geometry ids are converted back to geometry identifiers. - constexpr Acts::GeometryIdentifier operator()( - Acts::GeometryIdentifier::Value encoded) const { return Acts::GeometryIdentifier(encoded); } - - // support elements in map-like structures. - template <typename T> - constexpr Acts::GeometryIdentifier operator()( - const std::pair<Acts::GeometryIdentifier, T>& mapItem) const { return mapItem.first; } - - // support elements that implement `.geometryId()`. - template <typename T> - inline auto operator()(const T& thing) const -> - decltype(thing.geometryId(), Acts::GeometryIdentifier()) { return thing.geometryId(); } - - // support reference_wrappers around such types as well - template <typename T> - inline auto operator()(std::reference_wrapper<T> thing) const -> - decltype(thing.get().geometryId(), Acts::GeometryIdentifier()) { return thing.get().geometryId(); } -}; - -struct CompareGeometryId -{ - // indicate that comparisons between keys and full objects are allowed. - using is_transparent = void; - // compare two elements using the automatic key extraction. - template <typename Left, typename Right> - constexpr bool operator()(Left&& lhs, Right&& rhs) const - { return GeometryIdGetter()(lhs) < GeometryIdGetter()(rhs); } -}; - -/// Store elements that know their detector geometry id, e.g. simulation hits. -/// -/// @tparam T type to be stored, must be compatible with `CompareGeometryId` -/// -/// The container stores an arbitrary number of elements for any geometry -/// id. Elements can be retrieved via the geometry id; elements can be selected -/// for a specific geometry id or for a larger range, e.g. a volume or a layer -/// within the geometry hierarchy using the helper functions below. Elements can -/// also be accessed by index that uniquely identifies each element regardless -/// of geometry id. -template <typename T> -using GeometryIdMultiset = boost::container::flat_multiset<T, CompareGeometryId>; - -/// Store elements indexed by an geometry id. -/// -/// @tparam T type to be stored -/// -/// The behaviour is the same as for the `GeometryIdMultiset` except that the -/// stored elements do not know their geometry id themself. When iterating -/// the iterator elements behave as for the `std::map`, i.e. -/// -/// for (const auto& entry: elements) { -/// auto id = entry.first; // geometry id -/// const auto& el = entry.second; // stored element -/// } -/// -template <typename T> -using GeometryIdMultimap = GeometryIdMultiset<std::pair<Acts::GeometryIdentifier, T>>; - -/// Select all elements within the given volume. -template <typename T> -inline Range<typename GeometryIdMultiset<T>::const_iterator> selectVolume( - const GeometryIdMultiset<T>& container, Acts::GeometryIdentifier::Value volume) -{ - auto cmp = Acts::GeometryIdentifier().setVolume(volume); - auto beg = std::lower_bound(container.begin(), container.end(), cmp, CompareGeometryId{}); - // WARNING overflows to volume==0 if the input volume is the last one - cmp = Acts::GeometryIdentifier().setVolume(volume + 1u); - // optimize search by using the lower bound as start point. also handles - // volume overflows since the geo id would be located before the start of - // the upper edge search window. - auto end = std::lower_bound(beg, container.end(), cmp, CompareGeometryId{}); - return makeRange(beg, end); -} - -/// Select all elements within the given volume. -template <typename T> -inline auto selectVolume(const GeometryIdMultiset<T>& container, Acts::GeometryIdentifier id) -{ - return selectVolume(container, id.volume()); -} - -/// Select all elements within the given layer. -template <typename T> -inline Range<typename GeometryIdMultiset<T>::const_iterator> selectLayer( - const GeometryIdMultiset<T>& container, - Acts::GeometryIdentifier::Value volume, - Acts::GeometryIdentifier::Value layer) -{ - auto cmp = Acts::GeometryIdentifier().setVolume(volume).setLayer(layer); - auto beg = std::lower_bound(container.begin(), container.end(), cmp, CompareGeometryId{}); - // WARNING resets to layer==0 if the input layer is the last one - cmp = Acts::GeometryIdentifier().setVolume(volume).setLayer(layer + 1u); - // optimize search by using the lower bound as start point. also handles - // volume overflows since the geo id would be located before the start of - // the upper edge search window. - auto end = std::lower_bound(beg, container.end(), cmp, CompareGeometryId{}); - return makeRange(beg, end); -} - -// Select all elements within the given layer. -template <typename T> -inline auto selectLayer(const GeometryIdMultiset<T>& container, Acts::GeometryIdentifier id) -{ - return selectLayer(container, id.volume(), id.layer()); -} - -/// Select all elements for the given module / sensitive surface. -template <typename T> -inline Range<typename GeometryIdMultiset<T>::const_iterator> selectModule( -const GeometryIdMultiset<T>& container, Acts::GeometryIdentifier geoId) -{ - // module is the lowest level and defines a single geometry id value - return makeRange(container.equal_range(geoId)); -} - -/// Select all elements for the given module / sensitive surface. -template <typename T> -inline auto selectModule( - const GeometryIdMultiset<T>& container, - Acts::GeometryIdentifier::Value volume, - Acts::GeometryIdentifier::Value layer, - Acts::GeometryIdentifier::Value module) -{ - return selectModule(container, - Acts::GeometryIdentifier().setVolume(volume).setLayer(layer).setSensitive(module)); -} - -/// Select all elements for the lowest non-zero identifier component. -/// -/// Zero values of lower components are interpreted as wildcard search patterns -/// that select all element at the given geometry hierarchy and below. This only -/// applies to the lower components and not to intermediate zeros. -/// -/// Examples: -/// - volume=2,layer=0,module=3 -> select all elements in the module -/// - volume=1,layer=2,module=0 -> select all elements in the layer -/// - volume=3,layer=0,module=0 -> select all elements in the volume -/// -/// @note An identifier with all components set to zero selects the whole input -/// container. -/// @note Boundary and approach surfaces do not really fit into the geometry -/// hierarchy and must be set to zero for the selection. If they are set on an -/// input identifier, the behaviour of this search method is undefined. -template <typename T> -inline Range<typename GeometryIdMultiset<T>::const_iterator> -selectLowestNonZeroGeometryObject(const GeometryIdMultiset<T>& container, Acts::GeometryIdentifier geoId) -{ - assert((geoId.boundary() == 0u) && "Boundary component must be zero"); - assert((geoId.approach() == 0u) && "Approach component must be zero"); - - if (geoId.sensitive() != 0u) { return selectModule(container, geoId); } - else if (geoId.layer() != 0u) { return selectLayer(container, geoId); } - else if (geoId.volume() != 0u) { return selectVolume(container, geoId); } - else { return makeRange(container.begin(), container.end()); } -} - -/// Iterate over groups of elements belonging to each module/ sensitive surface. -template <typename T> -inline GroupBy<typename GeometryIdMultiset<T>::const_iterator, GeometryIdGetter> -groupByModule(const GeometryIdMultiset<T>& container) -{ - return makeGroupBy(container, GeometryIdGetter()); -} - -/// The accessor for the GeometryIdMultiset container -/// -/// It wraps up a few lookup methods to be used in the Combinatorial Kalman -/// Filter -template <typename T> -struct GeometryIdMultisetAccessor { -using Container = GeometryIdMultiset<T>; -using Key = Acts::GeometryIdentifier; -using Value = typename GeometryIdMultiset<T>::value_type; -using Iterator = typename GeometryIdMultiset<T>::const_iterator; - -// pointer to the container -const Container* container = nullptr; -}; \ No newline at end of file diff --git a/Reconstruction/RecActsTracking/src/utils/MagneticField.hpp b/Reconstruction/RecActsTracking/src/utils/MagneticField.hpp deleted file mode 100644 index 94ef4152..00000000 --- a/Reconstruction/RecActsTracking/src/utils/MagneticField.hpp +++ /dev/null @@ -1,121 +0,0 @@ -// STL -#include <memory> -#include <variant> -#include <vector> - -// acts -#include "Acts/Definitions/Algebra.hpp" -#include "Acts/MagneticField/ConstantBField.hpp" -#include "Acts/MagneticField/InterpolatedBFieldMap.hpp" -#include "Acts/MagneticField/MagneticFieldProvider.hpp" -#include "Acts/MagneticField/MagneticFieldContext.hpp" -#include "Acts/MagneticField/NullBField.hpp" -#include "Acts/Utilities/Grid.hpp" -#include "Acts/Utilities/Result.hpp" -#include "Acts/Utilities/detail/Axis.hpp" -#include "Acts/Utilities/detail/AxisFwd.hpp" -#include "Acts/Utilities/detail/grid_helper.hpp" - -/// The ScalableBField-specific magnetic field context. -struct ScalableBFieldContext -{ Acts::ActsScalar scalor = 1.; }; - -/// A constant magnetic field that is scaled depending on the event context. -class ScalableBField final : public Acts::MagneticFieldProvider -{ - public: - struct Cache - { - Acts::ActsScalar scalor = 1.; - /// @brief constructor with context - Cache(const Acts::MagneticFieldContext& mctx) - { scalor = mctx.get<const ScalableBFieldContext>().scalor; } - }; - - /// @brief construct constant magnetic field from field vector - /// - /// @param [in] B magnetic field vector in global coordinate system - explicit ScalableBField(Acts::Vector3 B) : m_BField(std::move(B)) {} - - /// @brief construct constant magnetic field from components - /// - /// @param [in] Bx magnetic field component in global x-direction - /// @param [in] By magnetic field component in global y-direction - /// @param [in] Bz magnetic field component in global z-direction - ScalableBField(Acts::ActsScalar Bx = 0, Acts::ActsScalar By = 0, Acts::ActsScalar Bz = 0) - : m_BField(Bx, By, Bz) {} - - /// @brief retrieve magnetic field value - /// - /// @param [in] position global position - /// @param [in] cache Cache object (is ignored) - /// @return magnetic field vector - /// - /// @note The @p position is ignored and only kept as argument to provide - /// a consistent interface with other magnetic field services. - Acts::Result<Acts::Vector3> getField( - const Acts::Vector3& /*position*/, - MagneticFieldProvider::Cache& gCache) const override - { - Cache& cache = gCache.as<Cache>(); - return Acts::Result<Acts::Vector3>::success(m_BField * cache.scalor); - } - - /// @brief retrieve magnetic field value & its gradient - /// - /// @param [in] position global position - /// @param [out] derivative gradient of magnetic field vector as (3x3) - /// matrix - /// @param [in] cache Cache object (is ignored) - /// @return magnetic field vector - /// - /// @note The @p position is ignored and only kept as argument to provide - /// a consistent interface with other magnetic field services. - /// @note currently the derivative is not calculated - /// @todo return derivative - Acts::Result<Acts::Vector3> getFieldGradient( - const Acts::Vector3& /*position*/, Acts::ActsMatrix<3, 3>& /*derivative*/, - MagneticFieldProvider::Cache& gCache) const override - { - Cache& cache = gCache.as<Cache>(); - return Acts::Result<Acts::Vector3>::success(m_BField * cache.scalor); - } - - Acts::MagneticFieldProvider::Cache makeCache( - const Acts::MagneticFieldContext& mctx) const override - { - return Acts::MagneticFieldProvider::Cache(std::in_place_type<Cache>, mctx); - } - - /// @brief check whether given 3D position is inside look-up domain - /// - /// @param [in] position global 3D position - /// @return @c true if position is inside the defined look-up grid, - /// otherwise @c false - /// @note The method will always return true for the constant B-Field - bool isInside(const Acts::Vector3& /*position*/) const { return true; } - - /// @brief update magnetic field vector from components - /// - /// @param [in] Bx magnetic field component in global x-direction - /// @param [in] By magnetic field component in global y-direction - /// @param [in] Bz magnetic field component in global z-direction - void setField(double Bx, double By, double Bz) { m_BField << Bx, By, Bz; } - - /// @brief update magnetic field vector - /// - /// @param [in] B magnetic field vector in global coordinate system - void setField(const Acts::Vector3& B) { m_BField = B; } - - private: - /// magnetic field vector - Acts::Vector3 m_BField; -}; // ScalableBField - -using InterpolatedMagneticField2 = Acts::InterpolatedBFieldMap< - Acts::Grid<Acts::Vector2, Acts::detail::EquidistantAxis, - Acts::detail::EquidistantAxis>>; - -using InterpolatedMagneticField3 = Acts::InterpolatedBFieldMap< - Acts::Grid<Acts::Vector3, Acts::detail::EquidistantAxis, - Acts::detail::EquidistantAxis, Acts::detail::EquidistantAxis>>; diff --git a/Reconstruction/RecActsTracking/src/utils/SimSpacePoint.hpp b/Reconstruction/RecActsTracking/src/utils/SimSpacePoint.hpp deleted file mode 100644 index 4c577ccd..00000000 --- a/Reconstruction/RecActsTracking/src/utils/SimSpacePoint.hpp +++ /dev/null @@ -1,243 +0,0 @@ -// STL -#include <cmath> -#include <vector> -#include <cstdint> - -// boost -#include <boost/container/static_vector.hpp> - -// acts tools -#include "Acts/Definitions/Algebra.hpp" -#include "Acts/Definitions/Common.hpp" -#include "Acts/EventData/SourceLink.hpp" -#include "Acts/Seeding/Seed.hpp" -#include "Acts/Geometry/GeometryIdentifier.hpp" -#include "Acts/Geometry/TrackingGeometry.hpp" - -// edm4hep -#include "edm4hep/TrackerHit.h" -#include "edm4hep/SimTrackerHit.h" - -// local -#include "GeometryContainers.hpp" - -using Index = std::uint32_t; -template <typename value_t> -using IndexMultimap = boost::container::flat_multimap<Index, value_t>; - -template <typename value_t> -inline boost::container::flat_multimap<value_t, Index> invertIndexMultimap( - const IndexMultimap<value_t>& multimap) { - using InverseMultimap = boost::container::flat_multimap<value_t, Index>; - - // switch key-value without enforcing the new ordering (linear copy) - typename InverseMultimap::sequence_type unordered; - unordered.reserve(multimap.size()); - for (auto&& [index, value] : multimap) { - // value is now the key and the index is now the value - unordered.emplace_back(value, index); - } - - // adopting the unordered sequence will reestablish the correct order - InverseMultimap inverse; -#if BOOST_VERSION < 107800 - for (const auto& i : unordered) { - inverse.insert(i); - } -#else - inverse.insert(unordered.begin(), unordered.end()); -#endif - return inverse; -} - -/// Space point representation of a measurement suitable for track seeding. -class SimSpacePoint { - using Scalar = Acts::ActsScalar; - -public: - /// Construct the space point from edm4hep::TrackerHit - /// - /// @param trackerhit tracker hit to construct the space point from - SimSpacePoint(const edm4hep::TrackerHit trackerhit, - float x, float y, float z, float t, - // const edm4hep::SimTrackerHit simtrackerhit, - // Acts::GeometryIdentifier geometryId, - boost::container::static_vector<Acts::SourceLink, 2> sourceLinks) - : m_x(x), m_y(y), m_z(z), m_t(t), - m_sourceLinks(std::move(sourceLinks)) - // , m_geometryId(geometryId) - { - // m_trackerHit = trackerhit; - // m_simtrackerHit = simtrackerhit; - // m_x = simtrackerhit.getPosition()[0]; - // m_y = simtrackerhit.getPosition()[1]; - // m_z = simtrackerhit.getPosition()[2]; - // m_t = simtrackerhit.getTime(); - // m_cellid = simtrackerhit.getCellID(); - m_rho = std::sqrt(m_x * m_x + m_y * m_y + m_z * m_z); - m_varianceRho = trackerhit.getCovMatrix()[0]; - m_varianceZ = trackerhit.getCovMatrix()[5]; - } - - // edm4hep::TrackerHit getTrackerHit() { return m_trackerHit; } - // edm4hep::SimTrackerHit getSimTrackerHit() { return m_simtrackerHit; } - - constexpr Scalar x() const { return m_x; } - constexpr Scalar y() const { return m_y; } - constexpr Scalar z() const { return m_z; } - constexpr std::optional<Scalar> t() const { return m_t; } - constexpr Scalar r() const { return m_rho; } - constexpr Scalar varianceR() const { return m_varianceRho; } - constexpr Scalar varianceZ() const { return m_varianceZ; } - constexpr std::optional<Scalar> varianceT() const { return m_varianceT; } - - // constexpr std::uint64_t cellid() const { return m_cellid; } - // constexpr Acts::GeometryIdentifier geometryId() const { return m_geometryId; } - - const boost::container::static_vector<Acts::SourceLink, 2>& - sourceLinks() const { return m_sourceLinks; } - - constexpr float topHalfStripLength() const { return m_topHalfStripLength; } - constexpr float bottomHalfStripLength() const { return m_bottomHalfStripLength; } - - Acts::Vector3 topStripDirection() const { return m_topStripDirection; } - Acts::Vector3 bottomStripDirection() const { return m_bottomStripDirection; } - Acts::Vector3 stripCenterDistance() const { return m_stripCenterDistance; } - Acts::Vector3 topStripCenterPosition() const { return m_topStripCenterPosition; } - - constexpr bool validDoubleMeasurementDetails() const { - return m_validDoubleMeasurementDetails; - } - -private: - - // edm4hep::TrackerHit m_trackerHit; - // edm4hep::SimTrackerHit m_simtrackerHit; - // std::uint64_t m_cellid; - // Acts::GeometryIdentifier m_geometryId; - - // Global position - Scalar m_x; - Scalar m_y; - Scalar m_z; - std::optional<Scalar> m_t; - Scalar m_rho; - // Variance in rho/z of the global coordinates - Scalar m_varianceRho; - Scalar m_varianceZ; - std::optional<Scalar> m_varianceT; - // SourceLinks of the corresponding measurements. A Pixel (strip) SP has one - // (two) sourceLink(s). - boost::container::static_vector<Acts::SourceLink, 2> m_sourceLinks; - - // half of the length of the top strip - float m_topHalfStripLength = 0; - // half of the length of the bottom strip - float m_bottomHalfStripLength = 0; - // direction of the top strip - Acts::Vector3 m_topStripDirection = {0, 0, 0}; - // direction of the bottom strip - Acts::Vector3 m_bottomStripDirection = {0, 0, 0}; - // distance between the center of the two strips - Acts::Vector3 m_stripCenterDistance = {0, 0, 0}; - // position of the center of the bottom strip - Acts::Vector3 m_topStripCenterPosition = {0, 0, 0}; - bool m_validDoubleMeasurementDetails = false; - -}; // SimSpacePoint - -inline bool operator==(const SimSpacePoint& lhs, const SimSpacePoint& rhs) { - // (TODO) use sourceLinks for comparison - return ((lhs.x() == rhs.x()) && (lhs.y() == rhs.y()) && - (lhs.z() == rhs.z()) && (lhs.t() == rhs.t())); -} - -/// Container of space points. -using SimSpacePointContainer = std::vector<SimSpacePoint>; -using SimSeed = Acts::Seed<SimSpacePoint>; -using SimSeedContainer = std::vector<Acts::Seed<SimSpacePoint>>; - - -// -------------------------- -// IndexSourceLink -// -------------------------- - -/// A source link that stores just an index. -/// -/// This is intentionally kept as barebones as possible. The source link -/// is just a reference and will be copied, moved around, etc. often. -/// Keeping it small and separate from the actual, potentially large, -/// measurement data should result in better overall performance. -/// Using an index instead of e.g. a pointer, means source link and -/// measurement are decoupled and the measurement representation can be -/// easily changed without having to also change the source link. -class IndexSourceLink final -{ - public: - /// Construct from geometry identifier and index. - IndexSourceLink(Acts::GeometryIdentifier gid, Index idx, edm4hep::TrackerHit trackhit) - : m_geometryId(gid), m_index(idx), m_trackhit(trackhit) {} - - // Construct an invalid source link. - // Must be default constructible to satisfy SourceLinkConcept. - IndexSourceLink() = default; - IndexSourceLink(const IndexSourceLink&) = default; - IndexSourceLink(IndexSourceLink&&) = default; - IndexSourceLink& operator=(const IndexSourceLink&) = default; - IndexSourceLink& operator=(IndexSourceLink&&) = default; - - /// Access the index. - Index index() const { return m_index; } - Acts::GeometryIdentifier geometryId() const { return m_geometryId; } - edm4hep::TrackerHit getTrackerHit() const { return m_trackhit; } - - struct SurfaceAccessor - { - const Acts::TrackingGeometry& trackingGeometry; - const Acts::Surface* operator()(const Acts::SourceLink& sourceLink) const - { - const auto& indexSourceLink = sourceLink.get<IndexSourceLink>(); - return trackingGeometry.findSurface(indexSourceLink.geometryId()); - } - }; - - private: - Acts::GeometryIdentifier m_geometryId; - Index m_index = 0; - edm4hep::TrackerHit m_trackhit; - - friend bool operator==(const IndexSourceLink& lhs, const IndexSourceLink& rhs) - { - return (lhs.geometryId() == rhs.geometryId()) && (lhs.m_index == rhs.m_index); - } - - friend bool operator!=(const IndexSourceLink& lhs, const IndexSourceLink& rhs) - { - return !(lhs == rhs); - } -}; // IndexSourceLink - -/// Container of index source links. -/// -/// Since the source links provide a `.geometryId()` accessor, -/// they can be stored in an ordered geometry container. -using IndexSourceLinkContainer = GeometryIdMultiset<IndexSourceLink>; - -/// Accessor for the above source link container -/// -/// It wraps up a few lookup methods to be used in the Combinatorial Kalman -/// Filter -struct IndexSourceLinkAccessor : GeometryIdMultisetAccessor<IndexSourceLink> -{ - using BaseIterator = GeometryIdMultisetAccessor<IndexSourceLink>::Iterator; - - using Iterator = Acts::SourceLinkAdapterIterator<BaseIterator>; - - // get the range of elements with requested geoId - std::pair<Iterator, Iterator> range(const Acts::Surface& surface) const - { - assert(container != nullptr); - auto [begin, end] = container->equal_range(surface.geometryId()); - return {Iterator{begin}, Iterator{end}}; - } -}; \ No newline at end of file -- GitLab From 8adfc6a98a096531f69ded4c0c4723bad504132d Mon Sep 17 00:00:00 2001 From: "zhangyz@ihep.ac.cn" <zhangyz@ihep.ac.cn> Date: Thu, 5 Jun 2025 10:18:45 +0800 Subject: [PATCH 11/12] update ACTS for tdr25.5 --- .../RecActsTracking/src/RecActsTruthInput.cpp | 473 ----------- .../RecActsTracking/src/RecActsTruthInput.h | 100 --- .../src/RecActsTruthTracking.cpp | 796 ------------------ .../src/RecActsTruthTracking.h | 183 ---- 4 files changed, 1552 deletions(-) delete mode 100644 Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTruthInput.cpp delete mode 100644 Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTruthInput.h delete mode 100644 Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTruthTracking.cpp delete mode 100644 Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTruthTracking.h diff --git a/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTruthInput.cpp b/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTruthInput.cpp deleted file mode 100644 index 1418bc48..00000000 --- a/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTruthInput.cpp +++ /dev/null @@ -1,473 +0,0 @@ -// dependence -#include "RecActsTruthInput.h" - -DECLARE_COMPONENT(RecActsTruthInput) - -RecActsTruthInput::RecActsTruthInput(const std::string& name, ISvcLocator* svcLoc) - : GaudiAlgorithm(name, svcLoc) -{ -} - -StatusCode RecActsTruthInput::initialize() -{ - // -------------------------------- - // ---- initialize properties ----- - // -------------------------------- - - vtx_decoder = new dd4hep::DDSegmentation::BitFieldCoder("system:5,side:-2,layer:9,module:8,sensor:32:16"); - if(!vtx_decoder){ - info() << "Failed to create vtx_decoder" << endmsg; - return StatusCode::FAILURE; - } - - ITKBarrel_decoder = new dd4hep::DDSegmentation::BitFieldCoder("system:5,side:-2,layer:9,stave:8,module:8,sensor:5"); - if(!ITKBarrel_decoder){ - info() << "Failed to create ITKBarrel_decoder" << endmsg; - return StatusCode::FAILURE; - } - - ITKEndcap_decoder = new dd4hep::DDSegmentation::BitFieldCoder("system:5,side:-2,layer:9,module:8,sensor:8"); - if(!ITKEndcap_decoder){ - info() << "Failed to create ITKEndcap_decoder" << endmsg; - return StatusCode::FAILURE; - } - - tpc_decoder = new dd4hep::DDSegmentation::BitFieldCoder("system:5,side:-2,layer:13,module:6,sensor:6"); - if(!tpc_decoder){ - info() << "Failed to create TPC_decoder" << endmsg; - return StatusCode::FAILURE; - } - - OTKBarrel_decoder = new dd4hep::DDSegmentation::BitFieldCoder("system:5,side:-2,layer:9,module:8,iladder:32:4,oladder:-4,mmodule:-6"); - if(!OTKBarrel_decoder){ - info() << "Failed to create OTKBarrel_decoder" << endmsg; - return StatusCode::FAILURE; - } - - // -------------------------------- - // ---- initialize recActsSvc ---- - // -------------------------------- - - recActsSvc = service<IRecActsSvc>("RecActsSvc"); - if (!recActsSvc) { - error() << "Failed to get RecActsSvc" << endmsg; - return StatusCode::FAILURE; - } - - _nEvt = -1; - return StatusCode::SUCCESS; -} - -StatusCode RecActsTruthInput::execute() -{ - _nEvt++; - - recActsSvc->Clean(); - - if (useVTX.value()) { - if (!ReadInputVTX()) { - debug() << "VTX input failed at event " << _nEvt << endmsg; - } - } - - if (useITKBarrel.value()) { - if (!ReadInputITKBarrel()) { - debug() << "ITKBarrel input failed at event " << _nEvt << endmsg; - } - } - - if (useITKEndcap.value()) { - if (!ReadInputITKEndcap()) { - debug() << "ITKEndcap input failed at event " << _nEvt << endmsg; - } - } - - if (useTPC.value()) { - if (!ReadInputTPC()) { - debug() << "TPC input failed at event " << _nEvt << endmsg; - } - } - - if (useOTKBarrel.value()) { - if (!ReadInputOTKBarrel()) { - debug() << "OTKBarrel input failed at event " << _nEvt << endmsg; - } - } - - return StatusCode::SUCCESS; -} - -StatusCode RecActsTruthInput::finalize() -{ - return StatusCode::SUCCESS; -} - -bool RecActsTruthInput::ReadInputVTX() -{ - const edm4hep::TrackerHitCollection* hitVTXCol = nullptr; - const edm4hep::SimTrackerHitCollection* SimhitVTXCol = nullptr; - const edm4hep::MCRecoTrackerAssociationCollection* vtxAssCol = nullptr; - - try { - hitVTXCol = _inVTXTrackHdl.get(); - } catch (GaudiException& e) { - fatal() << "Collection " << _inVTXTrackHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; - return false; - } - - try { - SimhitVTXCol = _inVTXColHdl.get(); - } catch (GaudiException& e) { - fatal() << "Sim Collection " << _inVTXColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; - return false; - } - - try { - vtxAssCol = _inVTXAssColHdl.get(); - } catch (GaudiException& e) { - fatal() << "Association Collection " << _inVTXAssColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; - return false; - } - - if(hitVTXCol && SimhitVTXCol) - { - int nelem = hitVTXCol->size(); - - for(int ielem = 0; ielem < nelem; ++ielem){ - auto hit = hitVTXCol->at(ielem); - - std::vector<edm4hep::SimTrackerHit> simHits; - for(auto ass : *vtxAssCol){ - if(ass.getRec().getObjectID().collectionID != hit.getObjectID().collectionID) break; - else if(ass.getRec()==hit) simHits.push_back(ass.getSim()); - } - - if(simHits.size() == 0){ - info() << "Skip: Not found VTX simHit in AssociationCollection at event " << _nEvt << endmsg; - continue; - } - - auto simhit = simHits[0]; - - if (simhit.isProducedBySecondary()) { - continue; - } - - auto cellid = hit.getCellID(); - uint64_t m_layer = vtx_decoder->get(cellid, "layer"); - uint64_t m_module = vtx_decoder->get(cellid, "module"); - uint64_t m_sensor = vtx_decoder->get(cellid, "sensor"); - - if(m_layer <= 3){ - uint64_t acts_volume = VXD_volume_ids[m_layer]; - uint64_t acts_layer = 2; - uint64_t acts_sensitive = 1; - bool buildSpacePoint = true; - int moduleType = 1; - double onSurfaceTolerance = 1e-4; - - if (!recActsSvc->ReadInput(hit, - acts_volume, acts_layer, acts_sensitive, - buildSpacePoint, moduleType, onSurfaceTolerance)) - { return false; } - } else { - uint64_t acts_volume = VXD_volume_ids[4]; - uint64_t acts_layer = 2; - uint64_t acts_sensitive = (m_layer == 5) ? m_module*2 + 1 : m_module*2 + 2; - bool buildSpacePoint = true; - int moduleType = 0; - double onSurfaceTolerance = 1e-4; - - if (!recActsSvc->ReadInput(hit, - acts_volume, acts_layer, acts_sensitive, - buildSpacePoint, moduleType, onSurfaceTolerance)) - { return false; } - } - } - } - - return true; -} - -bool RecActsTruthInput::ReadInputITKBarrel() -{ - const edm4hep::TrackerHitCollection* hitITKBarrelCol = nullptr; - const edm4hep::SimTrackerHitCollection* SimhitITKBarrelCol = nullptr; - const edm4hep::MCRecoTrackerAssociationCollection* itkBarrelAssCol = nullptr; - - try { - hitITKBarrelCol = _inITKBarrelTrackHdl.get(); - } catch (GaudiException& e) { - fatal() << "Collection " << _inITKBarrelTrackHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; - return false; - } - - try { - SimhitITKBarrelCol = _inITKBarrelColHdl.get(); - } catch (GaudiException& e) { - fatal() << "Sim Collection " << _inITKBarrelColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; - return false; - } - - try { - itkBarrelAssCol = _inITKBarrelAssColHdl.get(); - } catch (GaudiException& e) { - fatal() << "Association Collection " << _inITKBarrelAssColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; - return false; - } - - if(hitITKBarrelCol) - { - int nelem = hitITKBarrelCol->size(); - - for (int ielem = 0; ielem < nelem; ++ielem) - { - auto hit = hitITKBarrelCol->at(ielem); - - std::vector<edm4hep::SimTrackerHit> simHits; - for(auto ass : *itkBarrelAssCol){ - if(ass.getRec().getObjectID().collectionID != hit.getObjectID().collectionID) break; - else if(ass.getRec()==hit) simHits.push_back(ass.getSim()); - } - - if(simHits.size() == 0){ - info() << "Skip: Not found ITKBarrel simHit in AssociationCollection at event " << _nEvt << endmsg; - continue; - } - - auto simhit = simHits[0]; - - if (simhit.isProducedBySecondary()) { - continue; - } - - auto cellid = hit.getCellID(); - uint64_t m_layer = ITKBarrel_decoder->get(cellid, "layer"); - uint64_t m_stave = ITKBarrel_decoder->get(cellid, "stave"); - - uint64_t acts_volume = ITKBarrel_volume_ids[m_layer]; - uint64_t acts_layer = 2; - uint64_t acts_sensitive = m_stave + 1; - bool buildSpacePoint = true; - int moduleType = 0; - double onSurfaceTolerance = 1e-4; - - if (!recActsSvc->ReadInput(hit, - acts_volume, acts_layer, acts_sensitive, - buildSpacePoint, moduleType, onSurfaceTolerance)) - { return false; } - } - } - - return true; -} - -bool RecActsTruthInput::ReadInputITKEndcap() -{ - const edm4hep::TrackerHitCollection* hitITKEndcapCol = nullptr; - const edm4hep::SimTrackerHitCollection* SimhitITKEndcapCol = nullptr; - const edm4hep::MCRecoTrackerAssociationCollection* itkEndcapAssCol = nullptr; - - try { - hitITKEndcapCol = _inITKEndcapTrackHdl.get(); - } catch (GaudiException& e) { - debug() << "Collection " << _inITKEndcapTrackHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; - return false; - } - - try { - SimhitITKEndcapCol = _inITKEndcapColHdl.get(); - } catch (GaudiException& e) { - debug() << "Sim Collection " << _inITKEndcapColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; - return false; - } - - try { - itkEndcapAssCol = _inITKEndcapAssColHdl.get(); - } catch (GaudiException& e) { - fatal() << "Association Collection " << _inITKEndcapAssColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; - return false; - } - - if (hitITKEndcapCol) - { - int nelem = hitITKEndcapCol->size(); - - for (int ielem = 0; ielem < nelem; ++ielem) - { - auto hit = hitITKEndcapCol->at(ielem); - - std::vector<edm4hep::SimTrackerHit> simHits; - for(auto ass : *itkEndcapAssCol){ - if(ass.getRec().getObjectID().collectionID != hit.getObjectID().collectionID) break; - else if(ass.getRec()==hit) simHits.push_back(ass.getSim()); - } - - if(simHits.size() == 0){ - info() << "Skip: Not found ITKEndcap simHit in AssociationCollection at event " << _nEvt << endmsg; - continue; - } - - auto simhit = simHits[0]; - - if (simhit.isProducedBySecondary()) { - continue; - } - - auto cellid = hit.getCellID(); - int m_side = ITKEndcap_decoder->get(cellid, "side"); - uint64_t m_layer = ITKEndcap_decoder->get(cellid, "layer"); - uint64_t m_module = ITKEndcap_decoder->get(cellid, "module"); - - uint64_t acts_volume = (m_side == 1) ? ITKEndcap_positive_volume_ids[m_layer] : ITKEndcap_negative_volume_ids[m_layer]; - uint64_t acts_layer = 2; - uint64_t acts_sensitive = m_module + 1; - - if (!recActsSvc->ReadInput(hit, - acts_volume, acts_layer, acts_sensitive)) - { return false; } - } - } - - return true; -} - - -bool RecActsTruthInput::ReadInputTPC() -{ - const edm4hep::TrackerHitCollection* hitTPCCol = nullptr; - const edm4hep::SimTrackerHitCollection* SimhitTPCCol = nullptr; - const edm4hep::MCRecoTrackerAssociationCollection* tpcAssCol = nullptr; - - try { - hitTPCCol = _inTPCTrackHdl.get(); - } catch (GaudiException& e) { - debug() << "Collection " << _inTPCTrackHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; - return false; - } - - try { - SimhitTPCCol = _inTPCColHdl.get(); - } catch (GaudiException& e) { - debug() << "Sim Collection " << _inTPCColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; - return false; - } - - try { - tpcAssCol = _inTPCAssColHdl.get(); - } catch (GaudiException& e) { - fatal() << "Association Collection " << _inTPCAssColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; - return false; - } - - if(hitTPCCol) - { - int nelem = hitTPCCol->size(); - - for (int ielem = 0; ielem < nelem; ++ielem) - { - auto hit = hitTPCCol->at(ielem); - - std::vector<edm4hep::SimTrackerHit> simHits; - for(auto ass : *tpcAssCol){ - if(ass.getRec().getObjectID().collectionID != hit.getObjectID().collectionID) break; - else if(ass.getRec()==hit) simHits.push_back(ass.getSim()); - } - - if(simHits.size() == 0){ - info() << "Skip: Not found TPC simHit in AssociationCollection at event " << _nEvt << endmsg; - continue; - } - - auto simhit = simHits[0]; - - if (simhit.isProducedBySecondary()) { - continue; - } - - auto cellid = hit.getCellID(); - uint64_t m_layer = tpc_decoder->get(cellid, "layer"); - - uint64_t acts_volume = TPC_volume_id; - uint64_t acts_layer = (m_layer + 1) * 2; - uint64_t acts_sensitive = 1; - bool buildSpacePoint = false; - int moduleType = 2; - double onSurfaceTolerance = 1e-4; - - if (!recActsSvc->ReadInput(hit, - acts_volume, acts_layer, acts_sensitive, - buildSpacePoint, moduleType, onSurfaceTolerance)) - { return false; } - } - } - - return true; -} - -bool RecActsTruthInput::ReadInputOTKBarrel() -{ - const edm4hep::TrackerHitCollection* hitOTKBarrelCol = nullptr; - const edm4hep::SimTrackerHitCollection* SimhitOTKBarrelCol = nullptr; - const edm4hep::MCRecoTrackerAssociationCollection* otkBarrelAssCol = nullptr; - - try { - hitOTKBarrelCol = _inOTKBarrelTrackHdl.get(); - } catch (GaudiException& e) { - debug() << "Collection " << _inOTKBarrelTrackHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; - return false; - } - - try { - SimhitOTKBarrelCol = _inOTKBarrelColHdl.get(); - } catch (GaudiException& e) { - debug() << "Sim Collection " << _inOTKBarrelColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; - return false; - } - - try { - otkBarrelAssCol = _inOTKBarrelAssColHdl.get(); - } catch (GaudiException& e) { - fatal() << "Association Collection " << _inOTKBarrelAssColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; - return false; - } - - if(hitOTKBarrelCol) - { - int nelem = hitOTKBarrelCol->size(); - - for (int ielem = 0; ielem < nelem; ++ielem) - { - auto hit = hitOTKBarrelCol->at(ielem); - - std::vector<edm4hep::SimTrackerHit> simHits; - for(auto ass : *otkBarrelAssCol){ - if(ass.getRec().getObjectID().collectionID != hit.getObjectID().collectionID) break; - else if(ass.getRec()==hit) simHits.push_back(ass.getSim()); - } - - if(simHits.size() == 0){ - info() << "Skip: Not found OTKBarrel simHit in AssociationCollection at event " << _nEvt << endmsg; - continue; - } - - auto simhit = simHits[0]; - - if (simhit.isProducedBySecondary()) { - continue; - } - - auto cellid = hit.getCellID(); - uint64_t m_module = OTKBarrel_decoder->get(cellid, "module"); - - uint64_t acts_volume = OTK_volume_id; - uint64_t acts_layer = 2; - uint64_t acts_sensitive = m_module + 1; - - if (!recActsSvc->ReadInput(hit, - acts_volume, acts_layer, acts_sensitive)) - { return false; } - } - } - return true; -} \ No newline at end of file diff --git a/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTruthInput.h b/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTruthInput.h deleted file mode 100644 index bd390199..00000000 --- a/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTruthInput.h +++ /dev/null @@ -1,100 +0,0 @@ -#ifndef RecActsTruthInput_H -#define RecActsTruthInput_H - -// gaudi framework -#include "k4FWCore/DataHandle.h" -#include "GaudiAlg/GaudiAlgorithm.h" - -// services -#include "RecActsSvc/IRecActsSvc.h" -// #include "DetInterface/IGeomSvc.h" - -// DD4hep -#include "DD4hep/Detector.h" -#include "DDRec/ISurface.h" -#include "DDRec/SurfaceManager.h" - -#include "UTIL/ILDConf.h" -#include "DataHelper/Navigation.h" - -// edm4hep -#include "edm4hep/MCParticle.h" -#include "edm4hep/MCParticleCollection.h" -#include "edm4hep/TrackerHitCollection.h" -#include "edm4hep/SimTrackerHitCollection.h" -#include "edm4hep/EventHeaderCollection.h" - -#include "edm4hep/Track.h" -#include "edm4hep/MutableTrack.h" -#include "edm4hep/TrackState.h" -#include "edm4hep/TrackCollection.h" - - -class RecActsTruthInput : public GaudiAlgorithm -{ - public: - RecActsTruthInput(const std::string& name, ISvcLocator* svcLoc); - - StatusCode initialize(); - StatusCode execute(); - StatusCode finalize(); - - private: - // Input collections - DataHandle<edm4hep::TrackerHitCollection> _inVTXTrackHdl{"VXDTrackerHits", Gaudi::DataHandle::Reader, this}; - DataHandle<edm4hep::TrackerHitCollection> _inITKBarrelTrackHdl{"ITKBarrelTrackerHits", Gaudi::DataHandle::Reader, this}; - DataHandle<edm4hep::TrackerHitCollection> _inITKEndcapTrackHdl{"ITKEndcapTrackerHits", Gaudi::DataHandle::Reader, this}; - DataHandle<edm4hep::TrackerHitCollection> _inOTKBarrelTrackHdl{"OTKBarrelTrackerHits", Gaudi::DataHandle::Reader, this}; - DataHandle<edm4hep::TrackerHitCollection> _inTPCTrackHdl{"TPCTrackerHits", Gaudi::DataHandle::Reader, this}; - - DataHandle<edm4hep::SimTrackerHitCollection> _inVTXColHdl{"VXDCollection", Gaudi::DataHandle::Reader, this}; - DataHandle<edm4hep::SimTrackerHitCollection> _inITKBarrelColHdl{"ITKBarrelCollection", Gaudi::DataHandle::Reader, this}; - DataHandle<edm4hep::SimTrackerHitCollection> _inITKEndcapColHdl{"ITKEndcapCollection", Gaudi::DataHandle::Reader, this}; - DataHandle<edm4hep::SimTrackerHitCollection> _inOTKBarrelColHdl{"OTKBarrelCollection", Gaudi::DataHandle::Reader, this}; - DataHandle<edm4hep::SimTrackerHitCollection> _inTPCColHdl{"TPCCollection", Gaudi::DataHandle::Reader, this}; - - // associations - DataHandle<edm4hep::MCRecoTrackerAssociationCollection> _inVTXAssColHdl{"VXDTrackerHitAssociation", Gaudi::DataHandle::Reader, this}; - DataHandle<edm4hep::MCRecoTrackerAssociationCollection> _inITKBarrelAssColHdl{"ITKBarrelTrackerHitAssociation", Gaudi::DataHandle::Reader, this}; - DataHandle<edm4hep::MCRecoTrackerAssociationCollection> _inITKEndcapAssColHdl{"ITKEndcapTrackerHitAssociation", Gaudi::DataHandle::Reader, this}; - DataHandle<edm4hep::MCRecoTrackerAssociationCollection> _inOTKBarrelAssColHdl{"OTKBarrelTrackerHitAssociation", Gaudi::DataHandle::Reader, this}; - DataHandle<edm4hep::MCRecoTrackerAssociationCollection> _inTPCAssColHdl{"TPCTrackerHitAss", Gaudi::DataHandle::Reader, this}; - - // properties - Gaudi::Property<bool> useVTX{this, "useVTX", true}; - Gaudi::Property<bool> useITKBarrel{this, "useITKBarrel", true}; - Gaudi::Property<bool> useITKEndcap{this, "useITKEndcap", true}; - Gaudi::Property<bool> useTPC{this, "useTPC", true}; - Gaudi::Property<bool> useOTKBarrel{this, "useOTKBarrel", true}; - - // read input - bool ReadInputVTX(); - bool ReadInputITKBarrel(); - bool ReadInputITKEndcap(); - bool ReadInputTPC(); - bool ReadInputOTKBarrel(); - - // services - // SmartIF<IGeomSvc> m_geosvc; - SmartIF<IRecActsSvc> recActsSvc; - SmartIF<IChronoStatSvc> chronoStatSvc; - - dd4hep::DDSegmentation::BitFieldCoder *vtx_decoder; - dd4hep::DDSegmentation::BitFieldCoder *ITKBarrel_decoder; - dd4hep::DDSegmentation::BitFieldCoder *ITKEndcap_decoder; - dd4hep::DDSegmentation::BitFieldCoder *tpc_decoder; - dd4hep::DDSegmentation::BitFieldCoder *OTKBarrel_decoder; - - // constants - int _nEvt; - uint64_t TPC_volume_id = 43; - uint64_t OTK_volume_id = 45; - std::vector<uint64_t> VXD_volume_ids{26, 27, 28, 29, 30}; - std::vector<uint64_t> ITKBarrel_volume_ids{33, 36, 39}; - std::vector<uint64_t> ITKEndcap_positive_volume_ids{34, 37, 40, 41}; - std::vector<uint64_t> ITKEndcap_negative_volume_ids{32, 15, 10, 8}; - std::vector<uint64_t> ITKBarrel_module_nums{7, 10, 14}; - -}; - -#endif // RecActsTruthInput_H \ No newline at end of file diff --git a/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTruthTracking.cpp b/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTruthTracking.cpp deleted file mode 100644 index 8a58b67c..00000000 --- a/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTruthTracking.cpp +++ /dev/null @@ -1,796 +0,0 @@ -// dependence -#include "RecActsTruthTracking.h" - -DECLARE_COMPONENT(RecActsTruthTracking) - -RecActsTruthTracking::RecActsTruthTracking(const std::string& name, ISvcLocator* svcLoc) - : GaudiAlgorithm(name, svcLoc) -{ -} - -StatusCode RecActsTruthTracking::initialize() -{ - // -------------------------------- - // ---- initialize properties ----- - // -------------------------------- - - info() << "Assume Particle: " << m_particle.value() << endmsg; - if(m_particle.value() == "muon"){ - particleHypothesis = Acts::ParticleHypothesis::muon(); - } - else if(m_particle.value() == "pion"){ - particleHypothesis = Acts::ParticleHypothesis::pion(); - } - else if(m_particle.value() == "electron"){ - particleHypothesis = Acts::ParticleHypothesis::electron(); - } - else if(m_particle.value() == "kaon"){ - particleHypothesis = Acts::ParticleHypothesis::kaon(); - } - else if(m_particle.value() == "proton"){ - particleHypothesis = Acts::ParticleHypothesis::proton(); - } - else if(m_particle.value() == "photon"){ - particleHypothesis = Acts::ParticleHypothesis::photon(); - } - else if(m_particle.value() == "geantino"){ - particleHypothesis = Acts::ParticleHypothesis::geantino(); - } - else if(m_particle.value() == "chargedgeantino"){ - particleHypothesis = Acts::ParticleHypothesis::chargedGeantino(); - } - else{ - info() << "Supported Assumed Particle: " << particleNames[0] << ", " << particleNames[1] << ", " << particleNames[2] << ", " - << particleNames[3] << ", " << particleNames[4] << ", " << particleNames[5] << ", " - << particleNames[6] << ", " << particleNames[7] << endmsg; - error() << "Unsupported particle name " << m_particle.value() << endmsg; - return StatusCode::FAILURE; - } - - // m_geosvc = service<IGeomSvc>("GeomSvc"); - // if (!m_geosvc) { - // error() << "Failed to get GeomSvc" << endmsg; - // return StatusCode::FAILURE; - // } - - // m_vtx_surfaces = m_geosvc->getSurfaceMap("VXD"); - // debug() << "VXD Surface map size: " << m_vtx_surfaces->size() << endmsg; - - // m_ITKBarrel_surfaces = m_geosvc->getSurfaceMap("ITKBarrel"); - // debug() << "ITKBarrel Surface map size: " << m_ITKBarrel_surfaces->size() << endmsg; - - // m_ITKEndcap_surfaces = m_geosvc->getSurfaceMap("ITKEndcap"); - // debug() << "ITKEndcap Surface map size: " << m_ITKEndcap_surfaces->size() << endmsg; - - // m_tpc_surfaces = m_geosvc->getSurfaceMap("TPC"); - // debug() << "TPC Surface map size: " << m_tpc_surfaces->size() << endmsg; - - // m_OTKBarrel_surfaces = m_geosvc->getSurfaceMap("OTKBarrel"); - // debug() << "OTK Barrel Surface map size: " << m_OTKBarrel_surfaces->size() << endmsg; - - // vtx_decoder = m_geosvc->getDecoder("VXDCollection"); - // if(!vtx_decoder){ - // return StatusCode::FAILURE; - // } - - // ITKBarrel_decoder = m_geosvc->getDecoder("ITKBarrelCollection"); - // if(!ITKBarrel_decoder){ - // return StatusCode::FAILURE; - // } - - // tpc_decoder = m_geosvc->getDecoder("TPCCollection"); - // if(!tpc_decoder){ - // return StatusCode::FAILURE; - // } - - // ITKEndcap_decoder = m_geosvc->getDecoder("ITKEndcapCollection"); - // if(!ITKEndcap_decoder){ - // return StatusCode::FAILURE; - // } - - // OTKBarrel_decoder = m_geosvc->getDecoder("OTKBarrelCollection"); - // if(!OTKBarrel_decoder){ - // return StatusCode::FAILURE; - // } - - vtx_decoder = new dd4hep::DDSegmentation::BitFieldCoder("system:5,side:-2,layer:9,module:8,sensor:32:16"); - if(!vtx_decoder){ - info() << "Failed to create vtx_decoder" << endmsg; - return StatusCode::FAILURE; - } - - ITKBarrel_decoder = new dd4hep::DDSegmentation::BitFieldCoder("system:5,side:-2,layer:9,stave:8,module:8,sensor:5"); - if(!ITKBarrel_decoder){ - info() << "Failed to create ITKBarrel_decoder" << endmsg; - return StatusCode::FAILURE; - } - - ITKEndcap_decoder = new dd4hep::DDSegmentation::BitFieldCoder("system:5,side:-2,layer:9,module:8,sensor:8"); - if(!ITKEndcap_decoder){ - info() << "Failed to create ITKEndcap_decoder" << endmsg; - return StatusCode::FAILURE; - } - - tpc_decoder = new dd4hep::DDSegmentation::BitFieldCoder("system:5,side:-2,layer:13,module:6,sensor:6"); - if(!tpc_decoder){ - info() << "Failed to create TPC_decoder" << endmsg; - return StatusCode::FAILURE; - } - - OTKBarrel_decoder = new dd4hep::DDSegmentation::BitFieldCoder("system:5,side:-2,layer:9,module:8,iladder:32:4,oladder:-4,mmodule:-6"); - if(!OTKBarrel_decoder){ - info() << "Failed to create OTKBarrel_decoder" << endmsg; - return StatusCode::FAILURE; - } - - recActsSvc = service<IRecActsSvc>("RecActsSvc"); - if (!recActsSvc) { - error() << "Failed to get RecActsSvc" << endmsg; - return StatusCode::FAILURE; - } - - // -------------------------------- - // ---- initialize recActsSvc ---- - // -------------------------------- - - recActsSvc = service<IRecActsSvc>("RecActsSvc"); - if (!recActsSvc) { - error() << "Failed to get RecActsSvc" << endmsg; - return StatusCode::FAILURE; - } - - chronoStatSvc = service<IChronoStatSvc>("ChronoStatSvc"); - - magneticField = std::make_shared<Acts::ConstantBField>(Acts::Vector3(0., 0., m_field.value()*_FCT)); - fit = ActsHelper::makeKalmanFitterFunction(recActsSvc->Geometry(), magneticField); - // fit = ActsHelper::makeGsfFitterFunction(recActsSvc->Geometry(), magneticField); (not working) - // fit = ActsHelper::makeGlobalChiSquareFitterFunction(recActsSvc->Geometry(), magneticField); (ok) - - _nEvt = -1; - return StatusCode::SUCCESS; -} - -StatusCode RecActsTruthTracking::execute() -{ - _nEvt++; - - chronoStatSvc->chronoStart("Truth Tracking"); - - auto trkCol = _outColHdl.createAndPut(); - - const edm4hep::MCParticleCollection* mcCols = nullptr; - try { mcCols = _inMCColHdl.get(); } - catch ( GaudiException &e ) { - debug() << "Collection " << _inMCColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; - } - - if(mcCols){ - for(const auto& mc : *mcCols){ - if (mc.getGeneratorStatus() != 1){ - info() << "MCParticle " << mc.getPDG() << " is not primary at event " << _nEvt << endmsg; - continue; - } - - recActsSvc->Clean(); - debug() << "Processing MCParticle " << mc.getPDG() << " at event " << _nEvt << endmsg; - - if(!ReadHits(mc)){ - info() << "Fit MCParticle " << mc.getPDG() << " failed at event " << _nEvt << endmsg; - continue; - } - - auto measurements = recActsSvc->Measurements(); - auto trackSourceLinks = recActsSvc->SourceLinks(); - auto initialParams = recActsSvc->InitialParameters(); - - if (initialParams->size() == 0) { - info() << "No initial parameters found for MCParticle " << mc.getPDG() << " at event " << _nEvt << endmsg; - continue; - } - - auto pSurface = Acts::Surface::makeShared<Acts::PerigeeSurface>(Acts::Vector3{0., 0., 0.}); - ActsHelper::PassThroughCalibrator pcalibrator; - ActsHelper::MeasurementCalibratorAdapter calibrator(pcalibrator, *measurements); - ActsHelper::TrackFitterFunction::GeneralFitterOptions options{ - geoContext, magFieldContext, calibContext, pSurface.get(), Acts::PropagatorPlainOptions()}; - - auto trackContainer = std::make_shared<Acts::VectorTrackContainer>(); - auto trackStateContainer = std::make_shared<Acts::VectorMultiTrajectory>(); - ActsHelper::TrackContainer tracks(trackContainer, trackStateContainer); - - std::vector<Acts::SourceLink> cur_trackSourceLinks; - for (const auto& sourceLink : *trackSourceLinks) { - cur_trackSourceLinks.push_back(Acts::SourceLink{sourceLink}); - } - auto result = (*fit)(cur_trackSourceLinks, initialParams->at(0), options, calibrator, tracks); - if (!result.ok()) { - info() << "Track fit failed for MCParticle " << mc.getPDG() << " at event " << _nEvt << endmsg; - continue; - } - - std::stringstream ss; - trackStateContainer->statistics().toStream(ss); - debug() << ss.str() << endmsg; - - ActsHelper::ConstTrackContainer constTracks - { - std::make_shared<Acts::ConstVectorTrackContainer>(std::move(*trackContainer)), - std::make_shared<Acts::ConstVectorMultiTrajectory>(std::move(*trackStateContainer)) - }; - - if (constTracks.size() == 0) { - info() << "No tracks fitted for MCParticle " << mc.getPDG() << " at event " << _nEvt << endmsg; - continue; - } else if (constTracks.size() > 1) { - info() << "Number of tracks fitted: " << constTracks.size() << " for MCParticle " << mc.getPDG() << " at event " << _nEvt << endmsg; - } - - for (const auto& cur_track : constTracks) - { - auto writeout_track = trkCol->create(); - - writeout_track.setChi2(cur_track.chi2()); - writeout_track.setNdf(cur_track.nDoF()); - writeout_track.setDEdx(cur_track.absoluteMomentum() / Acts::UnitConstants::GeV); - writeout_track.setDEdxError(mc.getPDG()); - - // TODO: covmatrix need to be converted - std::array<float, 21> writeout_covMatrix; - auto cur_track_covariance = cur_track.covariance(); - for (int i = 0; i < 6; i++) { - for (int j = 0; j < 6-i; j++) { - writeout_covMatrix[int((13-i)*i/2 + j)] = cur_track_covariance(writeout_indices[i], writeout_indices[j]); - } - } - // location: At{Other|IP|FirstHit|LastHit|Calorimeter|Vertex}|LastLocation - // TrackState: location, d0, phi, omega, z0, tanLambda, time, referencePoint, covMatrix - edm4hep::TrackState writeout_trackState{ - 1, // location: AtOther - cur_track.loc0() / Acts::UnitConstants::mm, // d0 - cur_track.phi(), // phi - cur_track.qOverP() * _FCT * m_field.value() / sin(cur_track.theta()) , // omega = qop * sin(theta) * _FCT * bf - cur_track.loc1() / Acts::UnitConstants::mm, // z0 - 1 / tan(cur_track.theta()), // tanLambda = 1 / tan(theta) - cur_track.time(), // time - ::edm4hep::Vector3f(0, 0, 0), // referencePoint - writeout_covMatrix - }; - - debug() << "Found track with momentum " << cur_track.absoluteMomentum() / Acts::UnitConstants::GeV << " GeV!" << endmsg; - writeout_track.addToTrackStates(writeout_trackState); - } - - if (!useMCTruth.value()) { break; } - } - } - - chronoStatSvc->chronoStop("Truth Tracking"); - - return StatusCode::SUCCESS; -} - -StatusCode RecActsTruthTracking::finalize() -{ - return StatusCode::SUCCESS; -} - -bool RecActsTruthTracking::ReadHits(const edm4hep::MCParticle& mc) -{ - double px = 0; - double py = 0; - double pz = 0; - - if (useVTX.value()) - { - const edm4hep::TrackerHitCollection* hitVTXCol = nullptr; - const edm4hep::SimTrackerHitCollection* SimhitVTXCol = nullptr; - const edm4hep::MCRecoTrackerAssociationCollection* vtxAssCol = nullptr; - - try { - hitVTXCol = _inVTXTrackHdl.get(); - } catch (GaudiException& e) { - fatal() << "Collection " << _inVTXTrackHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; - return false; - } - - try { - SimhitVTXCol = _inVTXColHdl.get(); - } catch (GaudiException& e) { - fatal() << "Sim Collection " << _inVTXColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; - return false; - } - - try { - vtxAssCol = _inVTXAssColHdl.get(); - } catch (GaudiException& e) { - fatal() << "Association Collection " << _inVTXAssColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; - return false; - } - - if(hitVTXCol && SimhitVTXCol) - { - int nelem = hitVTXCol->size(); - debug() << "Number of VTX hits = " << nelem << endmsg; - - std::vector<int> hit_indices; - std::vector<float> hit_radii; - for(int ielem = 0; ielem < nelem; ++ielem){ - auto hit = hitVTXCol->at(ielem); - - std::vector<edm4hep::SimTrackerHit> simHits; - for(auto ass : *vtxAssCol){ - if(ass.getRec().getObjectID().collectionID != hit.getObjectID().collectionID) break; - else if(ass.getRec()==hit) simHits.push_back(ass.getSim()); - } - - if(simHits.size() == 0){ - info() << "Skip: Not found VTX simHit in AssociationCollection at event " << _nEvt << endmsg; - continue; - } - - auto simhit = simHits[0]; - - if (simhit.isProducedBySecondary()) { - continue; - } - - if (useMCTruth.value() && !(simhit.getMCParticle() == mc)) { - continue; - } - - float hit_r = std::hypot(hit.getPosition()[0], hit.getPosition()[1]); - hit_indices.push_back(ielem); - hit_radii.push_back(hit_r); - } - - std::sort(hit_indices.begin(), hit_indices.end(), - [&hit_radii](int i1, int i2) { return hit_radii[i1] < hit_radii[i2]; }); - - for(int i_hit : hit_indices){ - auto hit = hitVTXCol->at(i_hit); - - auto cellid = hit.getCellID(); - uint64_t m_layer = vtx_decoder->get(cellid, "layer"); - uint64_t m_module = vtx_decoder->get(cellid, "module"); - - if(m_layer <= 3){ - uint64_t acts_volume = VXD_volume_ids[m_layer]; - uint64_t acts_layer = 2; - uint64_t acts_sensitive = 1; - bool buildSpacePoint = true; - int moduleType = 1; - double onSurfaceTolerance = 1e-4; - - if (!recActsSvc->ReadInput(hit, - acts_volume, acts_layer, acts_sensitive, - buildSpacePoint, moduleType, onSurfaceTolerance)) - { return false; } - } else { - uint64_t acts_volume = VXD_volume_ids[4]; - uint64_t acts_layer = 2; - uint64_t acts_sensitive = (m_layer == 5) ? m_module*2 + 1 : m_module*2 + 2;; - - if (!recActsSvc->ReadInput(hit, - acts_volume, acts_layer, acts_sensitive)) - { return false; } - } - } - - if (hit_indices.size() == 0) { - info() << "Skip: Not found VTX simHit at event " << _nEvt << endmsg; - return false; - } - - auto first_hit = hitVTXCol->at(hit_indices[0]); - std::vector<edm4hep::SimTrackerHit> simHits; - for(auto ass : *vtxAssCol){ - if(ass.getRec().getObjectID().collectionID != first_hit.getObjectID().collectionID) break; - else if(ass.getRec()==first_hit) simHits.push_back(ass.getSim()); - } - auto simhit = simHits[0]; - px = simhit.getMomentum()[0]; - py = simhit.getMomentum()[1]; - pz = simhit.getMomentum()[2]; - } - } - - if (useITKBarrel.value()) - { - const edm4hep::TrackerHitCollection* hitITKBarrelCol = nullptr; - const edm4hep::SimTrackerHitCollection* SimhitITKBarrelCol = nullptr; - const edm4hep::MCRecoTrackerAssociationCollection* itkBarrelAssCol = nullptr; - - try { - hitITKBarrelCol = _inITKBarrelTrackHdl.get(); - } catch (GaudiException& e) { - fatal() << "Collection " << _inITKBarrelTrackHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; - return false; - } - - try { - SimhitITKBarrelCol = _inITKBarrelColHdl.get(); - } catch (GaudiException& e) { - fatal() << "Sim Collection " << _inITKBarrelColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; - return false; - } - - try { - itkBarrelAssCol = _inITKBarrelAssColHdl.get(); - } catch (GaudiException& e) { - fatal() << "Association Collection " << _inITKBarrelAssColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; - return false; - } - - if(hitITKBarrelCol && SimhitITKBarrelCol) - { - int nelem = hitITKBarrelCol->size(); - debug() << "Number of ITKBarrel hits = " << nelem << endmsg; - - std::vector<int> hit_indices; - std::vector<float> hit_radii; - for(int ielem = 0; ielem < nelem; ++ielem){ - auto hit = hitITKBarrelCol->at(ielem); - - std::vector<edm4hep::SimTrackerHit> simHits; - for(auto ass : *itkBarrelAssCol){ - if(ass.getRec().getObjectID().collectionID != hit.getObjectID().collectionID) break; - else if(ass.getRec()==hit) simHits.push_back(ass.getSim()); - } - - if(simHits.size() == 0){ - info() << "Skip: Not found ITKBarrel simHit in AssociationCollection at event " << _nEvt << endmsg; - continue; - } - - auto simhit = simHits[0]; - - if (simhit.isProducedBySecondary()) { - continue; - } - - if (useMCTruth.value() && !(simhit.getMCParticle() == mc)) { - continue; - } - - float hit_r = std::hypot(hit.getPosition()[0], hit.getPosition()[1]); - hit_indices.push_back(ielem); - hit_radii.push_back(hit_r); - } - - std::sort(hit_indices.begin(), hit_indices.end(), - [&hit_radii](int i1, int i2) { return hit_radii[i1] < hit_radii[i2]; }); - - for (int i_hit : hit_indices) - { - auto hit = hitITKBarrelCol->at(i_hit); - - auto cellid = hit.getCellID(); - uint64_t m_layer = ITKBarrel_decoder->get(cellid, "layer"); - uint64_t m_stave = ITKBarrel_decoder->get(cellid, "stave"); - - uint64_t acts_volume = ITKBarrel_volume_ids[m_layer]; - uint64_t acts_layer = 2; - uint64_t acts_sensitive = m_stave + 1; - - if (!recActsSvc->ReadInput(hit, - acts_volume, acts_layer, acts_sensitive)) - { return false; } - } - } - } - - if (useITKEndcap.value()) - { - const edm4hep::TrackerHitCollection* hitITKEndcapCol = nullptr; - const edm4hep::SimTrackerHitCollection* SimhitITKEndcapCol = nullptr; - const edm4hep::MCRecoTrackerAssociationCollection* itkEndcapAssCol = nullptr; - - try { - hitITKEndcapCol = _inITKEndcapTrackHdl.get(); - } catch (GaudiException& e) { - debug() << "Collection " << _inITKEndcapTrackHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; - return false; - } - - try { - SimhitITKEndcapCol = _inITKEndcapColHdl.get(); - } catch (GaudiException& e) { - debug() << "Sim Collection " << _inITKEndcapColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; - return false; - } - - try { - itkEndcapAssCol = _inITKEndcapAssColHdl.get(); - } catch (GaudiException& e) { - fatal() << "Association Collection " << _inITKEndcapAssColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; - return false; - } - - if (hitITKEndcapCol && SimhitITKEndcapCol) - { - int nelem = hitITKEndcapCol->size(); - debug() << "Number of ITKEndcap hits = " << nelem << endmsg; - - std::vector<int> hit_indices; - std::vector<float> hit_radii; - for(int ielem = 0; ielem < nelem; ++ielem){ - auto hit = hitITKEndcapCol->at(ielem); - - std::vector<edm4hep::SimTrackerHit> simHits; - for(auto ass : *itkEndcapAssCol){ - if(ass.getRec().getObjectID().collectionID != hit.getObjectID().collectionID) break; - else if(ass.getRec()==hit) simHits.push_back(ass.getSim()); - } - - if(simHits.size() == 0){ - info() << "Skip: Not found ITKEndcap simHit in AssociationCollection at event " << _nEvt << endmsg; - continue; - } - - auto simhit = simHits[0]; - - if (simhit.isProducedBySecondary()) { - continue; - } - - if (useMCTruth.value() && !(simhit.getMCParticle() == mc)) { - continue; - } - - float hit_r = std::hypot(hit.getPosition()[0], hit.getPosition()[1]); - hit_indices.push_back(ielem); - hit_radii.push_back(hit_r); - } - - std::sort(hit_indices.begin(), hit_indices.end(), - [&hit_radii](int i1, int i2) { return hit_radii[i1] < hit_radii[i2]; }); - - for (int i_hit : hit_indices) - { - auto hit = hitITKEndcapCol->at(i_hit); - - std::vector<edm4hep::SimTrackerHit> simHits; - for(auto ass : *itkEndcapAssCol){ - if(ass.getRec().getObjectID().collectionID != hit.getObjectID().collectionID) break; - else if(ass.getRec()==hit) simHits.push_back(ass.getSim()); - } - - if(simHits.size() == 0){ - info() << "Skip: Not found ITKEndcap simHit in AssociationCollection at event " << _nEvt << endmsg; - continue; - } - - auto simhit = simHits[0]; - - if (simhit.isProducedBySecondary()) { - continue; - } - - if (useMCTruth.value() && !(simhit.getMCParticle() == mc)) { - continue; - } - - auto cellid = hit.getCellID(); - int m_side = ITKEndcap_decoder->get(cellid, "side"); - uint64_t m_layer = ITKEndcap_decoder->get(cellid, "layer"); - uint64_t m_module = ITKEndcap_decoder->get(cellid, "module"); - - uint64_t acts_volume = (m_side == 1) ? ITKEndcap_positive_volume_ids[m_layer] : ITKEndcap_negative_volume_ids[m_layer]; - uint64_t acts_layer = 2; - uint64_t acts_sensitive = m_module + 1; - - if (!recActsSvc->ReadInput(hit, - acts_volume, acts_layer, acts_sensitive)) - { return false; } - } - } - } - - if (useTPC.value()) - { - - const edm4hep::TrackerHitCollection* hitTPCCol = nullptr; - const edm4hep::SimTrackerHitCollection* SimhitTPCCol = nullptr; - const edm4hep::MCRecoTrackerAssociationCollection* tpcAssCol = nullptr; - - try { - hitTPCCol = _inTPCTrackHdl.get(); - } catch (GaudiException& e) { - debug() << "Collection " << _inTPCTrackHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; - return false; - } - - try { - SimhitTPCCol = _inTPCColHdl.get(); - } catch (GaudiException& e) { - debug() << "Sim Collection " << _inTPCColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; - return false; - } - - try { - tpcAssCol = _inTPCAssColHdl.get(); - } catch (GaudiException& e) { - fatal() << "Association Collection " << _inTPCAssColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; - return false; - } - - if(hitTPCCol && SimhitTPCCol) - { - int nelem = hitTPCCol->size(); - debug() << "Number of TPC hits = " << nelem << endmsg; - - std::vector<int> hit_indices; - std::vector<float> hit_radii; - for(int ielem = 0; ielem < nelem; ++ielem){ - auto hit = hitTPCCol->at(ielem); - - std::vector<edm4hep::SimTrackerHit> simHits; - for(auto ass : *tpcAssCol){ - if(ass.getRec().getObjectID().collectionID != hit.getObjectID().collectionID) break; - else if(ass.getRec()==hit) simHits.push_back(ass.getSim()); - } - - if(simHits.size() == 0){ - info() << "Skip: Not found TPC simHit in AssociationCollection at event " << _nEvt << endmsg; - continue; - } - - auto simhit = simHits[0]; - - if (simhit.isProducedBySecondary()) { - continue; - } - - if (useMCTruth.value() && !(simhit.getMCParticle() == mc)) { - continue; - } - - float hit_r = std::hypot(hit.getPosition()[0], hit.getPosition()[1]); - hit_indices.push_back(ielem); - hit_radii.push_back(hit_r); - } - - std::sort(hit_indices.begin(), hit_indices.end(), - [&hit_radii](int i1, int i2) { return hit_radii[i1] < hit_radii[i2]; }); - - for (int i_hit : hit_indices) - { - auto hit = hitTPCCol->at(i_hit); - - auto cellid = hit.getCellID(); - uint64_t m_layer = tpc_decoder->get(cellid, "layer"); - - uint64_t acts_volume = TPC_volume_id; - uint64_t acts_layer = (m_layer + 1) * 2; - uint64_t acts_sensitive = 1; - bool buildSpacePoint = false; - int moduleType = 2; - double onSurfaceTolerance = 1e-4; - - if (!recActsSvc->ReadInput(hit, - acts_volume, acts_layer, acts_sensitive, - buildSpacePoint, moduleType, onSurfaceTolerance)) - { return false; } - } - } - } - - if (useOTKBarrel.value()) - { - const edm4hep::TrackerHitCollection* hitOTKBarrelCol = nullptr; - const edm4hep::SimTrackerHitCollection* SimhitOTKBarrelCol = nullptr; - const edm4hep::MCRecoTrackerAssociationCollection* otkBarrelAssCol = nullptr; - - try { - hitOTKBarrelCol = _inOTKBarrelTrackHdl.get(); - } catch (GaudiException& e) { - debug() << "Collection " << _inOTKBarrelTrackHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; - return false; - } - - try { - SimhitOTKBarrelCol = _inOTKBarrelColHdl.get(); - } catch (GaudiException& e) { - debug() << "Sim Collection " << _inOTKBarrelColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; - return false; - } - - try { - otkBarrelAssCol = _inOTKBarrelAssColHdl.get(); - } catch (GaudiException& e) { - fatal() << "Association Collection " << _inOTKBarrelAssColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; - return false; - } - - if(hitOTKBarrelCol && SimhitOTKBarrelCol) - { - int nelem = hitOTKBarrelCol->size(); - debug() << "Number of OTKBarrel hits = " << nelem << endmsg; - - std::vector<int> hit_indices; - std::vector<float> hit_radii; - for(int ielem = 0; ielem < nelem; ++ielem) - { - auto hit = hitOTKBarrelCol->at(ielem); - - std::vector<edm4hep::SimTrackerHit> simHits; - for(auto ass : *otkBarrelAssCol){ - if(ass.getRec().getObjectID().collectionID != hit.getObjectID().collectionID) break; - else if(ass.getRec()==hit) simHits.push_back(ass.getSim()); - } - - if(simHits.size() == 0){ - info() << "Skip: Not found OTKBarrel simHit in AssociationCollection at event " << _nEvt << endmsg; - continue; - } - - auto simhit = simHits[0]; - - if (simhit.isProducedBySecondary()) { - continue; - } - - if (useMCTruth.value() && !(simhit.getMCParticle() == mc)) { - continue; - } - - float hit_r = std::hypot(hit.getPosition()[0], hit.getPosition()[1]); - hit_indices.push_back(ielem); - hit_radii.push_back(hit_r); - } - - std::sort(hit_indices.begin(), hit_indices.end(), - [&hit_radii](int i1, int i2) { return hit_radii[i1] < hit_radii[i2]; }); - - for (int i_hit : hit_indices) - { - auto hit = hitOTKBarrelCol->at(i_hit); - - auto cellid = hit.getCellID(); - uint64_t m_module = OTKBarrel_decoder->get(cellid, "module"); - - uint64_t acts_volume = OTK_volume_id; - uint64_t acts_layer = 2; - uint64_t acts_sensitive = m_module + 1; - - if (!recActsSvc->ReadInput(hit, - acts_volume, acts_layer, acts_sensitive)) - { return false; } - } - } - } - - double p = sqrt(px*px + py*py + pz*pz); - double phi = atan2(py, px); - double theta = atan2(sqrt(px*px + py*py), pz); - double qop = -1 / p; - - Acts::BoundVector params = Acts::BoundVector::Zero(); - Acts::BoundSquareMatrix cov = Acts::BoundSquareMatrix::Zero(); - ActsHelper::IndexSourceLink::SurfaceAccessor surfaceAccessor{*recActsSvc->Geometry()}; - - auto first_hit_meas = recActsSvc->Measurements()->at(0); - auto cur_meas_param = std::get<1>(first_hit_meas).parameters(); - auto cur_meas_sl = std::get<1>(first_hit_meas).sourceLink(); - const Acts::Surface* surface = surfaceAccessor(cur_meas_sl); - - params[Acts::eBoundLoc0] = cur_meas_param[Acts::eBoundLoc0]; - params[Acts::eBoundLoc1] = cur_meas_param[Acts::eBoundLoc1]; - params[Acts::eBoundPhi] = phi; - params[Acts::eBoundTheta] = theta; - params[Acts::eBoundQOverP] = qop; - params[Acts::eBoundTime] = 0; - for (std::size_t i = Acts::eBoundLoc0; i < Acts::eBoundSize; ++i) { - double sigma = initialSigmas[i]; - sigma += initialSimgaQoverPCoefficients[i] * params[Acts::eBoundQOverP]; - double var = sigma * sigma; - // var *= noTimeVarInflation.value(); - var *= initialVarInflation.value()[i]; - - cov(i, i) = var; - } - - recActsSvc->InitialParameters()->emplace_back(surface->getSharedPtr(), params, cov, particleHypothesis); - - return true; -} \ No newline at end of file diff --git a/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTruthTracking.h b/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTruthTracking.h deleted file mode 100644 index 19672f3b..00000000 --- a/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTruthTracking.h +++ /dev/null @@ -1,183 +0,0 @@ -#ifndef RecActsTruthTracking_H -#define RecActsTruthTracking_H - -// gaudi framework -#include "k4FWCore/DataHandle.h" -#include "GaudiAlg/GaudiAlgorithm.h" - -#include "UTIL/ILDConf.h" -#include "DataHelper/Navigation.h" - -// services -#include "RecActsSvc/IRecActsSvc.h" -#include "DetInterface/IGeomSvc.h" - -// DD4hep -#include "DD4hep/Detector.h" -#include "DDRec/ISurface.h" -#include "DDRec/SurfaceManager.h" - -// edm4hep -#include "edm4hep/MCParticle.h" -#include "edm4hep/MCParticleCollection.h" -#include "edm4hep/TrackerHitCollection.h" -#include "edm4hep/SimTrackerHitCollection.h" -#include "edm4hep/EventHeaderCollection.h" - -#include "edm4hep/Track.h" -#include "edm4hep/MutableTrack.h" -#include "edm4hep/TrackState.h" -#include "edm4hep/TrackCollection.h" -// Acts -#include "Acts/Definitions/Algebra.hpp" -#include "Acts/EventData/GenericBoundTrackParameters.hpp" -#include "Acts/EventData/SourceLink.hpp" -#include "Acts/EventData/TrackProxy.hpp" -#include "Acts/EventData/VectorMultiTrajectory.hpp" -#include "Acts/EventData/VectorTrackContainer.hpp" -#include "Acts/Propagator/Propagator.hpp" -#include "Acts/Surfaces/PerigeeSurface.hpp" -#include "Acts/Surfaces/Surface.hpp" -#include "Acts/Utilities/Result.hpp" - -#include "Acts/Definitions/Direction.hpp" -#include "Acts/Definitions/TrackParametrization.hpp" -#include "Acts/EventData/MultiTrajectory.hpp" -#include "Acts/EventData/TrackContainer.hpp" -#include "Acts/EventData/TrackStatePropMask.hpp" -#include "Acts/EventData/detail/CorrectedTransformationFreeToBound.hpp" -#include "Acts/Geometry/GeometryIdentifier.hpp" -#include "Acts/Propagator/DirectNavigator.hpp" -#include "Acts/Propagator/EigenStepper.hpp" -#include "Acts/Propagator/Navigator.hpp" -#include "Acts/TrackFitting/GlobalChiSquareFitter.hpp" -#include "Acts/TrackFitting/KalmanFitter.hpp" -#include "Acts/Utilities/Delegate.hpp" -#include "Acts/Utilities/Logger.hpp" - -namespace Acts -{ - class MagneticFieldProvider; - class TrackingGeometry; -} - -class RecActsTruthTracking : public GaudiAlgorithm -{ - public: - RecActsTruthTracking(const std::string& name, ISvcLocator* svcLoc); - - StatusCode initialize(); - StatusCode execute(); - StatusCode finalize(); - - private: - // Input collections - DataHandle<edm4hep::MCParticleCollection> _inMCColHdl{"MCParticle", Gaudi::DataHandle::Reader, this}; - - DataHandle<edm4hep::TrackerHitCollection> _inVTXTrackHdl{"VXDTrackerHits", Gaudi::DataHandle::Reader, this}; - DataHandle<edm4hep::TrackerHitCollection> _inITKBarrelTrackHdl{"ITKBarrelTrackerHits", Gaudi::DataHandle::Reader, this}; - DataHandle<edm4hep::TrackerHitCollection> _inITKEndcapTrackHdl{"ITKEndcapTrackerHits", Gaudi::DataHandle::Reader, this}; - DataHandle<edm4hep::TrackerHitCollection> _inOTKBarrelTrackHdl{"OTKBarrelTrackerHits", Gaudi::DataHandle::Reader, this}; - DataHandle<edm4hep::TrackerHitCollection> _inTPCTrackHdl{"TPCTrackerHits", Gaudi::DataHandle::Reader, this}; - - DataHandle<edm4hep::SimTrackerHitCollection> _inVTXColHdl{"VXDCollection", Gaudi::DataHandle::Reader, this}; - DataHandle<edm4hep::SimTrackerHitCollection> _inITKBarrelColHdl{"ITKBarrelCollection", Gaudi::DataHandle::Reader, this}; - DataHandle<edm4hep::SimTrackerHitCollection> _inITKEndcapColHdl{"ITKEndcapCollection", Gaudi::DataHandle::Reader, this}; - DataHandle<edm4hep::SimTrackerHitCollection> _inOTKBarrelColHdl{"OTKBarrelCollection", Gaudi::DataHandle::Reader, this}; - DataHandle<edm4hep::SimTrackerHitCollection> _inTPCColHdl{"TPCCollection", Gaudi::DataHandle::Reader, this}; - - // associations - DataHandle<edm4hep::MCRecoTrackerAssociationCollection> _inVTXAssColHdl{"VXDTrackerHitAssociation", Gaudi::DataHandle::Reader, this}; - DataHandle<edm4hep::MCRecoTrackerAssociationCollection> _inITKBarrelAssColHdl{"ITKBarrelTrackerHitAssociation", Gaudi::DataHandle::Reader, this}; - DataHandle<edm4hep::MCRecoTrackerAssociationCollection> _inITKEndcapAssColHdl{"ITKEndcapTrackerHitAssociation", Gaudi::DataHandle::Reader, this}; - DataHandle<edm4hep::MCRecoTrackerAssociationCollection> _inOTKBarrelAssColHdl{"OTKBarrelTrackerHitAssociation", Gaudi::DataHandle::Reader, this}; - DataHandle<edm4hep::MCRecoTrackerAssociationCollection> _inTPCAssColHdl{"TPCTrackerHitAss", Gaudi::DataHandle::Reader, this}; - - // Output collections - DataHandle<edm4hep::TrackCollection> _outColHdl{"ACTSTruthTracks", Gaudi::DataHandle::Writer, this}; - - Gaudi::Property<std::string> m_particle{this, "AssumeParticle", "muon"}; - Gaudi::Property<double> m_field{this, "bFieldInZ", 3.0}; // tesla - Gaudi::Property<std::vector<double>> initialVarInflation{this, "initialVarInflation", {1, 1, 1, 1, 1, 1}}; - Gaudi::Property<double> noTimeVarInflation{this, "noTimeVarInflation", 1.}; - - Gaudi::Property<bool> useMCTruth{this, "useMCTruth", false}; - Gaudi::Property<bool> useVTX{this, "useVTX", true}; - Gaudi::Property<bool> useITKBarrel{this, "useITKBarrel", true}; - Gaudi::Property<bool> useITKEndcap{this, "useITKEndcap", true}; - Gaudi::Property<bool> useTPC{this, "useTPC", true}; - Gaudi::Property<bool> useOTKBarrel{this, "useOTKBarrel", true}; - // Gaudi::Property<bool> useOTKEndcap{this, "useOTKEndcap", true}; - - // services - // SmartIF<IGeomSvc> m_geosvc; - SmartIF<IRecActsSvc> recActsSvc; - SmartIF<IChronoStatSvc> chronoStatSvc; - - bool ReadHits(const edm4hep::MCParticle& mc); - - // Decoders - dd4hep::DDSegmentation::BitFieldCoder *vtx_decoder; - dd4hep::DDSegmentation::BitFieldCoder *ITKBarrel_decoder; - dd4hep::DDSegmentation::BitFieldCoder *ITKEndcap_decoder; - dd4hep::DDSegmentation::BitFieldCoder *tpc_decoder; - dd4hep::DDSegmentation::BitFieldCoder *OTKBarrel_decoder; - - std::shared_ptr<ActsHelper::TrackFitterFunction> fit; - std::shared_ptr<const Acts::MagneticFieldProvider> magneticField; - // std::shared_ptr<ActsHelper::MeasurementCalibrator> m_calibrator; - - // globalChiSquareFitter config - bool multipleScattering = false; - bool energyLoss = false; - Acts::FreeToBoundCorrection freeToBoundCorrection; - std::size_t nUpdateMax = 5; - double relChi2changeCutOff = 1e-7; - - // context - Acts::GeometryContext geoContext; - Acts::MagneticFieldContext magFieldContext; - Acts::CalibrationContext calibContext; - - // double noTimeVarInflation = 10.; - std::array<double, 6> initialSigmas = { - 5 * Acts::UnitConstants::um, - 5 * Acts::UnitConstants::um, - 2e-2 * Acts::UnitConstants::degree, - 2e-2 * Acts::UnitConstants::degree, - 0 * Acts::UnitConstants::e / Acts::UnitConstants::GeV, - 1 * Acts::UnitConstants::s - }; - std::array<double, 6> initialSimgaQoverPCoefficients = { - 0 * Acts::UnitConstants::mm / (Acts::UnitConstants::e * Acts::UnitConstants::GeV), - 0 * Acts::UnitConstants::mm / (Acts::UnitConstants::e * Acts::UnitConstants::GeV), - 0 * Acts::UnitConstants::degree / (Acts::UnitConstants::e * Acts::UnitConstants::GeV), - 0 * Acts::UnitConstants::degree / (Acts::UnitConstants::e * Acts::UnitConstants::GeV), - 0.1, - 0 * Acts::UnitConstants::ns / (Acts::UnitConstants::e * Acts::UnitConstants::GeV) - }; - - std::array<std::string, 8> particleNames = {"muon", "pion", "electron", "kaon", "proton", "photon", "geantino", "chargedgeantino"}; - - // constants - const double _FCT = 2.99792458E-4; - uint64_t TPC_volume_id = 45; - uint64_t OTKBarrel_volume_id = 47; - uint64_t OTKEndcap_positive_volume_id = 2; - uint64_t OTKEndcap_negative_volume_id = 48; - std::vector<uint64_t> VXD_volume_ids{28, 29, 30, 31, 32}; - std::vector<uint64_t> ITKBarrel_volume_ids{35, 38, 41}; - std::vector<uint64_t> ITKEndcap_positive_volume_ids{36, 39, 42, 43}; - std::vector<uint64_t> ITKEndcap_negative_volume_ids{34, 17, 12, 10}; - std::vector<std::vector<uint64_t>> ITKEndcap_modules_per_ring{{13, 20, 0}, {16, 24, 28}, {24, 36, 44}, {24, 36, 44}}; - std::vector<uint64_t> ITKBarrel_module_nums{7, 10, 14}; - - const std::array<Acts::BoundIndices, 6> writeout_indices{ - Acts::BoundIndices::eBoundLoc0, Acts::BoundIndices::eBoundPhi, - Acts::BoundIndices::eBoundQOverP, Acts::BoundIndices::eBoundLoc1, - Acts::BoundIndices::eBoundTheta, Acts::BoundIndices::eBoundTime}; - Acts::ParticleHypothesis particleHypothesis = Acts::ParticleHypothesis::muon(); - int _nEvt; -}; - -#endif // RecActsTruthTracking_H \ No newline at end of file -- GitLab From 39321ba42b63c0e96a8543407345fd84162e0bcf Mon Sep 17 00:00:00 2001 From: "zhangyz@ihep.ac.cn" <zhangyz@ihep.ac.cn> Date: Thu, 5 Jun 2025 10:20:01 +0800 Subject: [PATCH 12/12] update ACTS for tdr25.5 --- .../RecActsTracking/CMakeLists.txt | 4 +- .../src/RecActsTrackReFitting.cpp | 401 ------------------ .../src/RecActsTrackReFitting.h | 153 ------- 3 files changed, 1 insertion(+), 557 deletions(-) delete mode 100644 Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTrackReFitting.cpp delete mode 100644 Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTrackReFitting.h diff --git a/Reconstruction/RecActsTracking/RecActsTracking/CMakeLists.txt b/Reconstruction/RecActsTracking/RecActsTracking/CMakeLists.txt index a0aad036..9fe46edd 100644 --- a/Reconstruction/RecActsTracking/RecActsTracking/CMakeLists.txt +++ b/Reconstruction/RecActsTracking/RecActsTracking/CMakeLists.txt @@ -10,13 +10,11 @@ endif() gaudi_add_module(RecActsTracking SOURCES src/RecActsReadInput.cpp - src/RecActsTruthInput.cpp src/RecActsSeeding.cpp src/RecActsTrackParamsEstimation.cpp src/RecActsTrackFinding.cpp src/RecActsTrackFitting.cpp - # src/RecActsTrackReFitting.cpp - # src/RecActsTruthTracking.cpp + LINK DetInterface k4FWCore::k4FWCore Gaudi::GaudiAlgLib Gaudi::GaudiKernel diff --git a/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTrackReFitting.cpp b/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTrackReFitting.cpp deleted file mode 100644 index 87ce36e5..00000000 --- a/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTrackReFitting.cpp +++ /dev/null @@ -1,401 +0,0 @@ -// dependence -#include "RecActsTrackReFitting.h" - -DECLARE_COMPONENT(RecActsTrackReFitting) - -RecActsTrackReFitting::RecActsTrackReFitting(const std::string& name, ISvcLocator* svcLoc) - : GaudiAlgorithm(name, svcLoc) -{ -} - -StatusCode RecActsTrackReFitting::initialize() -{ - // -------------------------------- - // ---- initialize properties ----- - // -------------------------------- - - info() << "Assume Particle: " << m_particle.value() << endmsg; - if(m_particle.value() == "muon"){ - particleHypothesis = Acts::ParticleHypothesis::muon(); - } - else if(m_particle.value() == "pion"){ - particleHypothesis = Acts::ParticleHypothesis::pion(); - } - else if(m_particle.value() == "electron"){ - particleHypothesis = Acts::ParticleHypothesis::electron(); - } - else if(m_particle.value() == "kaon"){ - particleHypothesis = Acts::ParticleHypothesis::kaon(); - } - else if(m_particle.value() == "proton"){ - particleHypothesis = Acts::ParticleHypothesis::proton(); - } - else if(m_particle.value() == "photon"){ - particleHypothesis = Acts::ParticleHypothesis::photon(); - } - else if(m_particle.value() == "geantino"){ - particleHypothesis = Acts::ParticleHypothesis::geantino(); - } - else if(m_particle.value() == "chargedgeantino"){ - particleHypothesis = Acts::ParticleHypothesis::chargedGeantino(); - } - else{ - info() << "Supported Assumed Particle: " << particleNames[0] << ", " << particleNames[1] << ", " << particleNames[2] << ", " - << particleNames[3] << ", " << particleNames[4] << ", " << particleNames[5] << ", " - << particleNames[6] << ", " << particleNames[7] << endmsg; - error() << "Unsupported particle name " << m_particle.value() << endmsg; - return StatusCode::FAILURE; - } - - vtx_decoder = new dd4hep::DDSegmentation::BitFieldCoder("system:5,side:-2,layer:9,module:8,sensor:32:16"); - if(!vtx_decoder){ - info() << "Failed to create vtx_decoder" << endmsg; - return StatusCode::FAILURE; - } - - ITKBarrel_decoder = new dd4hep::DDSegmentation::BitFieldCoder("system:5,side:-2,layer:9,stave:8,module:8,sensor:5"); - if(!ITKBarrel_decoder){ - info() << "Failed to create ITKBarrel_decoder" << endmsg; - return StatusCode::FAILURE; - } - - ITKEndcap_decoder = new dd4hep::DDSegmentation::BitFieldCoder("system:5,side:-2,layer:9,module:8,sensor:8"); - if(!ITKEndcap_decoder){ - info() << "Failed to create ITKEndcap_decoder" << endmsg; - return StatusCode::FAILURE; - } - - tpc_decoder = new dd4hep::DDSegmentation::BitFieldCoder("system:5,side:-2,layer:13,module:6,sensor:6"); - if(!tpc_decoder){ - info() << "Failed to create TPC_decoder" << endmsg; - return StatusCode::FAILURE; - } - - OTKBarrel_decoder = new dd4hep::DDSegmentation::BitFieldCoder("system:5,side:-2,layer:9,module:8,iladder:32:4,oladder:-4,mmodule:-6"); - if(!OTKBarrel_decoder){ - info() << "Failed to create OTKBarrel_decoder" << endmsg; - return StatusCode::FAILURE; - } - - recActsSvc = service<IRecActsSvc>("RecActsSvc"); - if (!recActsSvc) { - error() << "Failed to get RecActsSvc" << endmsg; - return StatusCode::FAILURE; - } - - // -------------------------------- - // ---- initialize recActsSvc ---- - // -------------------------------- - - recActsSvc = service<IRecActsSvc>("RecActsSvc"); - if (!recActsSvc) { - error() << "Failed to get RecActsSvc" << endmsg; - return StatusCode::FAILURE; - } - - magneticField = std::make_shared<Acts::ConstantBField>(Acts::Vector3(0., 0., m_field.value()*_FCT)); - fit = ActsHelper::makeKalmanFitterFunction(recActsSvc->Geometry(), magneticField); - // fit = ActsHelper::makeGsfFitterFunction(recActsSvc->Geometry(), magneticField); (not working) - // fit = ActsHelper::makeGlobalChiSquareFitterFunction(recActsSvc->Geometry(), magneticField); (ok) - - _nEvt = -1; - return StatusCode::SUCCESS; -} - -StatusCode RecActsTrackReFitting::execute() -{ - _nEvt++; - - auto trkCol = _outColHdl.createAndPut(); - - const edm4hep::TrackCollection* trackCols = nullptr; - try { trackCols = _inTrackColHdl.get(); } - catch ( GaudiException &e ) - { debug() << "Collection " << _inTrackColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; } - - const edm4hep::MCRecoTrackerAssociationCollection* vtxHitAssCols = nullptr; - try { vtxHitAssCols = _inVTXAssColHdl.get(); } - catch ( GaudiException &e ) - { debug() << "Collection " << _inVTXAssColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg; } - - std::map<int, int> hitNumbers; - - hitNumbers[UTIL::ILDDetID::VXD] = 0; - hitNumbers[UTIL::ILDDetID::SIT] = 0; - hitNumbers[UTIL::ILDDetID::FTD] = 0; - hitNumbers[UTIL::ILDDetID::TPC] = 0; - hitNumbers[UTIL::ILDDetID::SET] = 0; - hitNumbers[UTIL::ILDDetID::ETD] = 0; - - if(trackCols){ - int Track_count = 0; - for(auto track : *trackCols){ - recActsSvc->Clean(); - Track_count++; - unsigned int nHits = track.trackerHits_size(); - - std::vector<int> hit_indices; - std::vector<float> hit_radii; - for(int ielem = 0; ielem < nHits; ++ielem){ - const edm4hep::TrackerHit& hit = track.getTrackerHits(ielem); - float hit_r = std::hypot(hit.getPosition()[0], hit.getPosition()[1]); - hit_indices.push_back(ielem); - hit_radii.push_back(hit_r); - } - - std::sort(hit_indices.begin(), hit_indices.end(), - [&hit_radii](int i1, int i2) { return hit_radii[i1] < hit_radii[i2]; }); - - auto first_hit = track.getTrackerHits(hit_indices[0]); - - std::vector<edm4hep::SimTrackerHit> first_simHits; - for(auto ass : *vtxHitAssCols){ - if(ass.getRec().getObjectID().collectionID != first_hit.getObjectID().collectionID) break; - else if(ass.getRec()==first_hit) first_simHits.push_back(ass.getSim()); - } - - if(first_simHits.size() == 0){ - info() << "Skip: Not found VTX simHit in AssociationCollection for track " << Track_count << " at event " << _nEvt << endmsg; - continue; - } - - auto first_simhit = first_simHits[0]; - double px = first_simhit.getMomentum()[0]; - double py = first_simhit.getMomentum()[1]; - double pz = first_simhit.getMomentum()[2]; - - for(int i_hit : hit_indices){ - const edm4hep::TrackerHit& hit = track.getTrackerHits(i_hit); - auto cellid = hit.getCellID(); - UTIL::BitField64 encoder(UTIL::ILDCellID0::encoder_string); - encoder.setValue(cellid); - int subdet = encoder[UTIL::ILDCellID0::subdet]; - ++hitNumbers[subdet]; - - if(subdet==UTIL::ILDDetID::VXD) - { - uint64_t m_layer = vtx_decoder->get(cellid, "layer"); - uint64_t m_module = vtx_decoder->get(cellid, "module"); - - if(m_layer <= 3){ - uint64_t acts_volume = VXD_volume_ids[m_layer]; - uint64_t acts_layer = 2; - uint64_t acts_sensitive = 1; - bool buildSpacePoint = false; - int moduleType = 1; - double onSurfaceTolerance = 1e-4; - - if (!recActsSvc->ReadInput(hit, - acts_volume, acts_layer, acts_sensitive, - buildSpacePoint, moduleType, onSurfaceTolerance)) - { - info() << "Failed to read VXD hit: layer " << m_layer << ", module " << m_module << endmsg; - } - } else { - uint64_t acts_volume = VXD_volume_ids[4]; - uint64_t acts_layer = 2; - uint64_t acts_sensitive = (m_layer == 5) ? m_module*2 + 1 : m_module*2 + 2;; - - if (!recActsSvc->ReadInput(hit, - acts_volume, acts_layer, acts_sensitive)) - { - info() << "Failed to read VXD hit: layer " << m_layer << ", module " << m_module << endmsg; - } - } - } - else if(subdet==UTIL::ILDDetID::SIT) - { - uint64_t m_layer = ITKBarrel_decoder->get(cellid, "layer"); - uint64_t m_stave = ITKBarrel_decoder->get(cellid, "stave"); - - uint64_t acts_volume = ITKBarrel_volume_ids[m_layer]; - uint64_t acts_layer = 2; - uint64_t acts_sensitive = m_stave + 1; - if (!recActsSvc->ReadInput(hit, - acts_volume, acts_layer, acts_sensitive)) - { - info() << "Failed to read ITKBarrel hit: layer " << m_layer << ", stave " << m_stave << endmsg; - } - } - else if(subdet==UTIL::ILDDetID::FTD) - { - int m_side = ITKEndcap_decoder->get(cellid, "side"); - uint64_t m_layer = ITKEndcap_decoder->get(cellid, "layer"); - uint64_t m_module = ITKEndcap_decoder->get(cellid, "module"); - - uint64_t acts_volume = (m_side == 1) ? ITKEndcap_positive_volume_ids[m_layer] : ITKEndcap_negative_volume_ids[m_layer]; - uint64_t acts_layer = 2; - uint64_t acts_sensitive = m_module + 1; - if (!recActsSvc->ReadInput(hit, - acts_volume, acts_layer, acts_sensitive)) - { - info() << "Failed to read ITKEndcap hit: side " << m_side << ", layer " << m_layer << ", module " << m_module << endmsg; - } - } - else if(subdet==UTIL::ILDDetID::TPC) - { - uint64_t m_layer = tpc_decoder->get(cellid, "layer"); - - uint64_t acts_volume = TPC_volume_id; - uint64_t acts_layer = (m_layer + 1) * 2; - uint64_t acts_sensitive = 1; - bool buildSpacePoint = false; - int moduleType = 2; - double onSurfaceTolerance = 1e-4; - - if (!recActsSvc->ReadInput(hit, - acts_volume, acts_layer, acts_sensitive, - buildSpacePoint, moduleType, onSurfaceTolerance)) - { - info() << "Failed to read TPC hit: layer " << m_layer << endmsg; - } - } - else if(subdet==UTIL::ILDDetID::SET) - { - uint64_t m_module = OTKBarrel_decoder->get(cellid, "module"); - - uint64_t acts_volume = OTK_volume_id; - uint64_t acts_layer = 2; - uint64_t acts_sensitive = m_module + 1; - if (!recActsSvc->ReadInput(hit, - acts_volume, acts_layer, acts_sensitive)) - { - info() << "Failed to read OTKBarrel hit: module " << m_module << endmsg; - } - } - else - { - debug() << "not supported subdetector: " << subdet << endmsg; - } - } - - double p = sqrt(px*px + py*py + pz*pz); - double phi = atan2(py, px); - double theta = atan2(sqrt(px*px + py*py), pz); - double qop = -1 / p; - - Acts::BoundVector params = Acts::BoundVector::Zero(); - Acts::BoundSquareMatrix cov = Acts::BoundSquareMatrix::Zero(); - ActsHelper::IndexSourceLink::SurfaceAccessor surfaceAccessor{*recActsSvc->Geometry()}; - - // (TODO) assume the first hit is the first measurement - auto first_hit_meas = recActsSvc->Measurements()->at(0); - auto cur_meas_param = std::get<1>(first_hit_meas).parameters(); - auto cur_meas_sl = std::get<1>(first_hit_meas).sourceLink(); - const Acts::Surface* surface = surfaceAccessor(cur_meas_sl); - - params[Acts::eBoundLoc0] = cur_meas_param[Acts::eBoundLoc0]; - params[Acts::eBoundLoc1] = cur_meas_param[Acts::eBoundLoc1]; - params[Acts::eBoundPhi] = phi; - params[Acts::eBoundTheta] = theta; - params[Acts::eBoundQOverP] = qop; - params[Acts::eBoundTime] = 0; - - for (std::size_t i = Acts::eBoundLoc0; i < Acts::eBoundSize; ++i) { - double sigma = initialSigmas[i]; - sigma += abs(initialSimgaQoverPCoefficients[i] * params[Acts::eBoundQOverP]); - double var = sigma * sigma; - // var *= noTimeVarInflation.value(); - var *= initialVarInflation.value()[i]; - - cov(i, i) = var; - } - - recActsSvc->InitialParameters()->emplace_back(surface->getSharedPtr(), params, cov, particleHypothesis); - - auto measurements = recActsSvc->Measurements(); - auto trackSourceLinks = recActsSvc->SourceLinks(); - auto initialParams = recActsSvc->InitialParameters(); - - // info() << "debug: event " << _nEvt << ", track " << Track_count << endmsg; - // info() << "measurements size: " << measurements->size() << endmsg; - // info() << "trackSourceLinks size: " << trackSourceLinks->size() << endmsg; - // info() << "initialParams size: " << initialParams->size() << endmsg; - - if (initialParams->size() == 0) { - info() << "No initial parameters found for track " << Track_count << " at event " << _nEvt << endmsg; - continue; - } - - auto pSurface = Acts::Surface::makeShared<Acts::PerigeeSurface>(Acts::Vector3{0., 0., 0.}); - ActsHelper::PassThroughCalibrator pcalibrator; - ActsHelper::MeasurementCalibratorAdapter calibrator(pcalibrator, *measurements); - ActsHelper::TrackFitterFunction::GeneralFitterOptions options{ - geoContext, magFieldContext, calibContext, pSurface.get(), Acts::PropagatorPlainOptions()}; - - auto trackContainer = std::make_shared<Acts::VectorTrackContainer>(); - auto trackStateContainer = std::make_shared<Acts::VectorMultiTrajectory>(); - ActsHelper::TrackContainer tracks(trackContainer, trackStateContainer); - - std::vector<Acts::SourceLink> cur_trackSourceLinks; - for (const auto& sourceLink : *trackSourceLinks) { - cur_trackSourceLinks.push_back(Acts::SourceLink{sourceLink}); - } - - auto result = (*fit)(cur_trackSourceLinks, initialParams->at(0), options, calibrator, tracks); - if (!result.ok()) { - info() << "Track fit failed for track " << Track_count << " at event " << _nEvt << endmsg; - continue; - } - - // std::stringstream ss; - // trackStateContainer->statistics().toStream(ss); - // debug() << ss.str() << endmsg; - - ActsHelper::ConstTrackContainer constTracks - { - std::make_shared<Acts::ConstVectorTrackContainer>(std::move(*trackContainer)), - std::make_shared<Acts::ConstVectorMultiTrajectory>(std::move(*trackStateContainer)) - }; - - if (constTracks.size() == 0) { - info() << "No tracks fitted for track " << Track_count << " at event " << _nEvt << endmsg; - continue; - } else if (constTracks.size() > 1) { - info() << "Number of tracks fitted: " << constTracks.size() << " for track " << Track_count << " at event " << _nEvt << endmsg; - } - - for (const auto& cur_track : constTracks) - { - auto writeout_track = trkCol->create(); - - writeout_track.setChi2(cur_track.chi2()); - writeout_track.setNdf(cur_track.nDoF()); - writeout_track.setDEdx(cur_track.absoluteMomentum() / Acts::UnitConstants::GeV); - writeout_track.setDEdxError(0); - - // TODO: covmatrix need to be converted - std::array<float, 21> writeout_covMatrix; - auto cur_track_covariance = cur_track.covariance(); - for (int i = 0; i < 6; i++) { - for (int j = 0; j < 6-i; j++) { - writeout_covMatrix[int((13-i)*i/2 + j)] = cur_track_covariance(writeout_indices[i], writeout_indices[j]); - } - } - // location: At{Other|IP|FirstHit|LastHit|Calorimeter|Vertex}|LastLocation - // TrackState: location, d0, phi, omega, z0, tanLambda, time, referencePoint, covMatrix - edm4hep::TrackState writeout_trackState{ - 1, // location: AtOther - cur_track.loc0() / Acts::UnitConstants::mm, // d0 - cur_track.phi(), // phi - cur_track.qOverP() * _FCT * m_field / sin(cur_track.theta()) , // omega = qop * sin(theta) * _FCT * bf - cur_track.loc1() / Acts::UnitConstants::mm, // z0 - 1 / tan(cur_track.theta()), // tanLambda = 1 / tan(theta) - cur_track.time(), // time - ::edm4hep::Vector3f(0, 0, 0), // referencePoint - writeout_covMatrix - }; - - debug() << "Found track with momentum " << cur_track.absoluteMomentum() / Acts::UnitConstants::GeV << " GeV!" << endmsg; - writeout_track.addToTrackStates(writeout_trackState); - } - } - } - - return StatusCode::SUCCESS; -} - -StatusCode RecActsTrackReFitting::finalize() -{ - return StatusCode::SUCCESS; -} \ No newline at end of file diff --git a/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTrackReFitting.h b/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTrackReFitting.h deleted file mode 100644 index 97f091c5..00000000 --- a/Reconstruction/RecActsTracking/RecActsTracking/src/RecActsTrackReFitting.h +++ /dev/null @@ -1,153 +0,0 @@ -#ifndef RecActsTrackReFitting_H -#define RecActsTrackReFitting_H - -// gaudi framework -#include "k4FWCore/DataHandle.h" -#include "GaudiAlg/GaudiAlgorithm.h" - -#include "UTIL/ILDConf.h" -#include "DataHelper/Navigation.h" - -// services -#include "RecActsSvc/IRecActsSvc.h" -#include "DetInterface/IGeomSvc.h" - -// DD4hep -#include "DD4hep/Detector.h" -#include "DDRec/ISurface.h" -#include "DDRec/SurfaceManager.h" - -// edm4hep -#include "edm4hep/MCParticle.h" -#include "edm4hep/MCParticleCollection.h" -#include "edm4hep/TrackerHitCollection.h" -#include "edm4hep/SimTrackerHitCollection.h" -#include "edm4hep/EventHeaderCollection.h" - -#include "edm4hep/Track.h" -#include "edm4hep/MutableTrack.h" -#include "edm4hep/TrackState.h" -#include "edm4hep/TrackCollection.h" -// Acts -#include "Acts/Definitions/Algebra.hpp" -#include "Acts/EventData/GenericBoundTrackParameters.hpp" -#include "Acts/EventData/SourceLink.hpp" -#include "Acts/EventData/TrackProxy.hpp" -#include "Acts/EventData/VectorMultiTrajectory.hpp" -#include "Acts/EventData/VectorTrackContainer.hpp" -#include "Acts/Propagator/Propagator.hpp" -#include "Acts/Surfaces/PerigeeSurface.hpp" -#include "Acts/Surfaces/Surface.hpp" -#include "Acts/Utilities/Result.hpp" - -#include "Acts/Definitions/Direction.hpp" -#include "Acts/Definitions/TrackParametrization.hpp" -#include "Acts/EventData/MultiTrajectory.hpp" -#include "Acts/EventData/TrackContainer.hpp" -#include "Acts/EventData/TrackStatePropMask.hpp" -#include "Acts/EventData/detail/CorrectedTransformationFreeToBound.hpp" -#include "Acts/Geometry/GeometryIdentifier.hpp" -#include "Acts/Propagator/DirectNavigator.hpp" -#include "Acts/Propagator/EigenStepper.hpp" -#include "Acts/Propagator/Navigator.hpp" -#include "Acts/TrackFitting/GlobalChiSquareFitter.hpp" -#include "Acts/TrackFitting/KalmanFitter.hpp" -#include "Acts/Utilities/Delegate.hpp" -#include "Acts/Utilities/Logger.hpp" - -namespace Acts -{ - class MagneticFieldProvider; - class TrackingGeometry; -} - -class RecActsTrackReFitting : public GaudiAlgorithm -{ - public: - RecActsTrackReFitting(const std::string& name, ISvcLocator* svcLoc); - - StatusCode initialize(); - StatusCode execute(); - StatusCode finalize(); - - private: - // Input collections - DataHandle<edm4hep::TrackCollection> _inTrackColHdl{"CompleteTracks", Gaudi::DataHandle::Reader, this}; - - // associations - DataHandle<edm4hep::MCRecoTrackerAssociationCollection> _inVTXAssColHdl{"VXDTrackerHitAssociation", Gaudi::DataHandle::Reader, this}; - - // Output collections - DataHandle<edm4hep::TrackCollection> _outColHdl{"ACTSRefitTracks", Gaudi::DataHandle::Writer, this}; - - Gaudi::Property<std::string> m_particle{this, "AssumeParticle", "muon"}; - Gaudi::Property<double> m_field{this, "bFieldInZ", 3.0}; // tesla - Gaudi::Property<std::vector<double>> initialVarInflation{this, "initialVarInflation", {1, 1, 1, 1, 1, 1}}; - Gaudi::Property<double> noTimeVarInflation{this, "noTimeVarInflation", 1.}; - - // services - // SmartIF<IGeomSvc> m_geosvc; - SmartIF<IRecActsSvc> recActsSvc; - SmartIF<IChronoStatSvc> chronoStatSvc; - - // Decoders - dd4hep::DDSegmentation::BitFieldCoder *vtx_decoder; - dd4hep::DDSegmentation::BitFieldCoder *ITKBarrel_decoder; - dd4hep::DDSegmentation::BitFieldCoder *ITKEndcap_decoder; - dd4hep::DDSegmentation::BitFieldCoder *tpc_decoder; - dd4hep::DDSegmentation::BitFieldCoder *OTKBarrel_decoder; - - std::shared_ptr<ActsHelper::TrackFitterFunction> fit; - std::shared_ptr<const Acts::MagneticFieldProvider> magneticField; - // std::shared_ptr<ActsHelper::MeasurementCalibrator> m_calibrator; - - // globalChiSquareFitter config - bool multipleScattering = false; - bool energyLoss = false; - Acts::FreeToBoundCorrection freeToBoundCorrection; - std::size_t nUpdateMax = 5; - double relChi2changeCutOff = 1e-7; - - // context - Acts::GeometryContext geoContext; - Acts::MagneticFieldContext magFieldContext; - Acts::CalibrationContext calibContext; - - // double noTimeVarInflation = 10.; - std::array<double, 6> initialSigmas = { - 5 * Acts::UnitConstants::um, - 5 * Acts::UnitConstants::um, - 2e-2 * Acts::UnitConstants::degree, - 2e-2 * Acts::UnitConstants::degree, - 1e-1 * Acts::UnitConstants::e / Acts::UnitConstants::GeV, - 1 * Acts::UnitConstants::s - }; - std::array<double, 6> initialSimgaQoverPCoefficients = { - 0 * Acts::UnitConstants::mm / (Acts::UnitConstants::e * Acts::UnitConstants::GeV), - 0 * Acts::UnitConstants::mm / (Acts::UnitConstants::e * Acts::UnitConstants::GeV), - 0 * Acts::UnitConstants::degree / (Acts::UnitConstants::e * Acts::UnitConstants::GeV), - 0 * Acts::UnitConstants::degree / (Acts::UnitConstants::e * Acts::UnitConstants::GeV), - 1e-1, - 0 * Acts::UnitConstants::ns / (Acts::UnitConstants::e * Acts::UnitConstants::GeV) - }; - - std::array<std::string, 8> particleNames = {"muon", "pion", "electron", "kaon", "proton", "photon", "geantino", "chargedgeantino"}; - - // constants - const double _FCT = 2.99792458E-4; - uint64_t TPC_volume_id = 43; - uint64_t OTK_volume_id = 45; - std::vector<uint64_t> VXD_volume_ids{26, 27, 28, 29, 30}; - std::vector<uint64_t> ITKBarrel_volume_ids{33, 36, 39}; - std::vector<uint64_t> ITKEndcap_positive_volume_ids{34, 37, 40, 41}; - std::vector<uint64_t> ITKEndcap_negative_volume_ids{32, 15, 10, 8}; - std::vector<uint64_t> ITKBarrel_module_nums{7, 10, 14}; - const std::array<Acts::BoundIndices, 6> writeout_indices{ - Acts::BoundIndices::eBoundLoc0, Acts::BoundIndices::eBoundPhi, - Acts::BoundIndices::eBoundQOverP, Acts::BoundIndices::eBoundLoc1, - Acts::BoundIndices::eBoundTheta, Acts::BoundIndices::eBoundTime}; - Acts::ParticleHypothesis particleHypothesis = Acts::ParticleHypothesis::muon(); - int _nEvt; -}; - -#endif // RecActsTrackReFitting_H \ No newline at end of file -- GitLab