From d8b8dac613d90b83d554da27b8660b5e9bf289c4 Mon Sep 17 00:00:00 2001
From: Oleksii Lubynets <lubynets@lxbk0200.gsi.de>
Date: Sun, 13 Sep 2020 18:26:40 +0200
Subject: [PATCH] add AT->KFPF interface

---
 analysis/CMakeLists.txt                       |   1 +
 .../at_kfpf_interface/ATKFParticleFinder.cxx  | 241 ++++++++++++++++++
 .../at_kfpf_interface/ATKFParticleFinder.h    |  68 +++++
 .../AnalysisTreeKfpfInterfaceLinkDef.h        |  10 +
 .../common/at_kfpf_interface/CMakeLists.txt   |  67 +++++
 .../at_kfpf_interface/CutsContainer.cxx       |   1 +
 .../common/at_kfpf_interface/CutsContainer.h  |  45 ++++
 7 files changed, 433 insertions(+)
 create mode 100644 analysis/common/at_kfpf_interface/ATKFParticleFinder.cxx
 create mode 100644 analysis/common/at_kfpf_interface/ATKFParticleFinder.h
 create mode 100644 analysis/common/at_kfpf_interface/AnalysisTreeKfpfInterfaceLinkDef.h
 create mode 100644 analysis/common/at_kfpf_interface/CMakeLists.txt
 create mode 100644 analysis/common/at_kfpf_interface/CutsContainer.cxx
 create mode 100644 analysis/common/at_kfpf_interface/CutsContainer.h

diff --git a/analysis/CMakeLists.txt b/analysis/CMakeLists.txt
index b854f7910b..13e0bf3759 100644
--- a/analysis/CMakeLists.txt
+++ b/analysis/CMakeLists.txt
@@ -13,6 +13,7 @@ add_subdirectory (PWGCHA/jpsi)
 add_subdirectory (PWGHAD/hadron)
 
 add_subdirectory (common/analysis_tree_converter)
+add_subdirectory (common/at_kfpf_interface)
 
 add_subdirectory (detectors)
 
