diff --git a/.github/workflows/clang.yml b/.github/workflows/clang.yml
index 7d38565..183cc70 100644
--- a/.github/workflows/clang.yml
+++ b/.github/workflows/clang.yml
@@ -11,5 +11,5 @@ jobs:
- uses: actions/checkout@v2
- uses: RafikFarhad/clang-format-github-action@v2.0.0
with:
- sources: "src/*.cpp src/*.h pid_new/*/*.cpp pid_new/*/*.h macro/*.C tasks/*.cpp input/*.C at_interface/*pp"
+ sources: "src_tof/*.cpp src_tof/*.h src_trd/*.cpp src_trd/*.h pid_new/*/*.cpp pid_new/*/*.h macro/*.C tasks/*.cpp input/*.C at_interface/*pp interface/*pp"
style: file
diff --git a/.gitignore b/.gitignore
index 53f726d..44ccbdd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,5 @@
Doxygen/*
*build*/*
*install*/*
+.DS_Store
+*/.DS_Store
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 588e82b..6c9fff1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -47,13 +47,15 @@ set(CMAKE_CXX_FLAGS_DEBUG "-O0 -ggdb -g -DDEBUG -D__DEBUG -Wall -Wextra")
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -ftree-vectorize -ffast-math -DNODEBUG")
message(STATUS "Using CXX flags for ${CMAKE_BUILD_TYPE}: ${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}}")
-add_subdirectory(src)
+add_subdirectory(src_tof)
+add_subdirectory(src_trd)
+add_subdirectory(interface)
if(${PID_BUNDLED_AT})
add_subdirectory(at_interface)
endif()
add_subdirectory(tasks)
- # Packaging routine
+# Packaging routine
# For complete explanation
# @see https://cmake.org/cmake/help/git-master/manual/cmake-packages.7.html#creating-packages
include(GenerateExportHeader)
diff --git a/README.md b/README.md
index bbd7866..2c4a5bf 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,15 @@
# Particle Identification Framework
## General information
-The procedure of particle identification is described in Sec. 4.4 of this [thesis](https://publikationen.ub.uni-frankfurt.de/opus4/frontdoor/deliver/index/docId/51779/file/main.pdf).
+The Pid framework identifies hadrons based on the Tof-*m*2 and/or the Trd-*dE/dx*. It assigns a probability to be a certain particle species to
+every track depending on its *m*2 and its momentum and/or on its Trd-dEdx and its momentum.
+
+The procedure of particle identification with the Tof-*m*2 is described in Sec. 4.4 of this [thesis](https://publikationen.ub.uni-frankfurt.de/opus4/frontdoor/deliver/index/docId/51779/file/main.pdf).
It consists of two steps - determination of particle type hypothesis (fitting) and application of hypothesis to a set of particles (filling).
-Running of these steps is described below, in the section "Examples".
+
+The procedure of particle identification with the the Trd-*dE/dx* is described in [presentation](https://next.hessenbox.de/index.php/s/DJrpKEaH7zZzNDx). It constists of three steps - creating of MC-input, calculating MC-probabilities and assigning probabilities and pid hypothesis to a set of particles (filling). In addition, the separtion of electrons and pions with the RICH detector is applied.
+
+Running of these steps is described below, in section "First Run".
## Installation
ROOT6 is needed for installation.
@@ -37,18 +43,89 @@ Now perform following commands for the installation:
*path-to-root-installation* and *path-to-analysistree-installation* must be replaced with your actual location of Root and AnalysisTree install directories respectively.
-## Examples
-Before running the Pid framework you need to set up the environment variables:
+## First run
+
+Before running the Pid framework the environment variables need to be set:
source path-to-pid-installation/bin/PidConfig.sh
-### Fitting
-Let us consider the fitting procedure with an example of 5M Au+Au collisions generated with DCM-QGSM-SMM at beam momentum 12*A* GeV/*c*.
-For this you need to prepare an input file with *m*2-*p* histograms, like input/m2_pq_vtx.apr20.dcmqgsm.12agev.root.
-In the folder "reco_info" there is a histogram with all reconstructed tracks matched to TOF hits.
-In folders "reco_vs_sim_info_from_tof", "reco_vs_sim_info_via_vtx" there are histograms for separate particles species (MC-true) - determined from "TOF hit - simulated particles" and "TOF hit - reconstructed track - simulated particles" matchings respectively.\
+The following steps need to be performed (for more details see below):
+
+- Preparation: creating mc-histograms
+
+ -- for Tof pid: preparation outside of the Pid-framework
+
+ -- for Trd pid run:
+
+ ./create_mcinput_trd filelist.sh outfilename (for one analysistree.root)
+
+ and merge output-files for runs into one file:
+
+ hadd mcfilename.root *.mcfilename.root
+
+- Step 1: producing probabilities that are required to identify the tracks.
+
+ -- for Tof pid:
+
+ ./run_pid_dcm12
+
+ -- for Trd pid:
+
+ ./calculate_mcprob_trd mcfilename
+
+- Step 2: assigning probabilities for particle species and a pid-hypothesis to reconstructed tracks from an analysistree and writing them into a new analysistree.
+
+ -- for Tof and Trd pid simoultanously:
+
+ ./fill_pid 0 filelist.txt outputfilename pid_file_tof pid_file_trd truncation_mode probability_mode min_hits (purity)
+
+ -- for Tof pid only:
+
+ ./fill_pid 1 filelist.txt outputfilename pid_file_tof
+
+ -- for Trd pid only:
+
+ ./fill_pid 2 filelist.txt outputfilename pid_file_trd truncation_mode probability_mode min_hits (purity)
+
+The preparation and the first step only need to be performed once.
+
+In the following the above steps are described in more detail.
+
+### Preparation: Creating MC-Input
+
+#### TOF
+The MC-input file for a specific system and energy needs to be created by the user before running the Pid framework. The input file needs to contain *m*2-*p* histograms in the format like input/m2_pq_vtx.apr20.dcmqgsm.12agev.root. In the folder "reco_info" there is a histogram with all reconstructed tracks matched to TOF hits. In folders "reco_vs_sim_info_from_tof", "reco_vs_sim_info_via_vtx" there are histograms for separate particles species (MC-true) - determined from "TOF hit - simulated particles" and "TOF hit - reconstructed track - simulated particles" matchings respectively.\
+
Another file which you need contains graphic cuts of certain particles species - it allows to ignore during fitting the particles entries in a non-specific parts of the *m*2-*p* histogram, which mainly originate from mismatching between track and TOF hit.
This file is input/cuts.root.\
+
+#### TRD
+The MC-input file for a specific system and energy needs to be created by running tasks/create_mcinput_trd.cpp. The MC-input file contains *dE/dx*-*p* histograms for all reconstructed tracks and hits as well as for reconstructed tracks and hits separated by particle species according to the MC-matching information. Separate histograms are createdf for:
+
+- tracks and hits
+- number of Trd-hits (1-4)
+- truncation (1-4) (including average)
+- all tracks/hits and separated by particles species (MC-matching information)
+
+An example file for 5 million minbias Au+Au events at *p*beam = 12 AGeV reconstructed with cbmroot jul25 can be found in input/dEdx_p.jul25.phqmd.auau.12agev.root.
+
+To run the executable type:
+
+ ./create_mcinput_trd filelist.sh outfilename
+
+The input for the creation of the MC-histrograms must be an analysistree including mc-information in the format jobId.analysistree.root.
+
+The path and name of the analysistree is read in via filelist.txt. Only one analysistree is read in one run. A separate filelist.sh is required for every run.
+
+The ouput filename will be in the format jobId.mcfilename.root
+
+For reliable MC-histograms a set of run needs to be performed and the resulting files for every run need to get merged into one file with:
+
+ hadd mcfilename.root *.mcfilename.root
+
+### Calculating probabilities
+
+#### TOF: Fitting
The task which runs the fitting process is tasks/run_pid_dcm12.cpp (look for comments in this file for understanding the configuration example), and it produces a C++ executable install/bin/run_pid_dcm12.
To run this executable just type:
@@ -66,32 +143,130 @@ Graphs pionpos_0, pionpos_1 and pionpos_2, kaonpos_0, ..., bgpos_1, bgpos_2 repr
Finally, the chi2 graph shows the chi2 dependence on momentum when *m*2 fits were performed.\
Running the macro/drawFits.C macro on the allpos.root (allneg.root) file allows to build all these distributions on the same canvas.
-Another file produced during the fitting procedure is pid_getter.root.
-There is a Pid::Getter which contains results of fitting.
+Another file produced during the fitting procedure is pidtof_getter.root.
+There is a Pid::GetterTof which contains results of fitting.
In order to determine bayesian probabilities (purities) of particle species in a certain *m*2-*p* point (*p*=3 GeV/*c*, *m*2=1 (GeV/*c*2)2), one runs
- pid_getter->GetBayesianProbability(3, 1)
+ pid_getter_tof->GetBayesianProbability(3, 1)
and obtains result in the following form:
(std::map) { -321 => 0.0000000, -211 => 0.0000000, -1 => 0.0000000, 1 => 0.0011928893, 211 => 8.0296922e-81, 321 => 7.1999527e-46, 2212 => 0.99880711 }
// Here 1 and -1 stand for background in the right and left side of the histogram respectively.
-Running the macro/RunGetter.C on the pid_getter.root file produces a set of plots showing purity distribution of different particles species and background.
+Running the macro/RunGetterTof.C on the pid_getter_tof.root file produces a set of plots showing purity distribution of different particles species and background.
+
+#### TRD
+
+The task which runs the calculation of mc-probabilities is tasks/calculate_prob_trd.cpp. To run this executable just type:
+
+ ./calculate_mcprob_trd mcfilename
+
+Mc-probabilities for all particle species are calculated for every *dE/dx*-*p* for all histograms with two methods: Total probability and likelyhood method (see PID_with_Trd_dEdx.pdf for more details). The probabilities are saved in pid_getter_trd.root. The getter is required for the filling procedure. The probabilites for all histograms in mcfilename.root are also saved in *mcfilename*_probabilities.root.
+
+**** Additional information on how to work the pid_getter_trd.root independently of the filling procedure: ****
+
+The Pid::GetterTrd contains the results of the probability calculations. For a reconstructed track with certain *dE/dx* for each Trd-hit and *p* value, probabilities can get obtained for the total proability method with:
+
+ pid_getter_trd->GetTrdProbabilities(trdtrack);
+
+and for the likelihood method with:
+
+ pid_getter_trd->GetTrdProbabilitiesMulti(trdtrack);
+
+The trdtrack is an object of the folllowing form:
+
+ TrdContainer trdtrack(mom, pT, charge, nhits_trd, dEdx_hits);
+
+Options for the application of probabilities and pid hypothesis (see below for a more detailed explanation of options) can be set with:
+
+ pid_getter_trd->SetProbabilityMode(mode); // default is total probability method
+ pid_getter_trd->SetTruncationMode(mode); // default is average
+ pid_getter_trd->SetMinHits(minhits); // default is 1 hit
+ pid_getter_trd->SetPurity(minpurity); // default is 0.0
+
+For example, for a postive track with an average *dE/dx* = 25 keV/cm and *p* = 5 GeV/*c*, the obtained result with the total probability method is in the form:
+
+ (std::map) {(2212, 0.5803), (211, 0.2162), (321, 0.0366), (1000010020, 0.0281), (1000010030, 0.0011), (1000020030, 0.0087), (1000020040 = 0.0009, (-11; 0.1277, (-13, 0.0004), (1, 0.0001) }
+ // Here 1 stands for background
+
+Alternatively, probabilites can get applied for the average mode and for the total probability method direcly with:
+
+ getter->GetTrdProbabilitiesTotalAverage(mom, dEdx, charge, nhits_trd);
+ // with dEdx = average dE/dx of a track
+
+and for the likelihood method with:
+
+ getter->GetTrdProbabilitiesLikelihoodAverage(mom, dEdx_hits, charge);
+ // with dEdx_hits = dE/dx vector for hits of a track
+
+The macro/RunGetterTrd.C shows some examples on how to access the pid_getter_trd.root to assign probabilities to a track. I also produces a set of plots showing probability distributions of different particles species and background.
### Filling
-Once fitting is preformed and the pid_getter.root file is produced, filling the root-file containing reconstructed tracks can be done - each track will be assigned with probabilities of belonging to different particle species and (optionally) its particle type hypothesis.
-This is done in the at_interface/PidFiller.*pp, which are managed by the task tasks/fill_pid.cpp (look for comments in this file for understanding the configuration example).
-It produces an executable fill_pid which can be run:
+Once fitting / probability calculatoin is preformed and the pid_getter_tof.root and/or pid_getter_trd.root files are produced, filling the root-file containing reconstructed tracks can be done - each track will be assigned with probabilities of belonging to different particle species and (optionally) its particle type hypothesis according to the Tof and/or Trd measurement.
+
+This is done in the at_interface/PidFiller.*pp, which are managed by the task tasks/fill_pid.cpp. It produces an executable fill_pid which can be run for either Tof and Trd pid simoultanously or for both separately.
+
+The first argument manages the selection of the detector: =0: Tof and Trd, =1: Tof, =2: Trd.
+
+The following arguments depend on the selection of the detector.
+
+To run Tof and Trd pid simoultanously type:
+
+ ./fill_pid 0 filelist.txt outputfilename pid_file_tof pid_file_trd truncation_mode probability_mode min_hits (purity)
+
+To run Tof pid only type:
- ./fill_pid filelist.list pid_getter.root
+ ./fill_pid 1 filelist.txt outputfilename pid_file_tof
+
+To run Trd pid only type
+
+ ./fill_pid 2 filelist.txt outputfilename pid_file_trd truncation_mode probability_mode min_hits (purity)
+
+- filelist.list is a text file containing names of the AnalysisTree root-files to be worked on (an example of AnalysisTree file can be downloaded [here](https://sf.gsi.de/f/3ba5a9e3ff5248edba2c/?dl=1)).
+
+- pid_file_tof / pid_file_tof are the getter-files that were produced in the step before
+
+- for the Trd pid the following options need to get selected:
+
+ -- truncation_mode: modes for calculation of energy loss for up to 4
+layers:
+
+ =0: average over all hits (default)
+
+ =1-4: Select hits with lowest dEdx: =1: 1 hit, =2: 2 hits, =3: 3 hits, =4: 4 hits
+
+ -- probability_mode:
+
+ =0: total probability - probability based on particle multiplicites (default)
+
+ =1: likelihood - probability based on dEdx-distribution of particle
+species
+
+ -- min_hits: minimum number of required hits per track
+
+ optional:
+
+ -- purity: minimum purity for the pid-hypothesis (most probable particle species) (default purity is 0)
-where filelist.list is a text file containing names of the AnalysisTree root-files to be worked on (en example of AnalysisTree file can be downloaded [here](https://sf.gsi.de/f/3ba5a9e3ff5248edba2c/?dl=1)).
After running this exacutable a pid.analysistree.root file is produced.
-It is based on the input file with following changes:
-branches RichRings and TrdTracks are missing, and branch VtxTracks is replaced with RecParticles branch.
-The RecParticles differs from VtxTracks in, firstly, the type of branch (Particles instead of Track), and secondly - in few additional fields: prob_K, prob_d, prob_p, prob_pi, prob_bg - a probability of the particle to be a kaon, deuteron, proton, pion or background (undefined type).
-Also there is a field 'pid' which shows the most probable particle type hypothesis.
+It is based on the input file. The branch VtxTracks is replaced with RecParticles branch.
+The RecParticles differs from VtxTracks in, firstly, the type of branch (Particles instead of Track), and secondly - in few additional fields:
+- for Tof:
+
+ prob_K, prob_d, prob_p, prob_pi, prob_bg - probability of the particle to be a kaon, deuteron, proton, pion or background (undefined type).
+
+ pid - Tof pid hypothesis which is the most probable particle type
+
+- for Trd:
+
+ prob_trd_p, prob_trd_pi, prob_trd_K, prob_trd_d, prob_trd_t, prob_trd_He3, prob_trd_He4, prob_trd_e, prob_trd_mu, prob_trd_bg - probability of the particle to be a proton, pion, kaon, deuteron, triton, He3, He4, electron, myon or background (undefined type).
+
+ pid_trd - Trd pid hypothesis which is the most probable particle type
+
+ In addition, when running with Trd, the RICH electron hyposthesis will be added:
+
+ electron_rich - RICH electron hypothesis: true = electron, false = no electron
### Doxygen documentation
doxygen docs/Doxyfile
diff --git a/at_interface/CMakeLists.txt b/at_interface/CMakeLists.txt
index 032ecdc..8918c9c 100644
--- a/at_interface/CMakeLists.txt
+++ b/at_interface/CMakeLists.txt
@@ -2,16 +2,17 @@ include(AnalysisTree)
set(SOURCES
PidFiller.cpp
+ PidTrdMcInput.cpp
)
string(REPLACE ".cpp" ".hpp" HEADERS "${SOURCES}")
-include_directories(${PROJECT_INCLUDE_DIRECTORIES} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/src)
+include_directories(${PROJECT_INCLUDE_DIRECTORIES} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/src_tof ${CMAKE_SOURCE_DIR}/src_trd)
add_library(PidAT SHARED ${SOURCES} G__PidAT.cxx)
message("${PROJECT_INCLUDE_DIRECTORIES}")
ROOT_GENERATE_DICTIONARY(G__PidAT ${HEADERS} LINKDEF PidATLinkDef.h)
-target_link_libraries(PidAT ${ROOT_LIBRARIES} AnalysisTreeBase AnalysisTreeInfra Pid)
+target_link_libraries(PidAT ${ROOT_LIBRARIES} AnalysisTreeBase AnalysisTreeInfra Pid PidTrd)
install(TARGETS PidAT EXPORT AnalysisTreeFillerTargets
LIBRARY DESTINATION lib
diff --git a/at_interface/PidFiller.cpp b/at_interface/PidFiller.cpp
index 9233f71..6a583ed 100644
--- a/at_interface/PidFiller.cpp
+++ b/at_interface/PidFiller.cpp
@@ -1,17 +1,44 @@
#include "PidFiller.hpp"
+using std::string;
using namespace AnalysisTree;
-PidFiller::PidFiller(const std::string& file, const std::string& getter) {
+PidFiller::PidFiller(const std::string& pid_file_name_tof, const std::string& pid_file_name_trd, const std::string& getter_name_tof, const std::string& getter_name_trd, int pid_mode) {
std::cout << "PidFiller::PidFiller" << std::endl;
- auto pid_file = std::unique_ptr(TFile::Open(file.c_str(), "read"));
- if ((!pid_file) || (pid_file->IsZombie())) {
- throw std::runtime_error("No file or file is zombie: " + file);
+ std::unique_ptr pid_file_tof;
+ std::unique_ptr pid_file_trd;
+
+ if (pid_mode == 0) {
+ is_run_pid_tof_ = true;
+ is_run_pid_trd_ = true;
}
- getter_ = pid_file->Get(getter.c_str());
- if (getter_ == nullptr) {
- throw std::runtime_error("PID Getter is nullptr: " + getter);
+
+ if (pid_mode == 1)
+ is_run_pid_tof_ = true;
+
+ if (pid_mode == 2)
+ is_run_pid_trd_ = true;
+ if (is_run_pid_tof_ == true) {
+ pid_file_tof = std::unique_ptr(TFile::Open(pid_file_name_tof.c_str(), "read"));
+ if ((!pid_file_tof) || (pid_file_tof->IsZombie())) {
+ throw std::runtime_error("No file or file is zombie: " + pid_file_name_tof);
+ }
+ getter_tof_ = pid_file_tof->Get(getter_name_tof.c_str());
+ if (getter_tof_ == nullptr) {
+ throw std::runtime_error("PID Tof Getter is nullptr: " + getter_name_tof);
+ }
+ }
+
+ if (is_run_pid_trd_ == true) {
+ pid_file_trd = std::unique_ptr(TFile::Open(pid_file_name_trd.c_str(), "read"));
+ if ((!pid_file_trd) || (pid_file_trd->IsZombie())) {
+ throw std::runtime_error("No file or file is zombie: " + pid_file_name_trd);
+ }
+ getter_trd_ = pid_file_trd->Get(getter_name_trd.c_str());
+ if (getter_trd_ == nullptr) {
+ throw std::runtime_error("PID Trd Getter is nullptr: " + getter_name_trd);
+ }
}
}
@@ -24,23 +51,128 @@ int PidFiller::signum(int x) const {
return -1;
}
+float PidFiller::GetMomentumTrd(const AnalysisTree::BranchChannel& trd_track) {
+ float momentum = 0.0;
+ if (TMath::Abs(trd_track.Value(trd_tracks_.GetField("p")) > 0))
+ momentum = trd_track.Value(trd_tracks_.GetField("p"));
+ else if (TMath::Abs(trd_track.Value(trd_tracks_.GetField("p_out")) > 0))
+ momentum = trd_track.Value(trd_tracks_.GetField("p_out"));
+ else
+ Warning("Exec", "Could not assign any momentum to the track, use p=0.");
+
+ return momentum;
+}
+
+float PidFiller::GetPtTrd(const AnalysisTree::BranchChannel& trd_track) {
+ float pT = 0;
+ if (TMath::Abs(trd_track.Value(trd_tracks_.GetField("pT")) > 0))
+ pT = trd_track.Value(trd_tracks_.GetField("pT"));
+ else if (TMath::Abs(trd_track.Value(trd_tracks_.GetField("pT_out")) > 0))
+ pT = trd_track.Value(trd_tracks_.GetField("pT_out"));
+ else
+ Warning("Exec", "Could not assign any pT to the track, use pT=0.");
+ return pT;
+}
+
+int PidFiller::GetCharge(const AnalysisTree::BranchChannel& rec_track) {
+ return rec_track.Value(rec_tracks_.GetField("q"));
+}
+
+void PidFiller::GetEnergyLossHitsTrd(const AnalysisTree::BranchChannel& trd_track, int& nhits_trd, std::array& dEdx) {
+
+ nhits_trd = 0;
+
+ for (int ihit = 0; ihit < NumberOfTrdLayers; ihit++) {
+ if (trd_track.Value(trd_dEdx_field_.at(ihit)) > 0) {
+ dEdx.at(ihit) = trd_track.Value(trd_dEdx_field_.at(ihit));
+ nhits_trd++;
+ } else
+ dEdx.at(ihit) = 0;
+ }
+}
+
+bool PidFiller::IsRichElectron(const AnalysisTree::BranchChannel& rec_track) {
+ bool isElectron = false;
+ int i_rich = rec_to_rich_->GetMatch(rec_track.GetId());
+ if (i_rich > 0) {
+ const auto& rich_ring = rich_rings_[i_rich];
+ float Aaxis = rich_ring.Value(rich_rings_.GetField("axis_a"));
+ float Baxis = rich_ring.Value(rich_rings_.GetField("axis_b"));
+ Double_t dist = 0;// richRing->GetDistance();
+
+ Float_t mom = GetMomentumTrd(rec_track);
+ Double_t MeanA = 4.95;
+ Double_t MeanB = 4.54;
+ Double_t RmsA = 0.30;
+ Double_t RmsB = 0.22;
+ Double_t RmsCoeff = 3.5;
+ Double_t DistCut = 1.;
+
+ if (mom < 5.) {
+ if (fabs(Aaxis - MeanA) < RmsCoeff * RmsA && fabs(Baxis - MeanB) < RmsCoeff * RmsB && dist < DistCut)
+ isElectron = true;
+ } else {
+ ///2 sigma
+ Double_t polAaxis = 5.64791 - 4.24077 / (mom - 3.65494);
+ Double_t polBaxis = 5.41106 - 4.49902 / (mom - 3.52450);
+ if (Aaxis < (MeanA + RmsCoeff * RmsA) && Aaxis > polAaxis && Baxis < (MeanB + RmsCoeff * RmsB) && Baxis > polBaxis && dist < DistCut)
+ isElectron = true;
+ }
+ }
+ return isElectron;
+}
+
void PidFiller::Init() {
+ // Settings for Trd Pid
+ if (is_run_pid_trd_ == true) {
+ getter_trd_->SetMinHits(nhits_min_);
+ getter_trd_->SetTruncationMode(trunc_mode_);
+ getter_trd_->SetProbabiltyMode(prob_mode_);
+ }
+
auto man = TaskManager::GetInstance();
auto chain = man->GetChain();
- rec_tracks_ = chain->GetBranch(rec_tracks_name_);
- tof_hits_ = chain->GetBranch(tof_hits_name_);
- pid_match_ = chain->GetMatchPointers().find({rec_tracks_name_ + "2" + tof_hits_name_})->second;
+ rec_tracks_ = chain->GetBranch(rec_tracks_name_);
in_branches_.emplace(rec_tracks_name_);
- in_branches_.emplace(tof_hits_name_);
-
auto conf = rec_tracks_.GetConfig().Clone(out_branch_name_, AnalysisTree::DetType::kParticle);
- std::vector names{};
- for (const auto& pid : pid_codes_) {
- names.push_back("prob_" + pid.second);
+ // Set and configure branches for Tof Pid
+ if (is_run_pid_tof_ == true) {
+ tof_hits_ = chain->GetBranch(tof_hits_name_);
+ rec_to_tof_ = chain->GetMatchPointers().find({rec_tracks_name_ + "2" + tof_hits_name_})->second;
+
+ in_branches_.emplace(tof_hits_name_);
+
+ std::vector names{};
+ for (const auto& pid : pid_codes_tof_) {
+ names.push_back("prob_" + pid.second);
+ }
+ conf.AddFields(names, "probability to be proton, pion, kaon etc");
+ }
+
+ // Set and configure branches for Trd Pid
+ if (is_run_pid_trd_ == true) {
+
+ trd_tracks_ = chain->GetBranchObject(trd_tracks_name_);
+ rich_rings_ = chain->GetBranchObject(rich_rings_name_);
+ rec_to_trd_ = chain->GetMatching(rec_tracks_name_, trd_tracks_name_);
+ rec_to_rich_ = chain->GetMatching(rec_tracks_name_, rich_rings_name_);
+
+ in_branches_.emplace(trd_tracks_name_);
+ in_branches_.emplace(rich_rings_name_);
+
+ conf.AddField("electron_rich", "rich electron hypothesis");
+ conf.AddField("pid_trd", "trd pid hypothesis");
+ conf.AddField("nhits_trd_eloss", "number of trd hits dEdx > 0");
+
+ std::vector names{};
+ for (const auto& pid : pid_codes_trd_) {
+ string name = Form("prob_trd_%s", pid.second.Data());
+ names.push_back(Form("prob_trd_%s", pid.second.Data()));
+ }
+ conf.AddFields(names, "trd probability to be proton, pion, kaon etc");
}
- conf.AddFields(names, "probability to be proton, pion, kaon etc");
ana_tracks_ = Branch(conf);
ana_tracks_.SetMutable();
@@ -50,23 +182,49 @@ void PidFiller::Init() {
man->AddBranch(&ana_tracks_);
- int i{0};
- auto match_br = {"SimParticles", "TofHits"};
+ // Add matching for ouput
+ int imatch{0};
+ std::vector match_br;
+ match_br.push_back("SimParticles");
+
+ if (is_run_pid_tof_ == true)
+ match_br.push_back("TofHits");
+
+ if (is_run_pid_trd_ == true) {
+ match_br.push_back("TrdTracks");
+ match_br.push_back("RichRings");
+ }
+
out_matches_.assign(match_br.size(), nullptr);
for (const auto& br : match_br) {
in_matches_.emplace_back(chain->GetMatchPointers().find({rec_tracks_name_ + "2" + br})->second);
- man->AddMatching(out_branch_name_, br, out_matches_.at(i));
- i++;
+ man->AddMatching(out_branch_name_, br, out_matches_.at(imatch));
+ imatch++;
+ }
+
+ // Set input variables for Tof Pid
+ if (is_run_pid_tof_ == true) {
+ qp_tof_field_ = tof_hits_.GetField("qp_tof");
+ q_field_ = rec_tracks_.GetField("q");
+ mass2_field_ = tof_hits_.GetField("mass2");
+ pid_tof_field_ = ana_tracks_.GetField("pid");
+ for (const auto& pid : pid_codes_tof_) {
+ prob_tof_field_.push_back(ana_tracks_.GetField("prob_" + pid.second));
+ }
}
- qp_tof_field_ = tof_hits_.GetField("qp_tof");
- q_field_ = rec_tracks_.GetField("q");
- mass2_field_ = tof_hits_.GetField("mass2");
- pid_field_ = ana_tracks_.GetField("pid");
+ // Set input variables for Trd Pid
+ if (is_run_pid_trd_ == true) {
+ nhits_trd_eloss_field_ = ana_tracks_.GetField("nhits_trd_eloss");
+ pid_trd_field_ = ana_tracks_.GetField("pid_trd");
+ el_rich_field_ = ana_tracks_.GetField("electron_rich");
- for (const auto& pid : pid_codes_) {
- prob_field_.push_back(ana_tracks_.GetField("prob_" + pid.second));
+ for (const auto& pid : pid_codes_trd_) {
+ prob_trd_field_.push_back(ana_tracks_.GetField(Form("prob_trd_%s", pid.second.Data())));
+ }
+ for (int i = 0; i < NumberOfTrdLayers; i++)
+ trd_dEdx_field_.push_back(trd_tracks_.GetField(("energy_loss_" + std::to_string(i)).c_str()));
}
}
@@ -77,32 +235,87 @@ void PidFiller::Exec() {
const auto& track = rec_tracks_[i];
auto particle = ana_tracks_.NewChannel();
particle.CopyContent(track);
- auto q = track[q_field_];
- auto hit_id = pid_match_->GetMatch(i);
- if (hit_id >= 0) {
- const auto& tof_hit = tof_hits_[hit_id];
- auto pq = tof_hit[qp_tof_field_];
- auto m2 = tof_hit[mass2_field_];
+ // Fill in Tof pid
+ if (is_run_pid_tof_ == true) {
+ auto q = track[q_field_];
- auto pid = getter_->GetPid(pq, m2, 0.5);
- if (pid == 1 && q < 0) {
- pid = -1;
- }
+ auto hit_id = rec_to_tof_->GetMatch(i);
+ if (hit_id >= 0) {
+ const auto& tof_hit = tof_hits_[hit_id];
+ auto pq = tof_hit[qp_tof_field_];
+ auto m2 = tof_hit[mass2_field_];
+
+ auto pid = getter_tof_->GetPid(pq, m2, 0.5);
+ if (pid == 1 && q < 0) {
+ pid = -1;
+ }
- particle.SetValue(pid_field_, pid);
- auto prob = getter_->GetBayesianProbability(pq, m2);
+ particle.SetValue(pid_tof_field_, pid);
+ auto prob = getter_tof_->GetBayesianProbability(pq, m2);
- int specie{0};
- for (const auto& pdg : pid_codes_) {
- particle.SetValue(prob_field_.at(specie++), prob[pdg.first * signum(q)]);// Think what to do in case of electrons and muons
+ int specie{0};
+ for (const auto& pdg : pid_codes_tof_) {
+ particle.SetValue(prob_tof_field_.at(specie++), prob[pdg.first * signum(q)]);// Think what to do in case of electrons and muons
+ }
+ } else {
+ int specie{0};
+ for (const auto& pdg : pid_codes_tof_) {
+ particle.SetValue(prob_tof_field_.at(specie++), -1.f);
+ }
+ particle.SetValue(pid_tof_field_, 2 * signum(q));
}
- } else {
- int specie{0};
- for (const auto& pdg : pid_codes_) {
- particle.SetValue(prob_field_.at(specie++), -1.f);
+ }
+
+ // Fill in Trd pid
+ if (is_run_pid_trd_ == true) {
+
+ int itrd = rec_to_trd_->GetMatch(i);
+ int nhits_trd = 0;
+
+ if (itrd > -1) {
+ const auto& trd_track = trd_tracks_[itrd];
+ float mom = GetMomentumTrd(trd_track);
+ float pT = GetPtTrd(trd_track);
+ int charge = GetCharge(track);
+
+ std::array dEdx_hits = {0.0, 0.0, 0.0, 0.0};
+ GetEnergyLossHitsTrd(trd_track, nhits_trd, dEdx_hits);
+
+ TrdContainer trdtrack(mom, pT, charge, nhits_trd, dEdx_hits);
+ trdtrack.ScaleEnergyLossLength();
+
+ int pidtrd_hypo;
+ std::map prob_trd;
+ if (nhits_trd >= nhits_min_) {
+ if (prob_mode_ == 0)
+ prob_trd = getter_trd_->GetTrdProbabilities(trdtrack);
+ if (prob_mode_ == 1)
+ prob_trd = getter_trd_->GetTrdProbabilitiesMulti(trdtrack);
+
+ int specie{0};
+ for (const auto& pdg : pid_codes_trd_)
+ particle.SetValue(prob_trd_field_.at(specie++), prob_trd[pdg.first]);
+
+ pidtrd_hypo = getter_trd_->GetTrdPid(prob_trd, purity_, charge);
+ particle.SetValue(pid_trd_field_, pidtrd_hypo);
+ } else {
+ particle.SetValue(pid_trd_field_, -2);
+ int specie{0};
+ for (const auto& pdg : pid_codes_trd_)
+ particle.SetValue(prob_trd_field_.at(specie++), -1.f);
+ }
+ } else {
+ particle.SetValue(pid_trd_field_, -2);
+ int specie{0};
+ for (const auto& pdg : pid_codes_trd_)
+ particle.SetValue(prob_trd_field_.at(specie++), -1.f);
}
- particle.SetValue(pid_field_, 2 * signum(q));
+
+ particle.SetValue(nhits_trd_eloss_field_, nhits_trd);
+
+ bool isElectron = IsRichElectron(track);
+ particle.SetValue(el_rich_field_, isElectron);
}
}
int i{0};
diff --git a/at_interface/PidFiller.hpp b/at_interface/PidFiller.hpp
index d766a36..7960829 100644
--- a/at_interface/PidFiller.hpp
+++ b/at_interface/PidFiller.hpp
@@ -1,17 +1,25 @@
-#ifndef PID_AT_INTERFACE_PIDFILLER_HPP_
-#define PID_AT_INTERFACE_PIDFILLER_HPP_
+#ifndef PID_INTERFACE_PIDFILLER_HPP_
+#define PID_INTERFACE_PIDFILLER_HPP_
-#include "Constants.h"
-#include "Getter.h"
+#include "ConstantsTof.h"
+#include "ConstantsTrd.h"
+#include "ContainerTrd.h"
+#include "GetterTof.h"
+#include "GetterTrd.h"
#include "AnalysisTree/Task.hpp"
#include "AnalysisTree/TaskManager.hpp"
+#include "TH2F.h"
+
class PidFiller : public AnalysisTree::Task {
public:
- PidFiller(const std::string& file, const std::string& getter);
- ~PidFiller() override { delete getter_; }
+ PidFiller(const std::string& pid_file_name_tof, const std::string& pid_file_name_trd, const std::string& getter_name_tof, const std::string& getter_name_trd, int pid_mode);
+ ~PidFiller() override {
+ delete getter_tof_;
+ delete getter_trd_;
+ }
void Init() override;
void Exec() override;
@@ -20,34 +28,99 @@ class PidFiller : public AnalysisTree::Task {
// man->RemoveBranch(rec_tracks_name_);
}
+ void SetRecTracksName(const std::string& name) { rec_tracks_name_ = name; }
+ void SetTofHitsName(const std::string& name) { tof_hits_name_ = name; }
+ void SetTrdTracksName(const std::string& name) { trd_tracks_name_ = name; };
+ void SetRichRingsName(const std::string& name) { rich_rings_name_ = name; };
+
+ // Settings for Trd Pid
+ void SetMinHits(int nhits_min) {// Min. number of hits per track
+ if (nhits_min < 1 || nhits_min > 4)
+ throw std::runtime_error("Wrong number of minimum hits: Number of minimum hits need to be between 1 and 4!");
+ else
+ nhits_min_ = nhits_min;
+ }
+ void SetTruncationMode(int trunc_mode) {// Calculation of energy loss for up to 4 layers:
+ // =0: average over all hits
+ if (trunc_mode < 0 || trunc_mode > 4) // =1-4: Select hits with lowest dEdx: 1 hit, =2: 2 hits, =3: 3 hits, =4: 4 hits
+ throw std::runtime_error("Wrong index for truncation mode: Truncation mode needs to be between 0 and 4!");
+ else
+ trunc_mode_ = trunc_mode;
+ }
+
+ void SetProbabilityMode(int prob_mode) {// Probability for particle species i:
+ // =0: total probability - probability based on particle multiplicites i
+ if (prob_mode < 0 || prob_mode > 1) // =1: likelihood - probability based on dEdx-distribution of particle
+ throw std::runtime_error("Wrong index for probability mode: Truncation mode needs to be between 0 and 4!");
+ else
+ prob_mode_ = prob_mode;
+ }
+
+ void SetPurity(const float purity) {// Minium purity for pid-hypothesis
+ if (purity < 0.0 || purity > 1.0)
+ throw std::runtime_error("Wrong value " + std::to_string(purity) + " for purity: Purity needs to be between 0.0 and 1.0!");
+ else
+ purity_ = purity;
+ }
+
protected:
int signum(int x) const;
+ float GetMomentumTrd(const AnalysisTree::BranchChannel& trd_particle);
+ float GetPtTrd(const AnalysisTree::BranchChannel& trd_particle);
+ int GetCharge(const AnalysisTree::BranchChannel& trd_particle);
+ void GetEnergyLossHitsTrd(const AnalysisTree::BranchChannel& trd_track, int& nhits_trd, std::array& dEdx);
+ bool IsRichElectron(const AnalysisTree::BranchChannel& rec_particle);
+
AnalysisTree::Branch rec_tracks_;
AnalysisTree::Branch tof_hits_;
+ AnalysisTree::Branch trd_tracks_;
+ AnalysisTree::Branch rich_rings_;
AnalysisTree::Branch ana_tracks_;
- AnalysisTree::Matching* pid_match_{nullptr};
+ AnalysisTree::Matching* rec_to_tof_{nullptr};
+ AnalysisTree::Matching* rec_to_trd_{nullptr};
+ AnalysisTree::Matching* rec_to_rich_{nullptr};
+ // Tof fields
AnalysisTree::Field qp_tof_field_;
AnalysisTree::Field q_field_;
AnalysisTree::Field mass2_field_;
- AnalysisTree::Field pid_field_;
- std::vector prob_field_{};
+ AnalysisTree::Field pid_tof_field_;
+ std::vector prob_tof_field_{};
+
+ // Trd fields
+ std::vector trd_dEdx_field_{};
+ AnalysisTree::Field el_rich_field_;
+ AnalysisTree::Field pid_trd_field_;
+ AnalysisTree::Field nhits_trd_eloss_field_;
+ std::vector prob_trd_field_{};
std::vector in_matches_{};
std::vector out_matches_{};
- std::string rec_tracks_name_{"VtxTracks"}; // Branch with input tracks
- std::string tof_hits_name_{"TofHits"}; // Branch with TOF info (m2)
- std::string out_branch_name_{"RecParticles"}; // Output branch (based on VtxTracks) with pid info: probabilities and particle type hypothesis
-
- Pid::Getter* getter_{nullptr};
- std::vector> pid_codes_{
- {PidParticles::kProton, "p"},
- {PidParticles::kPionPos, "pi"},
- {PidParticles::kKaonPos, "K"},
- {PidParticles::kDeutron, "d"},
- {PidParticles::kBgPos, "bg"}};
+ std::string rec_tracks_name_{"VtxTracks"}; // Branch with input tracks
+ std::string tof_hits_name_{"TofHits"}; // Branch with TOF info (m2)
+ std::string trd_tracks_name_{"TrdTracks"}; // Branch with Trd info (dEdx)
+ std::string rich_rings_name_{"RichRings"}; // Branch with Rich info
+ std::string out_branch_name_{"RecParticles"};// Output branch (based on VtxTracks) with pid info: probabilities and particle type hypothesis
+
+ bool is_run_pid_tof_{false};
+ bool is_run_pid_trd_{false};
+
+ int trunc_mode_{0};
+ int prob_mode_{0};
+ float purity_{0.0};
+ int nhits_min_{1};
+
+ Pid::GetterTof* getter_tof_{nullptr};
+ std::vector> pid_codes_tof_{
+ {PidTofParticles::kProton, "p"},
+ {PidTofParticles::kPionPos, "pi"},
+ {PidTofParticles::kKaonPos, "K"},
+ {PidTofParticles::kDeutron, "d"},
+ {PidTofParticles::kBgPos, "bg"}};
+
+ PidTrd::GetterTrd* getter_trd_{nullptr};
};
-#endif// PID_AT_INTERFACE_PIDFILLER_HPP_
+#endif// PID_INTERFACE_PIDFILLER_HPP_
diff --git a/at_interface/PidTrdMcInput.cpp b/at_interface/PidTrdMcInput.cpp
new file mode 100644
index 0000000..64e96c1
--- /dev/null
+++ b/at_interface/PidTrdMcInput.cpp
@@ -0,0 +1,397 @@
+#include "PidTrdMcInput.hpp"
+#include "ConstantsTrd.h"
+
+using namespace AnalysisTree;
+
+using std::to_string;
+
+float PidTrdMcInput::GetMomentum(const AnalysisTree::BranchChannel& trd_track) {
+ float momentum = 0;
+ if (TMath::Abs(trd_track.Value(rec_tracks_.GetField("p")) > 0))
+ momentum = trd_track.Value(rec_tracks_.GetField("p"));
+ else if (TMath::Abs(trd_track.Value(rec_tracks_.GetField("p_out")) > 0))
+ momentum = trd_track.Value(rec_tracks_.GetField("p_out"));
+ else
+ Warning("Exec", "Could not assign any momentum to the track, use p=0.");
+ return momentum;
+}
+
+float PidTrdMcInput::GetPt(const AnalysisTree::BranchChannel& trd_track) {
+ float pT = 0;
+ if (TMath::Abs(trd_track.Value(trd_tracks_.GetField("pT")) > 0))
+ pT = trd_track.Value(trd_tracks_.GetField("pT"));
+ else if (TMath::Abs(trd_track.Value(trd_tracks_.GetField("pT_out")) > 0))
+ pT = trd_track.Value(trd_tracks_.GetField("pT_out"));
+ else
+ Warning("Exec", "Could not assign any pT to the track, use pT=0.");
+ return pT;
+}
+
+int PidTrdMcInput::GetMcPdg(const AnalysisTree::BranchChannel& rec_track) {
+ const int sim_id = rec_to_sim_->GetMatch(rec_track.GetId());
+ int pdg;
+ if (sim_id < 0) pdg = -1;
+ else
+ pdg = sim_tracks_[sim_id].Value(sim_tracks_.GetField("pid"));
+ return pdg;
+}
+
+int PidTrdMcInput::GetCharge(const AnalysisTree::BranchChannel& rec_track) {
+ int charge = rec_track.Value(rec_tracks_.GetField("q"));
+ return charge;
+}
+
+void PidTrdMcInput::GetEnergyLossHits(const AnalysisTree::BranchChannel& trd_track, int& nhits_trd, array& dEdx) {
+
+ nhits_trd = 0;
+ for (int ihit = 0; ihit < NumberOfTrdLayers; ihit++) {
+ if (trd_track.Value(trd_dEdx_field_.at(ihit)) > 0) {
+ dEdx.at(ihit) = trd_track.Value(trd_dEdx_field_.at(ihit));
+ nhits_trd++;
+ } else
+ dEdx.at(ihit) = 0;
+ }
+}
+
+void PidTrdMcInput::FillHistogram(TrdContainer track) {
+
+ float mom = track.GetP();
+ int nhits_trd = track.GetNhitsTrd();
+ int mc_pdg = track.GetMcPdg();
+ int charge = track.GetCharge();
+
+ // Histograms for dEdx of track
+ for (int imode = 0; imode < nhits_trd; imode++) {
+
+ float dEdx = track.GetdEdxTrack(imode);
+ if (dEdx <= 0) continue;
+
+ outFile_->cd(dirname_tracks_ + "/" + dirname_nhits_.at(nhits_trd - 1) + "/reco_info");
+ if (charge > 0)
+ h2dEdx_p_pos_[imode]->Fill(mom, dEdx);
+ if (charge < 0)
+ h2dEdx_p_neg_[imode]->Fill(mom, dEdx);
+
+ for (int ipdg = 0; ipdg < NumberOfPidsTrd - 1; ipdg++) {
+ if (TMath::Abs(mc_pdg) == pid_codes_trd_.at(ipdg).first) {
+ outFile_->cd(dirname_tracks_ + "/" + dirname_nhits_.at(nhits_trd - 1) + "/reco_vs_sim_info/" + pid_codes_trd_.at(ipdg).second);
+ if (charge > 0)
+ h2dEdx_p_pdg_[imode].at(ipdg)->Fill(mom, dEdx);
+ if (charge < 0)
+ h2dEdx_p_pdg_[imode].at(NumberOfPidsTrd - 1 + ipdg)->Fill(mom, dEdx);
+ }
+ }
+ }
+
+ // Histograms for dEdx of hits
+ std::array dEdx_hits_sorted = track.GetdEdxHitsSorted();
+
+ // All hits in one plot for every particle
+ outFile_->cd(dirname_hits_ + "/reco_info");
+ for (int ihit = 0; ihit < nhits_trd; ihit++) {
+ if (charge > 0)
+ h2dEdx_hits_all_p_pos_->Fill(mom, dEdx_hits_sorted.at(ihit));
+ if (charge < 0)
+ h2dEdx_hits_all_p_neg_->Fill(mom, dEdx_hits_sorted.at(ihit));
+ }
+
+ for (int ipdg = 0; ipdg < NumberOfPidsTrd - 1; ipdg++) {
+ if (TMath::Abs(mc_pdg) == pid_codes_trd_.at(ipdg).first) {
+ outFile_->cd(dirname_hits_ + "/reco_vs_sim_info/" + pid_codes_trd_.at(ipdg).second);
+ for (int ihit = 0; ihit < nhits_trd; ihit++) {
+ if (charge > 0)
+ h2dEdx_hits_all_p_pdg_.at(ipdg)->Fill(mom, dEdx_hits_sorted.at(ihit));
+ if (charge < 0)
+ h2dEdx_hits_all_p_pdg_.at(NumberOfPidsTrd - 1 + ipdg)->Fill(mom, dEdx_hits_sorted.at(ihit));
+ }
+ }
+ }
+ for (int imode = 0; imode < nhits_trd; imode++) {
+ outFile_->cd(dirname_hits_ + "/" + dirname_nhits_.at(nhits_trd - 1) + "/reco_info");
+ for (int ihit = 0; ihit < imode + 1; ihit++) {
+ if (charge > 0)
+ h2dEdx_hits_p_pos_[imode]->Fill(mom, dEdx_hits_sorted.at(ihit));
+ if (charge < 0)
+ h2dEdx_hits_p_neg_[imode]->Fill(mom, dEdx_hits_sorted.at(ihit));
+ }
+
+ // Hits seperated by number of hits per track & truncation mode
+ for (int ipdg = 0; ipdg < NumberOfPidsTrd - 1; ipdg++) {
+ if (TMath::Abs(mc_pdg) == pid_codes_trd_.at(ipdg).first) {
+ outFile_->cd(dirname_hits_ + "/" + dirname_nhits_.at(nhits_trd - 1) + "/reco_vs_sim_info/" + pid_codes_trd_.at(ipdg).second);
+ for (int ihit = 0; ihit < imode + 1; ihit++) {
+ if (charge > 0)
+ h2dEdx_hits_p_pdg_[imode].at(ipdg)->Fill(mom, dEdx_hits_sorted.at(ihit));
+ if (charge < 0)
+ h2dEdx_hits_p_pdg_[imode].at(NumberOfPidsTrd - 1 + ipdg)->Fill(mom, dEdx_hits_sorted.at(ihit));
+ }
+ }
+ }
+ }
+}
+
+void PidTrdMcInput::CreateMcHistograms(int nhits) {
+
+ TString histname;
+
+ // Histgrams for dEdx of tracks
+ for (int imode = 0; imode < NumberOfTruncMode - 1; imode++) {
+ outFile_->cd(dirname_tracks_ + "/" + dirname_nhits_.at(nhits - 1) + "/reco_info");
+
+ h2dEdx_p_pos_[imode] = (TH2F*) gDirectory->Get(histnames_all_pos_.at(imode));
+ h2dEdx_p_neg_[imode] = (TH2F*) gDirectory->Get(histnames_all_neg_.at(imode));
+
+ for (int ipdg = 0; ipdg < NumberOfPidsTrd - 1; ipdg++) {
+ outFile_->cd(dirname_tracks_ + "/" + dirname_nhits_.at(nhits - 1) + "/reco_vs_sim_info/" + pid_codes_trd_.at(ipdg).second);
+
+ histname = histnames_pos_.at(imode).at(ipdg);
+ h2dEdx_p_pdg_[imode].at(ipdg) = (TH2F*) gDirectory->Get(histname);
+
+ histname = histnames_neg_.at(imode).at(ipdg);
+ h2dEdx_p_pdg_[imode].at(NumberOfPidsTrd - 1 + ipdg) = (TH2F*) gDirectory->Get(histname);
+ }
+ }
+
+ // Histgrams for dEdx of hits
+ outFile_->cd(dirname_hits_ + "/reco_info");
+ h2dEdx_hits_all_p_pos_ = (TH2F*) gDirectory->Get(histnames_hits_all_pos_);
+ h2dEdx_hits_all_p_neg_ = (TH2F*) gDirectory->Get(histnames_hits_all_neg_);
+
+ for (int ipdg = 0; ipdg < NumberOfPidsTrd - 1; ipdg++) {
+ outFile_->cd(dirname_hits_ + "/reco_vs_sim_info/" + pid_codes_trd_.at(ipdg).second);
+
+ histname = histnames_hits_pos_.at(ipdg);
+ h2dEdx_hits_all_p_pdg_.at(ipdg) = (TH2F*) gDirectory->Get(histname);
+
+ histname = histnames_hits_neg_.at(ipdg);
+ h2dEdx_hits_all_p_pdg_.at(NumberOfPidsTrd - 1 + ipdg) = (TH2F*) gDirectory->Get(histname);
+ }
+
+ for (int imode = 0; imode < NumberOfTruncMode - 1; imode++) {
+ outFile_->cd(dirname_hits_ + "/" + dirname_nhits_.at(nhits - 1) + "/reco_info");
+
+ h2dEdx_hits_p_pos_[imode] = (TH2F*) gDirectory->Get(histnames_all_pos_.at(imode));
+ h2dEdx_hits_p_neg_[imode] = (TH2F*) gDirectory->Get(histnames_all_neg_.at(imode));
+
+ for (int ipdg = 0; ipdg < NumberOfPidsTrd - 1; ipdg++) {
+ outFile_->cd(dirname_hits_ + "/" + dirname_nhits_.at(nhits - 1) + "/reco_vs_sim_info/" + pid_codes_trd_.at(ipdg).second);
+
+ histname = histnames_pos_.at(imode).at(ipdg);
+ h2dEdx_hits_p_pdg_[imode].at(ipdg) = (TH2F*) gDirectory->Get(histname);
+
+ histname = histnames_neg_.at(imode).at(ipdg);
+ h2dEdx_hits_p_pdg_[imode].at(NumberOfPidsTrd - 1 + ipdg) = (TH2F*) gDirectory->Get(histname);
+ }
+ }
+
+ auto it = trd_container_.find(nhits);
+ if (it != trd_container_.end()) {
+ for (auto track : it->second) {
+ FillHistogram(track);
+ }
+ }
+ outFile_->cd();
+ outFile_->Write("", TObject::kOverwrite);
+}
+
+void PidTrdMcInput::InitMcHistograms() {
+
+ outFile_ = new TFile(outfilename_, "RECREATE");
+
+ // Create directories
+ TDirectory *directory, *directory1, *directory2, *directory3;
+ for (int idir = 0; idir < 2; idir++) {
+ if (idir == 0) directory = outFile_->mkdir(dirname_tracks_);
+ if (idir == 1) {
+ directory = outFile_->mkdir(dirname_hits_);
+ directory1 = directory->mkdir("reco_info");
+ directory1 = directory->mkdir("reco_vs_sim_info");
+ for (int ipdg = 0; ipdg < NumberOfPidsTrd - 1; ipdg++) {
+ directory2 = directory1->mkdir(pid_codes_trd_.at(ipdg).second);
+ }
+ }
+ for (int inhits = 0; inhits < NumberOfTrdLayers; inhits++) {
+ directory1 = directory->mkdir(dirname_nhits_.at(inhits));
+ directory2 = directory1->mkdir("reco_info");
+ directory2 = directory1->mkdir("reco_vs_sim_info");
+ for (int ipdg = 0; ipdg < NumberOfPidsTrd - 1; ipdg++) {
+ directory3 = directory2->mkdir(pid_codes_trd_.at(ipdg).second);
+ }
+ }
+ }
+
+ // Initialize histograms
+ TString dirname, histname, histtitle;
+ TH2F* histogram;
+
+ for (int idir = 0; idir < 2; idir++) {
+
+ if (idir == 0) dirname = dirname_tracks_;
+
+ if (idir == 1) {
+
+ dirname = dirname_hits_;
+
+ outFile_->cd(dirname + "/reco_info");
+ histname = histnames_hits_all_pos_;
+ histtitle = "dEdx hits vs. p_{rec} all+";
+ histogram = new TH2F(histname, histtitle, nbins_mom_, bins_mom_, nbins_dEdx_, bins_dEdx_);
+ histogram->Write();
+
+ histname = histnames_hits_all_neg_;
+ histtitle = "dEdx hits vs. p_{rec} all- ";
+ histogram = new TH2F(histname, histtitle, nbins_mom_, bins_mom_, nbins_dEdx_, bins_dEdx_);
+ histogram->Write();
+
+ for (int ipdg = 0; ipdg < NumberOfPidsTrd - 1; ipdg++) {
+ TString particlename = pid_codes_trd_.at(ipdg).second;
+
+ outFile_->cd(dirname + "/reco_vs_sim_info/" + pid_codes_trd_.at(ipdg).second);
+
+ histname = histnames_hits_pos_.at(ipdg);
+ histtitle = Form("dEdx hits : p_{rec} (%s+)", particlename.Data());
+ histogram = new TH2F(histname, histtitle, nbins_mom_, bins_mom_, nbins_dEdx_, bins_dEdx_);
+ histogram->Write();
+
+ histname = histnames_hits_neg_.at(ipdg);
+ histtitle = Form("dEdx hits : p_{rec} (%s-)", particlename.Data());
+ histogram = new TH2F(histname, histtitle, nbins_mom_, bins_mom_, nbins_dEdx_, bins_dEdx_);
+ histogram->Write();
+ }
+ }
+
+ for (int inhits = 0; inhits < NumberOfTrdLayers; inhits++) {
+ for (int imode = 0; imode < NumberOfTruncMode - 1; imode++) {
+
+ if (imode > inhits) continue;
+
+ outFile_->cd(dirname + "/" + dirname_nhits_.at(inhits) + "/reco_info");
+
+ histname = histnames_all_pos_.at(imode);
+ histtitle = "dEdx vs. p_{rec} all+ " + to_string(inhits + 1) + " Trd Hits - " + histtitle_mode_.at(imode);
+ histogram = new TH2F(histname, histtitle, nbins_mom_, bins_mom_, nbins_dEdx_, bins_dEdx_);
+ histogram->Write();
+
+ histname = histnames_all_neg_.at(imode);
+ histtitle = "dEdx vs. p_{rec} all- " + to_string(inhits + 1) + " Trd Hits - " + histtitle_mode_.at(imode);
+ histogram = new TH2F(histname, histtitle, nbins_mom_, bins_mom_, nbins_dEdx_, bins_dEdx_);
+ histogram->Write();
+
+ for (int ipdg = 0; ipdg < NumberOfPidsTrd - 1; ipdg++) {
+ TString particlename = pid_codes_trd_.at(ipdg).second;
+
+ outFile_->cd(dirname + "/" + dirname_nhits_.at(inhits) + "/reco_vs_sim_info/" + pid_codes_trd_.at(ipdg).second);
+
+ histname = histnames_pos_.at(imode).at(ipdg);
+ histtitle = Form("dEdx : p_{rec} (%s+) %d Trd Hits - %s", particlename.Data(), inhits + 1, histtitle_mode_.at(imode).Data());
+ histogram = new TH2F(histname, histtitle, nbins_mom_, bins_mom_, nbins_dEdx_, bins_dEdx_);
+ histogram->Write();
+
+ histname = histnames_neg_.at(imode).at(ipdg);
+ histtitle = Form("dEdx : p_{rec} (%s-) %d Trd Hits - %s", particlename.Data(), inhits + 1, histtitle_mode_.at(imode).Data());
+ histogram = new TH2F(histname, histtitle, nbins_mom_, bins_mom_, nbins_dEdx_, bins_dEdx_);
+ histogram->Write();
+ }
+ }
+ }
+ }
+}
+
+void PidTrdMcInput::OpenMcHistograms() {
+ outFile_ = new TFile(outfilename_, "UPDATE");
+}
+
+void PidTrdMcInput::Init() {
+ auto man = TaskManager::GetInstance();
+ auto chain = man->GetChain();
+
+ chain->InitPointersToBranches({});
+ rec_tracks_ = chain->GetBranchObject(rec_tracks_name_);
+ trd_tracks_ = chain->GetBranchObject(trd_tracks_name_);
+ sim_tracks_ = chain->GetBranchObject(sim_tracks_name_);
+ rec_to_trd_ = chain->GetMatching(rec_tracks_name_, trd_tracks_name_);
+ rec_to_sim_ = chain->GetMatching(rec_tracks_name_, sim_tracks_name_);
+
+ for (int i = 0; i < NumberOfTrdLayers; i++)
+ trd_dEdx_field_.push_back(trd_tracks_.GetField(("energy_loss_" + to_string(i)).c_str()));
+
+ Float_t bw_mom, bw_dEdx;
+
+ if (update_mchisto_ == kFALSE) {
+ bw_mom = BwMom;
+ nbins_mom_ = NbinsMom;
+ bins_mom_[0] = 0.;
+ for (int i = 0; i < nbins_mom_; i++)
+ bins_mom_[i + 1] = TMath::Power(10, -1.0 + i * bw_mom);
+
+ bw_dEdx = BwdEdx;
+ nbins_dEdx_ = NbinsdEdx;
+ bins_dEdx_[0] = 0.;
+ for (int i = 0; i < nbins_dEdx_; i++)
+ bins_dEdx_[i + 1] = TMath::Power(10, -1.0 + i * bw_dEdx);
+ }
+
+ for (int imode = 0; imode < NumberOfTruncMode - 1; imode++) {
+ histnames_all_pos_.at(imode) = "h2dEdx_p_pos_" + to_string(imode);
+ histnames_all_neg_.at(imode) = "h2dEdx_p_neg_" + to_string(imode);
+ for (int ipdg = 0; ipdg < NumberOfPidsTrd - 1; ipdg++) {
+ TString particlename = pid_codes_trd_.at(ipdg).second;
+ histnames_pos_.at(imode).at(ipdg) = "h2dEdx_p_" + particlename + "_pos_" + to_string(imode);
+ histnames_neg_.at(imode).at(ipdg) = "h2dEdx_p_" + particlename + "_neg_" + to_string(imode);
+ }
+
+ histnames_hits_all_pos_ = "h2dEdx_p_pos";
+ histnames_hits_all_neg_ = "h2dEdx_p_neg";
+ for (int ipdg = 0; ipdg < NumberOfPidsTrd - 1; ipdg++) {
+ TString particlename = pid_codes_trd_.at(ipdg).second;
+ histnames_hits_pos_.at(ipdg) = "h2dEdx_p_" + particlename + "_pos";
+ histnames_hits_neg_.at(ipdg) = "h2dEdx_p_" + particlename + "_neg";
+ }
+ }
+
+ if (update_mchisto_ == kTRUE)
+ OpenMcHistograms();
+ else
+ InitMcHistograms();
+}
+
+void PidTrdMcInput::Exec() {
+ trd_container_.clear();
+
+ for (int itrack = 0; itrack < rec_tracks_.size(); ++itrack) {
+ const auto& rec_track = rec_tracks_[itrack];
+ int itrd = rec_to_trd_->GetMatch(rec_track.GetId());
+ if (itrd < 0) continue;
+ const auto& trd_track = trd_tracks_[itrd];
+
+ float mom = GetMomentum(trd_track);
+ float pT = GetPt(trd_track);
+ int mc_pdg = GetMcPdg(rec_track);
+ int charge = GetCharge(rec_track);
+ array dEdx_hits = {0.0, 0.0, 0.0, 0.0};
+ int nhits_trd = 0;
+
+ GetEnergyLossHits(trd_track, nhits_trd, dEdx_hits);
+
+ if (nhits_trd < 1) continue;
+
+ TrdContainer trdtrack(mom, pT, charge, nhits_trd, dEdx_hits, mc_pdg);
+ trdtrack.ScaleEnergyLossLength();
+ trdtrack.CalculateEnergyLossTrackAllModes();
+
+ auto it = trd_container_.find(nhits_trd);
+ if (it != trd_container_.end()) {
+ it->second.emplace_back(trdtrack);
+ } else {
+ trd_container_[nhits_trd] = {static_cast(trdtrack)};
+ }
+ }
+
+ for (int inhits = 0; inhits < NumberOfTrdLayers; inhits++) {
+ CreateMcHistograms(inhits + 1);
+ }
+}
+
+void PidTrdMcInput::Finish() {
+ outFile_->Close();
+}
diff --git a/at_interface/PidTrdMcInput.hpp b/at_interface/PidTrdMcInput.hpp
new file mode 100644
index 0000000..4ca28de
--- /dev/null
+++ b/at_interface/PidTrdMcInput.hpp
@@ -0,0 +1,89 @@
+#ifndef PIDTRD_MCINPUT_HPP_
+#define PIDTRD_MCINPUT_HPP_
+
+#include "TH2F.h"
+
+#include "AnalysisTree/Task.hpp"
+#include "AnalysisTree/TaskManager.hpp"
+
+#include "ContainerTrd.h"
+
+using std::array;
+
+class PidTrdMcInput : public AnalysisTree::Task {
+
+ public:
+ PidTrdMcInput(const std::string& outfilename) {
+ outfilename_ = outfilename;
+ };
+ ~PidTrdMcInput() override = default;
+
+ void Init() override;
+ void InitMcHistograms();
+ void OpenMcHistograms();
+ void Exec() override;
+ void Finish() override;
+
+ void SetRecTracksName(const std::string& name) { rec_tracks_name_ = name; };
+ void SetSimTracksName(const std::string& name) { sim_tracks_name_ = name; };
+ void SetTrdTracksName(const std::string& name) { trd_tracks_name_ = name; };
+ void SetUpdateMcHistos(const Bool_t update_mchisto) { update_mchisto_ = update_mchisto; };
+
+ protected:
+ float GetMomentum(const AnalysisTree::BranchChannel& trd_track);
+ float GetPt(const AnalysisTree::BranchChannel& trd_particle);
+ int GetMcPdg(const AnalysisTree::BranchChannel& rec_track);
+ int GetCharge(const AnalysisTree::BranchChannel& rec_track);
+ void GetEnergyLossHits(const AnalysisTree::BranchChannel& trd_track, int& nhits_trd, array& dEdx);
+ void CalculateEnergyLoss(TrdContainer track, float& dEdx_track, int trunc_mode);
+ void CreateMcHistograms(int trunc_mode);
+ void FillHistogram(TrdContainer track, float dEdx);
+ void FillHistogram(TrdContainer track);
+ bool IsRichElectron(const AnalysisTree::BranchChannel& rec_particle);
+
+ AnalysisTree::Branch rec_tracks_;
+ AnalysisTree::Branch sim_tracks_;
+ AnalysisTree::Branch trd_tracks_;
+
+ AnalysisTree::Matching* rec_to_sim_{nullptr};
+ AnalysisTree::Matching* rec_to_trd_{nullptr};
+
+ std::string rec_tracks_name_{"RecTracks"}; // Branch with input tracks
+ std::string trd_tracks_name_{"TrdTracks"}; // Branch with Trd info (dEdx)
+ std::string sim_tracks_name_{"SimParticles"};// Branch with Mc info
+
+ std::vector trd_dEdx_field_{};
+
+ TString outfilename_;
+ TFile* outFile_;
+
+ // MC histograms
+
+ TString histnames_hits_all_pos_, histnames_hits_all_neg_;
+ array histnames_hits_pos_, histnames_hits_neg_;
+ array histnames_all_pos_, histnames_all_neg_;
+ array, NumberOfTrdLayers> histnames_pos_, histnames_neg_;
+
+ TString outfile_info_{""};
+
+ TH2F* h2dEdx_p_pos_[NumberOfTruncMode - 1];
+ TH2F* h2dEdx_p_neg_[NumberOfTruncMode - 1];
+ array h2dEdx_p_pdg_[NumberOfTrdLayers];
+ TH2F* h2dEdx_hits_all_p_pos_;
+ TH2F* h2dEdx_hits_all_p_neg_;
+ array h2dEdx_hits_all_p_pdg_;
+ TH2F* h2dEdx_hits_p_pos_[NumberOfTruncMode - 1];
+ TH2F* h2dEdx_hits_p_neg_[NumberOfTruncMode - 1];
+ array h2dEdx_hits_p_pdg_[NumberOfTrdLayers];
+
+ Int_t nbins_mom_;
+ Double_t bins_mom_[NbinsMax];
+ Int_t nbins_dEdx_;
+ Double_t bins_dEdx_[NbinsMax];
+
+ Bool_t update_mchisto_{kFALSE};
+
+ std::map> trd_container_;//container with trd tracks
+};
+
+#endif//PIDTRD_AT_INTERFACE_PIDFILLER_HPP_
diff --git a/input/dEdx_p.jul25.phqmd.auau.12agev.root b/input/dEdx_p.jul25.phqmd.auau.12agev.root
new file mode 100644
index 0000000..97b5761
Binary files /dev/null and b/input/dEdx_p.jul25.phqmd.auau.12agev.root differ
diff --git a/input/dEdx_p.jul25.phqmd.auau.12agev_probabilities.root b/input/dEdx_p.jul25.phqmd.auau.12agev_probabilities.root
new file mode 100644
index 0000000..a3af9c3
Binary files /dev/null and b/input/dEdx_p.jul25.phqmd.auau.12agev_probabilities.root differ
diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt
new file mode 100644
index 0000000..e6f4aea
--- /dev/null
+++ b/interface/CMakeLists.txt
@@ -0,0 +1,32 @@
+set(SOURCES
+ PidTrdRunGetter.cpp
+ )
+
+string(REPLACE ".cpp" ".hpp" HEADERS "${SOURCES}")
+include_directories(${PROJECT_INCLUDE_DIRECTORIES} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/src_trd)
+add_library(PidInt SHARED ${SOURCES} G__PidInt.cxx)
+
+message("${PROJECT_INCLUDE_DIRECTORIES}")
+
+ROOT_GENERATE_DICTIONARY(G__PidInt ${HEADERS} LINKDEF PidIntLinkDef.h)
+target_link_libraries(PidInt ${ROOT_LIBRARIES} PidTrd)
+
+install(
+ FILES
+ ${HEADERS}
+ DESTINATION
+ include
+ COMPONENT
+ Devel
+)
+
+set(PCM_FILE_NAME libPidInt)
+
+install(
+ FILES
+ "${CMAKE_CURRENT_BINARY_DIR}/${PCM_FILE_NAME}_rdict.pcm"
+ "${CMAKE_CURRENT_BINARY_DIR}/${PCM_FILE_NAME}.rootmap"
+ DESTINATION
+ lib
+ OPTIONAL
+)
diff --git a/interface/PidIntLinkDef.h b/interface/PidIntLinkDef.h
new file mode 100644
index 0000000..90de817
--- /dev/null
+++ b/interface/PidIntLinkDef.h
@@ -0,0 +1,8 @@
+#ifndef PID_INTERFACE_PIDLINKDEF_H_
+#define PID_INTERFACE_PIDLINKDEF_H_
+
+#pragma link off all globals;
+#pragma link off all classes;
+#pragma link off all functions;
+
+#endif //PID_INTERFACE_PIDLINKDEF_H_
diff --git a/interface/PidTrdRunGetter.cpp b/interface/PidTrdRunGetter.cpp
new file mode 100644
index 0000000..ac60d33
--- /dev/null
+++ b/interface/PidTrdRunGetter.cpp
@@ -0,0 +1,163 @@
+#include "PidTrdRunGetter.hpp"
+#include "ConstantsTrd.h"
+using std::to_string;
+
+void PidTrdRunGetter::CalculateProbabilities(int nhits) {
+
+ TH2F* h2pos;
+ TH2F* h2neg;
+ TH2F* h2tmp;
+ TH2F* h2prob;
+ TString histname;
+ PidTrd::ParticleProb particleprob;
+
+ for (int truncmode = 0; truncmode < nhits + 1; truncmode++) {
+ inFile_->cd(dirname_tracks_ + "/" + dirname_nhits_.at(nhits) + "/reco_info");
+ h2pos = (TH2F*) gDirectory->Get(histnames_all_pos_.at(truncmode));
+ h2neg = (TH2F*) gDirectory->Get(histnames_all_neg_.at(truncmode));
+
+ for (int ipdg = 0; ipdg < NumberOfPidsTrd - 1; ipdg++) {
+ TString particlename = pid_codes_trd_.at(ipdg).second.Data();
+ int charge = 1;// charge = 1: positive particles
+
+ int probmode = 0;// total probability - probability based on particle multiplicites
+ inFile_->cd(dirname_tracks_ + "/" + dirname_nhits_.at(nhits) + "/reco_vs_sim_info/" + pid_codes_trd_.at(ipdg).second);
+ h2tmp = (TH2F*) gDirectory->Get(histnames_pos_.at(truncmode).at(ipdg));
+ h2prob = (TH2F*) h2tmp->Clone(histnames_prob_pos_.at(truncmode).at(ipdg));
+ CalculateProbabilitiesTot(h2pos, h2tmp, h2prob);
+ h2prob->SetTitle(Form("dEdx : p_{rec} probability (T) (%s+) %d Trd Hits - %s", pid_codes_trd_.at(ipdg).second.Data(), nhits + 1, histtitle_mode_.at(truncmode).Data()));
+ particleprob.Update(ipdg, charge, nhits, truncmode, probmode, h2prob);
+ getter_trd_.AddParticleProb(particleprob);
+ if (write_mchistograms_out_ == kTRUE)
+ outFile_->cd(dirname_nhits_.at(nhits) + "/" + particlename + "/" + probname_.at(0)) && h2prob->Write("", TObject::kOverwrite);
+
+ probmode = 1;// likelihood - probability based on dEdx-distribution of particle
+ inFile_->cd(dirname_hits_ + "/" + dirname_nhits_.at(nhits) + "/reco_vs_sim_info/" + pid_codes_trd_.at(ipdg).second);
+ h2tmp = (TH2F*) gDirectory->Get(histnames_pos_.at(truncmode).at(ipdg));
+ h2prob = (TH2F*) h2tmp->Clone(histnames_prob_pos_.at(truncmode).at(ipdg));
+ CalculateProbabilitiesLike(h2tmp, h2prob);
+ h2prob->SetTitle(Form("dEdx : p_{rec} probability (L) (%s+) %d Trd Hits - %s", pid_codes_trd_.at(ipdg).second.Data(), nhits + 1, histtitle_mode_.at(truncmode).Data()));
+ particleprob.Update(ipdg, charge, nhits, truncmode, probmode, h2prob);
+ getter_trd_.AddParticleProb(particleprob);
+ if (write_mchistograms_out_ == kTRUE)
+ outFile_->cd(dirname_nhits_.at(nhits) + "/" + particlename + "/" + probname_.at(1)) && h2prob->Write("", TObject::kOverwrite);
+
+ charge = -1;// charge = -1: negative particles
+ probmode = 0;
+ inFile_->cd(dirname_tracks_ + "/" + dirname_nhits_.at(nhits) + "/reco_vs_sim_info/" + pid_codes_trd_.at(ipdg).second);
+ h2tmp = (TH2F*) gDirectory->Get(histnames_neg_.at(truncmode).at(ipdg));
+ h2prob = (TH2F*) h2tmp->Clone(histnames_prob_neg_.at(truncmode).at(ipdg));
+ CalculateProbabilitiesTot(h2neg, h2tmp, h2prob);
+ h2prob->SetTitle(Form("dEdx : p_{rec} probability (T) (%s-) %d Trd Hits - %s", pid_codes_trd_.at(ipdg).second.Data(), nhits + 1, histtitle_mode_.at(truncmode).Data()));
+ particleprob.Update(ipdg, charge, nhits, truncmode, probmode, h2prob);
+ getter_trd_.AddParticleProb(particleprob);
+ if (write_mchistograms_out_ == kTRUE)
+ outFile_->cd(dirname_nhits_.at(nhits) + "/" + particlename + "/" + probname_.at(0)) && h2prob->Write("", TObject::kOverwrite);
+
+ probmode = 1;
+ inFile_->cd(dirname_hits_ + "/" + dirname_nhits_.at(nhits) + "/reco_vs_sim_info/" + pid_codes_trd_.at(ipdg).second);
+ h2tmp = (TH2F*) gDirectory->Get(histnames_neg_.at(truncmode).at(ipdg));
+ h2prob = (TH2F*) h2tmp->Clone(histnames_prob_neg_.at(truncmode).at(ipdg));
+ CalculateProbabilitiesLike(h2tmp, h2prob);
+ h2prob->SetTitle(Form("dEdx : p_{rec} probability (L) (%s-) %d Trd Hits - %s", pid_codes_trd_.at(ipdg).second.Data(), nhits + 1, histtitle_mode_.at(truncmode).Data()));
+ particleprob.Update(ipdg, charge, nhits, truncmode, probmode, h2prob);
+ getter_trd_.AddParticleProb(particleprob);
+ if (write_mchistograms_out_ == kTRUE)
+ outFile_->cd(dirname_nhits_.at(nhits) + "/" + particlename + "/" + probname_.at(1)) && h2prob->Write("", TObject::kOverwrite);
+ }
+ }
+ h2tmp->Delete();
+}
+
+void PidTrdRunGetter::CalculateProbabilitiesTot(TH2F* h2all, TH2F* h2tmp, TH2F*& h2prob) {
+ h2prob->Divide(h2all);
+}
+
+void PidTrdRunGetter::CalculateProbabilitiesLike(TH2F* h2tmp, TH2F*& h2prob) {
+ for (Int_t ibinx = 1; ibinx < h2tmp->GetNbinsX() + 1; ibinx++) {
+ Double_t sumy = 0.;
+ for (Int_t ibiny = 1; ibiny < h2tmp->GetNbinsY() + 1; ibiny++)
+ sumy += h2tmp->GetBinContent(ibinx, ibiny);
+ for (Int_t ibiny = 1; ibiny < h2tmp->GetNbinsY() + 1; ibiny++)
+ if (sumy > 0) h2prob->SetBinContent(ibinx, ibiny, h2tmp->GetBinContent(ibinx, ibiny) / sumy);
+ }
+}
+
+void PidTrdRunGetter::InitMcHistogramsOut() {
+
+ TDirectory *directory, *directory1, *directory2;
+
+ for (int imode = 0; imode < NumberOfTruncMode - 1; imode++) {
+ for (int ipdg = 0; ipdg < NumberOfPidsTrd - 1; ipdg++) {
+ TString particlename = pid_codes_trd_.at(ipdg).second;
+ histnames_prob_pos_.at(imode).at(ipdg) = "h2dEdx_p_prob_" + particlename + "_pos_" + to_string(imode);
+ histnames_prob_neg_.at(imode).at(ipdg) = "h2dEdx_p_prob_" + particlename + "_neg_" + to_string(imode);
+ }
+ }
+
+ for (int inhits = 0; inhits < NumberOfTrdLayers; inhits++) {
+ directory = outFile_->mkdir(dirname_nhits_.at(inhits));
+ for (int ipdg = 0; ipdg < NumberOfPidsTrd - 1; ipdg++) {
+ outFile_->cd();
+ directory1 = directory->mkdir(pid_codes_trd_.at(ipdg).second);
+ directory2 = directory1->mkdir(probname_.at(0));
+ directory2 = directory1->mkdir(probname_.at(1));
+ }
+ }
+}
+
+void PidTrdRunGetter::OpenMcHistograms() {
+
+ for (int imode = 0; imode < NumberOfTruncMode - 1; imode++) {
+ histnames_all_pos_.at(imode) = "h2dEdx_p_pos_" + to_string(imode);
+ histnames_all_neg_.at(imode) = "h2dEdx_p_neg_" + to_string(imode);
+ for (int ipdg = 0; ipdg < NumberOfPidsTrd - 1; ipdg++) {
+ TString particlename = pid_codes_trd_.at(ipdg).second;
+ histnames_pos_.at(imode).at(ipdg) = "h2dEdx_p_" + particlename + "_pos_" + to_string(imode);
+ histnames_neg_.at(imode).at(ipdg) = "h2dEdx_p_" + particlename + "_neg_" + to_string(imode);
+ }
+ }
+
+ histnames_hits_all_pos_ = "h2dEdx_p_pos";
+ histnames_hits_all_neg_ = "h2dEdx_p_neg";
+ for (int ipdg = 0; ipdg < NumberOfPidsTrd - 1; ipdg++) {
+ TString particlename = pid_codes_trd_.at(ipdg).second;
+ histnames_hits_pos_.at(ipdg) = "h2dEdx_p_" + particlename + "_pos";
+ histnames_hits_neg_.at(ipdg) = "h2dEdx_p_" + particlename + "_neg";
+ }
+}
+
+void PidTrdRunGetter::Init() {
+
+ inFile_ = new TFile(mcfile_name_, "READ");
+ if (!inFile_ || !inFile_->IsOpen()) {
+ throw std::runtime_error("Could not open input file: " + mcfile_name_);
+ }
+
+ OpenMcHistograms();
+
+ if (write_mchistograms_out_ == kTRUE) {
+ TString name = mcfile_name_;
+ name.Replace(name.Index(".root"), 5, "");
+ TString outfilename = Form("%s_probabilities.root", name.Data());
+ outFile_ = new TFile(outfilename, "RECREATE");
+ InitMcHistogramsOut();
+ }
+}
+
+void PidTrdRunGetter::Exec() {
+
+ for (int inhits = 0; inhits < NumberOfTrdLayers; inhits++)
+ CalculateProbabilities(inhits);
+
+ std::unique_ptr outFile_getter{TFile::Open(getter_file_, "recreate")};
+ outFile_getter->WriteObject(&getter_trd_, getter_name_);
+ outFile_getter->Close();
+
+ if (write_mchistograms_out_ == kTRUE) outFile_->Close();
+}
+
+void PidTrdRunGetter::Finish() {
+ inFile_->Close();
+ if (write_mchistograms_out_ == kTRUE) outFile_->Close();
+}
diff --git a/interface/PidTrdRunGetter.hpp b/interface/PidTrdRunGetter.hpp
new file mode 100644
index 0000000..5da4812
--- /dev/null
+++ b/interface/PidTrdRunGetter.hpp
@@ -0,0 +1,60 @@
+#ifndef PIDTRD_RUNGETTER_HPP_
+#define PIDTRD_RUNGETTER_HPP_
+
+#include "TH2F.h"
+
+#include "GetterTrd.h"
+#include "ParticleProb.h"
+
+using std::array;
+
+class PidTrdRunGetter {
+
+ public:
+ PidTrdRunGetter(const std::string& mcfile_name, const std::string& getter_file, TString getter_name) {
+ mcfile_name_ = mcfile_name;
+ getter_file_ = getter_file;
+ getter_name_ = getter_name;
+ };
+ virtual ~PidTrdRunGetter() = default;
+
+ void Init();
+ void OpenMcHistograms();
+ void InitMcHistogramsOut();
+ void Exec();
+ void Finish();
+ void SetWriteMcHistogramsOut(const Bool_t write_mchistograms_out) { write_mchistograms_out_ = write_mchistograms_out; };// Probabilities are written and saved in histograms in addition to Getter
+
+ protected:
+ void CalculateProbabilities(int trunc_mode);
+ void CalculateProbabilitiesTot(TH2F* h2all, TH2F* h2tmp, TH2F*& h2prob);// total probability - probability based on particle multiplicites
+ void CalculateProbabilitiesLike(TH2F* h2tmp, TH2F*& h2prob); // likelihood - probability based on dEdx-distribution of particle
+
+ TString mcfile_name_{""};
+ TFile* inFile_;
+ TFile* outFile_;
+ TString getter_file_;
+ TString getter_name_;
+
+ // MC histograms
+
+ array probname_ = {"probT", "probL"};
+
+ array histnames_all_pos_, histnames_all_neg_;
+ array, NumberOfTrdLayers> histnames_pos_, histnames_neg_;
+ array, NumberOfTrdLayers> histnames_prob_pos_, histnames_prob_neg_;
+
+ TString histnames_hits_all_pos_, histnames_hits_all_neg_;
+ array histnames_hits_pos_, histnames_hits_neg_;
+
+ Int_t nbins_mom_;
+ Double_t bins_mom_[NbinsMax];
+ Int_t nbins_dEdx_;
+ Double_t bins_dEdx_[NbinsMax];
+
+ Bool_t write_mchistograms_out_{kFALSE};
+
+ PidTrd::GetterTrd getter_trd_{};
+};
+
+#endif//PIDTRD_RUNGETTER_HPP_
diff --git a/macro/RunGetter.C b/macro/RunGetter.C
deleted file mode 100644
index e697f63..0000000
--- a/macro/RunGetter.C
+++ /dev/null
@@ -1,74 +0,0 @@
-#ifndef __CLING__
-
-#include "Getter.h"
-#include
-#include
-#include
-#include
-#include