diff --git a/analysis/common/at_kfpf_interface/ATKFParticleFinder.cxx b/analysis/common/at_kfpf_interface/ATKFParticleFinder.cxx
new file mode 100644
index 0000000000..0332d3a986
--- /dev/null
+++ b/analysis/common/at_kfpf_interface/ATKFParticleFinder.cxx
@@ -0,0 +1,241 @@
+#include "ATKFParticleFinder.h"
+
+void ATKFParticleFinder::InitInput(const std::string& file_name, const std::string& tree_name)
+{
+  std::cout << "ATKFParticleFinder::InitInput()\n";
+  
+//   topo_reconstructor_ = new KFParticleTopoReconstructor;
+//   topo_reconstructor_->Clear();
+  
+  in_file_ = TFile::Open(file_name.c_str(), "read");
+  config_ = (AnalysisTree::Configuration*) in_file_->Get("Configuration");
+
+  in_chain_ =  new TChain(tree_name.c_str());
+  in_chain_ -> Add(file_name.c_str());
+  in_chain_ -> SetBranchAddress("VtxTracks", &kf_tracks_);
+  in_chain_ -> SetBranchAddress("RecEventHeader", &rec_event_header_);
+
+  auto branch_conf_kftr = config_->GetBranchConfig( "VtxTracks" );
+  q_field_id_ = branch_conf_kftr.GetFieldId("q");
+
+  par_field_id_ = branch_conf_kftr.GetFieldId("x");   // par0
+  mf_field_id_ = branch_conf_kftr.GetFieldId("cx0");  // magnetic field par0
+  cov_field_id_ = branch_conf_kftr.GetFieldId("cov1"); // cov matrix 0
+  
+  passcuts_field_id_ = branch_conf_kftr.GetFieldId("pass_cuts");
+  pdg_field_id_ = branch_conf_kftr.GetFieldId("mc_pdg");
+  nhits_field_id_ = branch_conf_kftr.GetFieldId("nhits");
+  nhits_mvd_field_id_ = branch_conf_kftr.GetFieldId("nhits_mvd");
+  vtx_chi2_field_id_ = branch_conf_kftr.GetFieldId("vtx_chi2");
+}
+
+void ATKFParticleFinder::InitOutput(const std::string& file_name)
+{
+  std::cout << "ATKFParticleFinder::InitOutput()\n";
+  
+  out_file_ = TFile::Open(file_name.c_str(), "recreate");
+  
+  AnalysisTree::BranchConfig ParticlesRecoBranch("ParticlesReconstructed", AnalysisTree::DetType::kParticle);
+  
+  ParticlesRecoBranch.AddField<int>("daughter1id");
+  ParticlesRecoBranch.AddField<int>("daughter2id");
+  
+  out_config_.AddBranchConfig( ParticlesRecoBranch );
+  particles_reco_ = new AnalysisTree::Particles(out_config_.GetLastId());
+  
+  out_tree_ = new TTree("aTree", "AnalysisTree ParticlesReco");
+  out_tree_ -> Branch("ParticlesReconstructed", "AnalysisTree::Particles", &particles_reco_);
+  out_config_.Write("Configuration");
+  
+  daughter1_id_field_id_ = out_config_.GetBranchConfig( particles_reco_->GetId() ).GetFieldId("daughter1id");
+  daughter2_id_field_id_ = out_config_.GetBranchConfig( particles_reco_->GetId() ).GetFieldId("daughter2id");  
+}
+
+void ATKFParticleFinder::Finish()
+{
+  std::cout << "ATKFParticleFinder::Finish()\n";
+  
+  out_tree_->Write();  
+  out_file_->Close();
+}
+
+void ATKFParticleFinder::Run(int n_events)
+{
+  if(n_events<0 || n_events>in_chain_->GetEntries())
+    n_events = in_chain_->GetEntries();
+  
+  std::cout << "ATKFParticleFinder::Run() " << n_events << " events\n";
+  
+  for(int i_event=0; i_event<n_events; i_event++)
+  {
+    std::cout << "eveNo = " << i_event << "\n";
+    in_chain_->GetEntry(i_event);
+    KFParticleTopoReconstructor* eventTopoReconstructor = CreateTopoReconstructor();
+    
+//     const KFPTrackVector* tv = eventTopoReconstructor->GetTracks();
+//     KFPTrackVector tvv = *tv;
+//     tvv.Print();
+    
+    eventTopoReconstructor->SortTracks();
+    eventTopoReconstructor->ReconstructParticles();
+       
+    WriteCandidates(eventTopoReconstructor);
+  }
+  Finish();
+}
+
+KFParticleTopoReconstructor* ATKFParticleFinder::CreateTopoReconstructor()
+{
+// 
+// Creates the pointer on the KFParticleTopoReconstructor object
+// with all necessary input information in order to perform particle selection using
+// non-simplified "standard" KFParticle algorithm. 
+// 
+  auto* TR = new KFParticleTopoReconstructor;
+  
+  // cuts setting
+  TR -> GetKFParticleFinder() -> SetChiPrimaryCut2D(cuts_.GetCutChi2Prim());
+  TR -> GetKFParticleFinder() -> SetMaxDistanceBetweenParticlesCut(cuts_.GetCutDistance());
+  TR -> GetKFParticleFinder() -> SetChi2Cut2D(cuts_.GetCutChi2Geo());
+  TR -> GetKFParticleFinder() -> SetLCut(cuts_.GetCutLDown());
+  TR -> GetKFParticleFinder() -> SetLdLCut2D(cuts_.GetCutLdL());
+  
+  int n_good_tracks=0;
+  
+  for(int i_track=0; i_track < kf_tracks_->GetNumberOfChannels(); i_track++)
+  {
+    const AnalysisTree::Track& rec_track = kf_tracks_->GetChannel(i_track);
+    if(rec_track.GetField<bool>(passcuts_field_id_)==0) continue;
+    if(rec_track.GetField<int>(pdg_field_id_)==-2 && pid_mode_==1) continue;
+    n_good_tracks++;
+  }
+    
+  KFPTrackVector track_vector1, track_vector2;
+  track_vector1.Resize(n_good_tracks);
+  
+  int j_track = 0;
+    
+  for(int i_track=0; i_track < kf_tracks_->GetNumberOfChannels(); i_track++)
+  {
+    const AnalysisTree::Track& rec_track = kf_tracks_->GetChannel(i_track);
+    
+    if(rec_track.GetField<bool>(passcuts_field_id_)==0) continue;
+    if(rec_track.GetField<int>(pdg_field_id_)==-2 && pid_mode_==1) continue;
+    
+    for(Int_t iP=0; iP<3; iP++)
+      track_vector1.SetParameter(rec_track.GetField<float>(par_field_id_+iP), iP, j_track);
+    track_vector1.SetParameter(rec_track.GetPx(), 3, j_track);
+    track_vector1.SetParameter(rec_track.GetPy(), 4, j_track);
+    track_vector1.SetParameter(rec_track.GetPz(), 5, j_track);
+    auto cov_matrix = GetCovMatrixCbm(rec_track);
+    for(Int_t iC=0; iC<21; iC++)
+      track_vector1.SetCovariance(cov_matrix.at(iC), iC, j_track);
+    for(Int_t iF=0; iF<10; iF++)
+      track_vector1.SetFieldCoefficient(rec_track.GetField<float>(mf_field_id_+iF), iF, j_track);
+    if(pid_mode_==0)
+      track_vector1.SetPDG(-1, j_track);
+    else if (pid_mode_==1)
+      track_vector1.SetPDG(rec_track.GetField<int>(pdg_field_id_), j_track);
+    track_vector1.SetQ(rec_track.GetField<int>(q_field_id_), j_track);
+    if(rec_track.GetField<float>(vtx_chi2_field_id_)<3.)
+      track_vector1.SetPVIndex(0, j_track);
+    else
+      track_vector1.SetPVIndex(-1, j_track);
+    track_vector1.SetNPixelHits(rec_track.GetField<int>(nhits_mvd_field_id_), j_track);
+    track_vector1.SetId(rec_track.GetId(), j_track);  
+    j_track++;
+  }
+  TR->Init(track_vector1, track_vector2);
+  
+  KFPVertex primVtx_tmp;
+  primVtx_tmp.SetXYZ(rec_event_header_->GetVertexX(), rec_event_header_->GetVertexY(), rec_event_header_->GetVertexZ());
+  primVtx_tmp.SetCovarianceMatrix( 0,0,0,0,0,0 );
+  primVtx_tmp.SetNContributors( 0 );
+  primVtx_tmp.SetChi2( -100 );
+  std::vector<int> pvTrackIds;
+  KFVertex pv(primVtx_tmp);
+  TR->AddPV(pv, pvTrackIds);
+  
+  std::cout << track_vector1.Size() << "\n";
+
+  return TR; 
+}
+
+void ATKFParticleFinder::WriteCandidates(const KFParticleTopoReconstructor* eventTR)
+{
+  particles_reco_->ClearChannels();
+  
+  for(unsigned int iP=0;iP<eventTR->GetParticles().size();iP++)
+  {
+    const KFParticle& particle = eventTR->GetParticles()[iP];
+    
+    auto* particlerec = particles_reco_->AddChannel();
+    particlerec->Init(out_config_.GetBranchConfig(particles_reco_->GetId()));
+    
+    float mass, masserr;
+    particle.GetMass(mass, masserr);
+    particlerec->SetMass(mass);
+    particlerec->SetField(particle.DaughterIds()[0], daughter1_id_field_id_);
+    particlerec->SetField(particle.DaughterIds()[1], daughter2_id_field_id_);    
+    particlerec->SetMomentum(particle.GetPx(), particle.GetPy(), particle.GetPz());
+    particlerec->SetPid ( particle.GetPDG() );
+        
+//     topo_reconstructor_->AddParticle(particle);
+  }
+  out_tree_->Fill();
+}
+
+std::vector<float> ATKFParticleFinder::GetCovMatrixCbm(const AnalysisTree::Track& track) const
+{
+  const double tx = track.GetField<float>(par_field_id_+3); 
+  const double ty = track.GetField<float>(par_field_id_+4); 
+  const double qp = track.GetField<float>(par_field_id_+5);
+  const Int_t q = track.GetField<int>(q_field_id_);
+  
+  //calculate covariance matrix
+  const double t = sqrt(1.f + tx*tx + ty*ty);
+  const double t3 = t*t*t;
+  const double dpxdtx = q/qp*(1.f+ty*ty)/t3;
+  const double dpxdty = -q/qp*tx*ty/t3;
+  const double dpxdqp = -q/(qp*qp)*tx/t;
+  const double dpydtx = -q/qp*tx*ty/t3;
+  const double dpydty = q/qp*(1.f+tx*tx)/t3;
+  const double dpydqp = -q/(qp*qp)*ty/t;
+  const double dpzdtx = -q/qp*tx/t3;
+  const double dpzdty = -q/qp*ty/t3;
+  const double dpzdqp = -q/(qp*qp*t3);
+  
+  const double F[6][5] = { {1.f, 0.f, 0.f,    0.f,    0.f},
+  {0.f, 1.f, 0.f,    0.f,    0.f},
+  {0.f, 0.f, 0.f,    0.f,    0.f},
+  {0.f, 0.f, dpxdtx, dpxdty, dpxdqp},
+  {0.f, 0.f, dpydtx, dpydty, dpydqp},
+  {0.f, 0.f, dpzdtx, dpzdty, dpzdqp} };
+    
+  double VFT[5][6];
+  for(int i=0; i<5; i++)
+    for(int j=0; j<6; j++)
+    {
+      VFT[i][j] = 0;
+      for(int k=0; k<5; k++)
+      {
+        if (k<=i)
+          VFT[i][j] += track.GetField<float>(cov_field_id_ + k + i*(i+1)/2) * F[j][k];   //parameters->GetCovariance(i,k) * F[j][k];
+        else
+          VFT[i][j] += track.GetField<float>(cov_field_id_ + i + k*(k+1)/2) * F[j][k];   //parameters->GetCovariance(i,k) * F[j][k];
+      }
+    }
+
+    
+  std::vector<float> cov(21, 0);
+  for(int i=0, l=0; i<6; i++)
+    for(int j=0; j<=i; j++, l++)
+    {
+      cov[l] = 0;
+      for(int k=0; k<5; k++)
+      {
+        cov[l] += F[i][k] * VFT[k][j];
+      }
+    }
+  return cov;
+}
\ No newline at end of file
diff --git a/analysis/common/at_kfpf_interface/ATKFParticleFinder.h b/analysis/common/at_kfpf_interface/ATKFParticleFinder.h
new file mode 100644
index 0000000000..9cbe6713a5
--- /dev/null
+++ b/analysis/common/at_kfpf_interface/ATKFParticleFinder.h
@@ -0,0 +1,68 @@
+#ifndef ATKFParticleFinder_HH
+#define ATKFParticleFinder_HH
+
+#include <string>
+#include <utility>
+
+#include "TFile.h"
+#include "TChain.h"
+#include "TTree.h"
+
+#include "AnalysisTree/Detector.hpp"
+#include "AnalysisTree/Configuration.hpp"
+#include "AnalysisTree/EventHeader.hpp"
+
+#include "KFParticleTopoReconstructor.h"
+#include "CutsContainer.h"
+
+class ATKFParticleFinder
+{
+public:
+  
+  void InitInput(const std::string& file_name, const std::string& tree_name);
+  void InitOutput(const std::string& file_name="KFPF_output.root");
+  void Finish();
+  void SetCuts(CutsContainer cuts) {cuts_ = cuts;};
+//   const KFParticleTopoReconstructor* GetTopoReconstructor() const {return topo_reconstructor_;};
+  void SetPIDMode(int pid){pid_mode_ = pid;};
+  void WriteCandidates(const KFParticleTopoReconstructor* TR);
+  void Run(int n_events=-1);
+  
+private:
+  
+  KFParticleTopoReconstructor* CreateTopoReconstructor();
+  
+  std::string in_file_name_;
+  std::string in_tree_name_;
+  TFile* in_file_{nullptr};
+  TChain* in_chain_{nullptr};
+  AnalysisTree::Configuration* config_{nullptr};
+  AnalysisTree::EventHeader* rec_event_header_{nullptr};
+  AnalysisTree::TrackDetector* kf_tracks_{nullptr};
+  
+  TFile* out_file_{nullptr};
+  TTree* out_tree_{nullptr};
+  AnalysisTree::Configuration out_config_;
+  AnalysisTree::Particles* particles_reco_{nullptr};
+    
+  int q_field_id_{-999};
+  int par_field_id_ {-999};
+  int mf_field_id_ {-999};
+  int cov_field_id_{-999};
+  int passcuts_field_id_{-999};
+  int pdg_field_id_{-999};
+  int vtx_chi2_field_id_{-999};
+  int nhits_field_id_{-999};
+  int nhits_mvd_field_id_{-999};
+  
+  int daughter1_id_field_id_{-999};
+  int daughter2_id_field_id_{-999};
+  
+  CutsContainer cuts_;
+//   KFParticleTopoReconstructor* topo_reconstructor_{nullptr};
+  
+  std::vector<float> GetCovMatrixCbm(const AnalysisTree::Track& track) const;
+  
+  int pid_mode_{1};
+};
+#endif //ATKFParticleFinder_HH
\ No newline at end of file
diff --git a/analysis/common/at_kfpf_interface/AnalysisTreeKfpfInterfaceLinkDef.h b/analysis/common/at_kfpf_interface/AnalysisTreeKfpfInterfaceLinkDef.h
new file mode 100644
index 0000000000..6135a06bde
--- /dev/null
+++ b/analysis/common/at_kfpf_interface/AnalysisTreeKfpfInterfaceLinkDef.h
@@ -0,0 +1,10 @@
+#ifdef __CINT__
+
+#pragma link off all globals;
+#pragma link off all classes;
+#pragma link off all functions;
+
+#pragma link C++ class ATKFParticleFinder+;
+#pragma link C++ class CutsContainer+;
+
+#endif
diff --git a/analysis/common/at_kfpf_interface/CMakeLists.txt b/analysis/common/at_kfpf_interface/CMakeLists.txt
new file mode 100644
index 0000000000..bddba6c0de
--- /dev/null
+++ b/analysis/common/at_kfpf_interface/CMakeLists.txt
@@ -0,0 +1,67 @@
+Set(LIBRARY_NAME AnalysisTreeKfpfInterface)
+
+set(SRCS
+        ATKFParticleFinder.cxx
+        CutsContainer.cxx
+    )
+
+Set(INCLUDE_DIRECTORIES
+  ${CMAKE_CURRENT_SOURCE_DIR}
+
+  ${KFParticle_INCLUDE_DIR}
+  ${AnalysisTree_INCLUDE_DIR}
+)
+
+Include_Directories (${INCLUDE_DIRECTORIES})
+
+Set(SYSTEM_INCLUDE_DIRECTORIES
+  ${VC_INCLUDE_DIRS}
+  ${BASE_INCLUDE_DIRECTORIES}
+  ${Boost_INCLUDE_DIR} 
+)
+
+Include_Directories (SYSTEM ${SYSTEM_INCLUDE_DIRECTORIES})
+
+set (LINK_DIRECTORIES
+  ${ROOT_LIBRARY_DIR}
+  ${FAIRROOT_LIBRARY_DIR}
+  ${Boost_LIBRARY_DIRS}
+  ${Vc_LIB_DIR}
+  ${KFParticle_LIB_DIR}
+  ${AnalysisTree_LIBRARY_DIR}
+)
+ 
+link_directories(${LINK_DIRECTORIES})
+
+IF (SSE_FOUND)
+  Message(STATUS "${LIBRARY_NAME} will be compiled with SSE support")
+  ADD_DEFINITIONS(-DHAVE_SSE)
+  SET_SOURCE_FILES_PROPERTIES(${SRCS} PROPERTIES COMPILE_FLAGS "-msse -O3")
+ELSE (SSE_FOUND)
+  MESSAGE(STATUS "${LIBRARY_NAME} will be compiled without SSE support")
+  SET_SOURCE_FILES_PROPERTIES(${SRCS} PROPERTIES COMPILE_FLAGS "-msse -O3")
+ENDIF (SSE_FOUND)
+
+Set(LINKDEF AnalysisTreeKfpfInterfaceLinkDef.h)
+
+If(UNIX AND NOT APPLE)
+  Set(_AnalysisTree_LIB  AnalysisTreeBase.so AnalysisTreeInfra.so)
+  Else()
+  Set(_AnalysisTree_LIB  AnalysisTreeBase.dylib AnalysisTreeInfra.dylib)
+EndIf()
+
+Set(DEPENDENCIES 
+	${_AnalysisTree_LIB} 
+	KFParticle
+	Vc.a)
+Set(DEFINITIONS -DDO_TPCCATRACKER_EFF_PERFORMANCE -DNonhomogeneousField -DCBM -DUSE_TIMERS)
+
+ADD_DEFINITIONS(${DEFINITIONS})
+
+GENERATE_LIBRARY()
+
+# Install(FILES ../../../macro/analysis/common/analysis_tree_converter/run_treemaker.C
+#         DESTINATION share/cbmroot/macro/analysis_tree
+#        )
+
+Add_Dependencies(AnalysisTreeKfpfInterface ANALYSISTREE KFPARTICLE)
\ No newline at end of file
diff --git a/analysis/common/at_kfpf_interface/CutsContainer.cxx b/analysis/common/at_kfpf_interface/CutsContainer.cxx
new file mode 100644
index 0000000000..5a2499dc0d
--- /dev/null
+++ b/analysis/common/at_kfpf_interface/CutsContainer.cxx
@@ -0,0 +1 @@
+#include "CutsContainer.h"
diff --git a/analysis/common/at_kfpf_interface/CutsContainer.h b/analysis/common/at_kfpf_interface/CutsContainer.h
new file mode 100644
index 0000000000..33f5d7fd19
--- /dev/null
+++ b/analysis/common/at_kfpf_interface/CutsContainer.h
@@ -0,0 +1,45 @@
+//
+// @class CutsContainer
+// @brief Container with values of cuts.
+// @authors Oleksii Lubynets, Viktor Klochkov, Ilya Selyuzhenkov
+//
+// The meaning of quantities to be cut is described in the OutputContainer.h
+//
+
+
+#ifndef CutsContainer_H
+#define CutsContainer_H
+
+class CutsContainer
+{
+  
+ public:
+   
+  CutsContainer() = default;
+  virtual ~CutsContainer() = default;  
+  
+  //  lambda candidate parameters setters
+  void SetCutChi2Prim(float value){cut_chi2_prim_ = value;};
+  void SetCutDistance(float value){cut_distance_ = value;};
+  void SetCutChi2Geo(float value){cut_chi2_geo_ = value;};
+  void SetCutLDown(float value){cut_l_down_ = value;};
+  void SetCutLdL(float value){cut_ldl_ = value;};
+    
+  //  lambda candidate parameters getters
+  float GetCutChi2Prim() const {return cut_chi2_prim_;};
+  float GetCutDistance() const {return cut_distance_;};
+  float GetCutChi2Geo() const {return cut_chi2_geo_;};
+  float GetCutLDown() const {return cut_l_down_;};
+  float GetCutLdL() const {return cut_ldl_;};
+    
+ protected:
+   
+  // Cuts with their default values
+  float cut_chi2_prim_{18.4207};
+  float cut_distance_{1.};
+  float cut_chi2_geo_{3.};
+  float cut_l_down_{-5.};;
+  float cut_ldl_{5.};   
+    
+};
+#endif//CutsContainer_H
\ No newline at end of file
-- 
GitLab