8#include "BmnGlobalTrack.h"
9#include "BmnMCInfoDst.h"
10#include "BmnTrackMatch.h"
11#include "CbmMCTrack.h"
13#include "FairLogger.h"
14#include "FairMCEventHeader.h"
15#include "FairRootManager.h"
16#include "FairTrackParam.h"
33#include "TVirtualMC.h"
111 LOG(error) <<
"Errors occurred while initializing the BmnParticleEqualizer1D generator, "
112 "the simulation run will be stopped";
117 vector<Int_t> pdg_codes,
132 for (
auto pdg_key : pdg_codes) {
134 LOG(warning) <<
"The PDG code " << pdg_key
135 <<
" is listed more than once for the equalizing generator, "
136 "the extra entries are ignored";
157 LOG(error) <<
"Errors occurred while initializing the BmnParticleEqualizer1D generator, "
158 "the simulation run will be stopped";
175 TF1* p_distribution =
176 new TF1(func_name,
"(x<[9])*(gaus(0)+gaus(3)+landau(6))+(x>=[9])*[10]*TMath::Exp(-[11]*(x-[9]))", p_min, p_max);
177 Double_t p_avg = (p_min + p_max) / 2;
189 Double_t margin = 0.01 * (max_value - min_value);
190 p_distribution->
SetParLimits(index, min_value, max_value);
197 set_parameter(0, 0., 10. * y_peak, 0.3 * y_peak);
198 set_parameter(1, p_min, p_avg, x_peak - 0.5 * rms);
199 set_parameter(2, 0.1, p_avg, 0.5 * rms);
200 set_parameter(3, 0., 10. * y_peak, 0.5 * y_peak);
201 set_parameter(4, x_max_value - 0.1, p_max, x_peak + 0.5 * rms);
202 set_parameter(5, 0.1, p_avg, rms);
203 set_parameter(6, 0., 100. * y_peak, 2. * y_peak);
204 set_parameter(7, p_min,
TMath::Min(x_max_value, p_avg), x_peak - 0.1);
205 set_parameter(8, 0.1, p_avg, 0.3 * rms);
210 const Double_t tail_fraction = 0.05, min_tail_entries = 30;
234 for (
Int_t index = 0; index <= 8; index++)
237 Double_t bulk_value = p_distribution->
Eval(p_tail * (1. - 1.e-12));
239 set_parameter(10, 0., 100. *
TMath::Max(bulk_value, 1.), bulk_value);
241 set_parameter(11, 0., 50., 2.);
242 p_distribution->
SetRange(p_tail, p_max);
243 is_valid = hP->
Fit(p_distribution,
"SQ0LR")->
IsValid() && is_valid;
246 p_distribution->
SetRange(p_min, p_max);
248 if (fitted_function !=
nullptr)
249 fitted_function->
SetRange(p_min, p_max);
257 if (hP->GetEntries() == 0) {
258 LOG(warning) <<
TString::Format(
"P (momentum) histogram is empty for PDG = %d", pdg_key);
264 LOG(error) <<
TString::Format(
"Fit of the P (momentum) histogram failed for PDG = %d", pdg_key);
279 if (hPt->GetEntries() == 0) {
280 LOG(warning) <<
TString::Format(
"Pt (transverse momentum) histogram is empty for PDG = %d", pdg_key);
288 TF1* pt_distribution =
new TF1(
289 dist_func_name,
TString::Format(
"[0]*x*exp(-sqrt(x*x+%.10g)/[1])", pdg_mass * pdg_mass), pt_min, pt_max);
297 "Fit of the Pt (transverse momentum) histogram failed for PDG = %d, the previous temperature value "
313 if (hY->GetEntries() == 0) {
314 LOG(warning) <<
TString::Format(
"Rapidity histogram is empty for %d PDG code", pdg_key);
319 if (pdg_key != 2212) {
325 Double_t max_bin_value = hY->GetMaximum();
339 unique_ptr<TF1> fProtonYDistribution =
340 make_unique<TF1>(
"distProtonY",
"gaus(0)+gaus(3)+gaus(6)", 0.2, 5);
341 fProtonYDistribution->SetParLimits(0, 0, max_bin_value);
342 fProtonYDistribution->SetParLimits(1, 0, 0.05);
343 fProtonYDistribution->SetParLimits(2, 0.01, 0.4);
344 fProtonYDistribution->SetParameter(2, 0.2);
345 fProtonYDistribution->SetParLimits(3, 0, max_bin_value);
346 fProtonYDistribution->SetParName(4,
"proton_y0");
347 fProtonYDistribution->SetParLimits(4, 0.3, 2);
348 fProtonYDistribution->SetParameter(4, 1);
349 fProtonYDistribution->SetParName(5,
"proton_sigma");
350 fProtonYDistribution->SetParLimits(5, 0.05, 1);
351 fProtonYDistribution->SetParameter(5, 0.5);
352 fProtonYDistribution->SetParLimits(6, 0, max_bin_value);
353 fProtonYDistribution->SetParLimits(7, 1.5, 3);
354 fProtonYDistribution->SetParameter(7, 2.25);
355 fProtonYDistribution->SetParLimits(8, 0.05, 1);
356 fProtonYDistribution->SetParameter(8, 0.5);
358 TFitResultPtr r = hY->Fit(fProtonYDistribution.get(),
"SQ0",
"", 0, 5);
371 if (hEta->GetEntries() == 0) {
372 LOG(warning) <<
TString::Format(
"Eta (pseudorapidity) histogram is empty for PDG = %d", pdg_key);
378 TF1* eta_distribution =
new TF1(dist_func_name,
"crystalball", eta_min, eta_max);
390 LOG(error) <<
TString::Format(
"Fit of the Eta (pseudorapidity) histogram failed for PDG = %d", pdg_key);
399 gSystem->ExpandPathName(input_list_file);
402 list<string> file_list;
403 ifstream list_file(input_list_file.
Data());
405 while (getline(list_file, s))
406 file_list.push_back(s);
407 if (file_list.empty()) {
408 cout <<
"ERROR: There are no files in the list of the input text file: " << input_list_file << endl;
413 TChain dataChain(
"bmndata");
414 for (
auto const& cur_file_path : file_list) {
415 TString strFilePath(cur_file_path);
416 gSystem->ExpandPathName(strFilePath);
418 dataChain.
AddFile(strFilePath);
422 cout <<
"ERROR: There are no correct input files in the text list stored at: \"" << input_list_file <<
"\""
431 if (dataChain.
GetBranch(
"MCTrack") ==
nullptr) {
432 LOG(info) <<
"'MCTrack' branch was not found, searching for 'BmnMCInfo->MCTrack'...";
433 if (dataChain.
GetBranch(
"BmnMCInfo.") ==
nullptr) {
434 LOG(error) <<
"'BmnMCInfo.' branch was not found too, please, check the structure of the files, exiting...";
438 if (mcInfo ==
nullptr) {
440 <<
"'BmnMCInfo.' branch was not read correctly, please, check the structure of the files, exiting...";
444 LOG(info) <<
"'BmnMCInfo->MCTrack' has been found";
449 if (mcTracks ==
nullptr) {
451 <<
"MCTrack' branch was not read correctly, please, check the structure of the files, exiting...";
459 if (iEventNumber < 1) {
460 cout <<
"ERROR: There are no correct entries in the file list stored at: \"" << input_list_file <<
"\"" << endl;
465 unique_ptr<TFile> hist_file(
TFile::Open(output_histo_file,
"RECREATE"));
466 if ((!hist_file) || (!hist_file->IsOpen())) {
467 cout <<
"ERROR: unable to create ROOT file for the sample histograms: " << output_histo_file << endl;
472 map<Int_t, unique_ptr<stParticleInfo>> particle_infos;
480 particle_infos[pdg_key]->fPHist = make_unique<TH1D>(histogram_name, histogram_name, 80,
fPMin,
fPMax);
482 particle_infos[pdg_key]->fPtHist = make_unique<TH1D>(histogram_name, histogram_name, 60,
fPtMin,
fPtMax);
484 particle_infos[pdg_key]->fYHist = make_unique<TH1D>(histogram_name, histogram_name, 60,
fYMin,
fYMax);
486 particle_infos[pdg_key]->fEtaHist = make_unique<TH1D>(histogram_name, histogram_name, 60,
fEtaMin,
fEtaMax);
488 particle_infos[pdg_key]->fThetaHist =
491 particle_infos[pdg_key]->fPhiHist = make_unique<TH1D>(histogram_name, histogram_name, 64,
fPhiMin,
fPhiMax);
495 particle_infos[pdg_key]->fPHist->SetDirectory(
nullptr);
496 particle_infos[pdg_key]->fPtHist->SetDirectory(
nullptr);
497 particle_infos[pdg_key]->fYHist->SetDirectory(
nullptr);
498 particle_infos[pdg_key]->fEtaHist->SetDirectory(
nullptr);
499 particle_infos[pdg_key]->fThetaHist->SetDirectory(
nullptr);
500 particle_infos[pdg_key]->fPhiHist->SetDirectory(
nullptr);
501 int hist_counter = 0;
502 for (
auto& p_hist : particle_infos[pdg_key]->fPHistVector) {
503 histogram_name =
TString::Format(
"hP%d_pdg%d", ++hist_counter, pdg_key);
504 p_hist = make_unique<TH1D>(histogram_name, histogram_name, 40,
fPMin + (hist_counter - 1) * interval_width,
505 fPMin + hist_counter * interval_width);
506 p_hist->SetDirectory(
nullptr);
509 for (
auto& eta_hist : particle_infos[pdg_key]->fEtaHistVector) {
510 histogram_name =
TString::Format(
"hEta%d_pdg%d", ++hist_counter, pdg_key);
511 eta_hist = make_unique<TH1D>(histogram_name, histogram_name, 60,
fEtaMin,
fEtaMax);
512 eta_hist->SetDirectory(
nullptr);
515 for (
auto& phi_hist : particle_infos[pdg_key]->fPhiHistVector) {
516 histogram_name =
TString::Format(
"hPhi%d_pdg%d", ++hist_counter, pdg_key);
518 phi_hist->SetDirectory(
nullptr);
523 int iCurrentEvent = 0;
524 LOG(info) <<
"Processing events...";
525 for (
Int_t iEvent = 0; iEvent < iEventNumber; iEvent++) {
528 if (iCurrentEvent % 1000 == 0)
529 LOG(info) <<
"Processing event #" << iCurrentEvent <<
" of " << iEventNumber;
536 mc_tracks = mcTracks;
558 if (
auto part_iter = particle_infos.find(part_code); part_iter != particle_infos.end()) {
559 int interval_number = (pTrack->
GetP() -
fPMin) / interval_width;
564 part_iter->second->fPHist->Fill(track_p);
565 part_iter->second->fPtHist->Fill(pTrack->
GetPt());
566 part_iter->second->fYHist->Fill(pTrack->
GetRapidity());
567 part_iter->second->fEtaHist->Fill(track_eta);
568 part_iter->second->fThetaHist->Fill(
TMath::ACos(pTrack->
GetPz() / track_p));
569 part_iter->second->fPhiHist->Fill(track_phi);
571 if ((track_p >=
fPMin) && (isless(track_p,
fPMax))) {
572 part_iter->second->fPHistVector[interval_number]->Fill(track_p);
573 part_iter->second->fEtaHistVector[interval_number]->Fill(track_eta);
574 part_iter->second->fPhiHistVector[interval_number]->Fill(track_phi);
582 if (particle_infos[pdg_key]->fPHist->GetEntries() == 0) {
583 LOG(error) <<
"Momentum histogram is empty for pdg=" << pdg_key;
586 if (particle_infos[pdg_key]->fPtHist->GetEntries() == 0) {
587 LOG(error) <<
"Transverse momentum histogram is empty for pdg=" << pdg_key;
590 if (particle_infos[pdg_key]->fYHist->GetEntries() == 0) {
591 LOG(error) <<
"Rapidity histogram is empty for pdg=" << pdg_key;
594 if (particle_infos[pdg_key]->fEtaHist->GetEntries() == 0) {
595 LOG(error) <<
"Pseudorapidity histogram is empty for pdg=" << pdg_key;
598 if (particle_infos[pdg_key]->fThetaHist->GetEntries() == 0) {
599 LOG(error) <<
"Theta angle histogram is empty for pdg=" << pdg_key;
602 if (particle_infos[pdg_key]->fPhiHist->GetEntries() == 0) {
603 LOG(error) <<
"Phi angle histogram is empty for pdg=" << pdg_key;
612 Double_t fY0 = 0, fSigma = 0.72, fT = 0.223;
616 LOG(fatal) <<
"PDG code " << pdg_key <<
"is not defined. exiting...";
630 if (
FitYHistogram(particle_infos[pdg_key]->fYHist, pdg_key, fY0, fSigma) != 0)
634 hist_file->WriteObject(&Y0SigmaT, vector_name);
640 LOG(info) <<
TString::Format(
"pdg=%i y0=%4.2f sigma_y=%4.2f T_pt=%6.4f", pdg_key, fY0, fSigma, fT);
647 momentum_grid[0] =
fPMin;
648 momentum_grid[1] =
fPMax;
654 hist_file->WriteTObject(particle_infos[pdg_key]->fPHist.get());
655 hist_file->WriteTObject(particle_infos[pdg_key]->fPtHist.get());
656 hist_file->WriteTObject(particle_infos[pdg_key]->fYHist.get());
657 hist_file->WriteTObject(particle_infos[pdg_key]->fEtaHist.get());
658 hist_file->WriteTObject(particle_infos[pdg_key]->fThetaHist.get());
659 hist_file->WriteTObject(particle_infos[pdg_key]->fPhiHist.get());
660 for (
auto& p_hist : particle_infos[pdg_key]->fPHistVector)
661 hist_file->WriteTObject(p_hist.get());
662 for (
auto& eta_hist : particle_infos[pdg_key]->fEtaHistVector)
663 hist_file->WriteTObject(eta_hist.get());
664 for (
auto& phi_hist : particle_infos[pdg_key]->fPhiHistVector)
665 hist_file->WriteTObject(phi_hist.get());
678 LOG(error) <<
"The efficiency map is absent in the file with the sample histograms for at least one of the "
679 "particle types, so the correction by the efficiency cannot be switched on. Build the map with "
680 "BmnParticleEqualizer1D::ProduceEfficiencyMap() from the reconstructed (DST) files first";
683 if (min_efficiency <= 0.) {
684 LOG(error) <<
"The lower limit of the efficiency has to be positive, otherwise the correction factor is "
685 "unlimited; the correction is not switched on";
697 if ((hist_file ==
nullptr) || (!hist_file->
IsOpen())) {
698 LOG(error) <<
"The file with the sample histograms is not open";
703 if ((momentum_grid ==
nullptr) || (momentum_grid->GetNoElements() !=
kMomentumGridSize)) {
705 <<
"') is absent in the file with the sample histograms: " << hist_file->
GetName()
706 <<
". The file was produced by an older version of the equalizing generator, please, recreate it "
707 "with ProduceSampleHistograms()";
716 "The sample histograms were produced for %d momentum intervals in [%g, %g] GeV, but the generator is "
717 "configured for %d intervals in [%g, %g] GeV. Please, recreate the file '%s' with "
718 "ProduceSampleHistograms() or configure the generator accordingly",
730 gSystem->ExpandPathName(input_list_file);
733 list<string> file_list;
734 ifstream list_file(input_list_file.
Data());
736 while (getline(list_file, s))
737 file_list.push_back(s);
738 if (file_list.empty()) {
739 LOG(error) <<
"There are no files in the list of the input text file: " << input_list_file;
744 TChain dataChain(
"bmndata");
745 for (
auto const& cur_file_path : file_list) {
746 TString strFilePath(cur_file_path);
747 gSystem->ExpandPathName(strFilePath);
748 dataChain.
AddFile(strFilePath);
751 LOG(error) <<
"There are no correct input files in the text list stored at: " << input_list_file;
757 unique_ptr<TFile> hist_file(
TFile::Open(histo_file,
"UPDATE"));
758 if ((!hist_file) || (!hist_file->IsOpen())) {
759 LOG(error) <<
"Unable to open the file with the sample histograms for updating: " << histo_file;
768 if (dataChain.
GetBranch(
"BmnGlobalTrack") ==
nullptr) {
769 LOG(error) <<
"'BmnGlobalTrack' branch was not found: the efficiency map is built from the reconstructed "
770 "(DST) files, please, check the structure of the given files";
782 Bool_t isMatched = isMC && (dataChain.
GetBranch(
"BmnGlobalTrackMatch") !=
nullptr);
785 LOG(info) <<
"Building the efficiency map from the " << (isMC ?
"simulated" :
"experimental") <<
" DST files";
786 if (isMC && (!isMatched))
787 LOG(warning) <<
"'BmnGlobalTrackMatch' branch was not found, the particle types of the reconstructed tracks "
788 "without an MC index are defined by the mass measured by the ToF detectors";
791 map<Int_t, vector<Double_t>> reconstructed_count;
797 for (
int iEvent = 0; iEvent < iEventNumber; iEvent++) {
798 if ((iEvent + 1) % 1000 == 0)
799 LOG(info) <<
"Processing event #" << iEvent + 1 <<
" of " << iEventNumber;
801 if (globalTracks ==
nullptr)
805 for (
int iTrack = 0; iTrack < globalTracks->
GetEntries(); iTrack++) {
807 if (global_track ==
nullptr)
822 if (reconstructed_count.find(track_pdg) == reconstructed_count.end())
826 if (parFirst ==
nullptr)
828 Double_t track_qp = parFirst->GetQp();
834 int interval_number = (track_p -
fPMin) / interval_width;
838 reconstructed_count[track_pdg][interval_number] += 1.;
845 for (
int cur_interval = 0; cur_interval <
fIntervalCount; cur_interval++) {
847 unique_ptr<TH1D> p_hist((
TH1D*)hist_file->Get(histogram_name));
848 if (p_hist ==
nullptr) {
849 LOG(error) <<
"The momentum histogram '" << histogram_name
850 <<
"' does not exist in the file with the sample histograms: " << histo_file;
853 p_hist->SetDirectory(
nullptr);
854 Double_t sample_count = p_hist->GetEntries();
855 efficiency[cur_interval] =
856 (sample_count > 0) ? (reconstructed_count[pdg_key][cur_interval] / sample_count) : 0.;
857 max_efficiency =
TMath::Max(max_efficiency, efficiency[cur_interval]);
860 if (max_efficiency <= 0.) {
861 LOG(error) <<
"No track of pdg=" << pdg_key <<
" was reconstructed in the given files, "
862 <<
"the efficiency map cannot be built";
867 efficiency *= 1. / max_efficiency;
872 for (
int cur_interval = 0; cur_interval <
fIntervalCount; cur_interval++)
873 efficiency_values +=
TString::Format(
" %4.2f", efficiency[cur_interval]);
874 LOG(info) <<
"Relative efficiency for pdg=" << pdg_key <<
":" << efficiency_values;
887 if ((hist_file ==
nullptr) || (hist_file->
IsZombie())) {
888 LOG(error) <<
"The file with the sample histograms was not opened: " << input_histo_file;
904 LOG(error) <<
"Momentum histogram does not exist for pdg=" << pdg_key;
911 LOG(error) <<
"Momentum histogram is empty for pdg=" << pdg_key;
917 LOG(info) <<
"The fitted momentum function is absent for pdg=" << pdg_key <<
", fitting it now";
923 LOG(error) <<
"Transverse momentum histogram does not exist for pdg=" << pdg_key;
928 LOG(error) <<
"Transverse momentum histogram is empty for pdg=" << pdg_key;
934 LOG(error) <<
"Rapidity histogram does not exist for pdg=" << pdg_key;
939 LOG(error) <<
"Rapidity histogram is empty for pdg=" << pdg_key;
945 LOG(error) <<
"Pseudorapidity histogram does not exist for pdg=" << pdg_key;
950 LOG(error) <<
"Pseudorapidity histogram is empty for pdg=" << pdg_key;
956 LOG(error) <<
"Theta angle histogram does not exist for pdg=" << pdg_key;
961 LOG(error) <<
"Theta angle histogram is empty for pdg=" << pdg_key;
967 LOG(error) <<
"Phi angle histogram does not exist for pdg=" << pdg_key;
972 LOG(error) <<
"Phi angle histogram is empty for pdg=" << pdg_key;
975 int hist_counter = 0;
977 histogram_name =
TString::Format(
"hP%d_pdg%d", ++hist_counter, pdg_key);
978 p_hist = unique_ptr<TH1D>((
TH1D*)hist_file->
Get(histogram_name));
979 if (p_hist.get() ==
nullptr) {
980 LOG(error) <<
"Momentum histogram does not exist for pdg=" << pdg_key
981 <<
" in interval=" << hist_counter;
984 p_hist->SetDirectory(
nullptr);
988 histogram_name =
TString::Format(
"hEta%d_pdg%d", ++hist_counter, pdg_key);
989 eta_hist = unique_ptr<TH1D>((
TH1D*)hist_file->
Get(histogram_name));
990 if (eta_hist.get() ==
nullptr) {
991 LOG(error) <<
"Pseudorapidity histogram does not exist for pdg=" << pdg_key
992 <<
" in interval=" << hist_counter;
995 eta_hist->SetDirectory(
nullptr);
999 histogram_name =
TString::Format(
"hPhi%d_pdg%d", ++hist_counter, pdg_key);
1000 phi_hist = unique_ptr<TH1D>((
TH1D*)hist_file->
Get(histogram_name));
1001 if (phi_hist.get() ==
nullptr) {
1002 LOG(error) <<
"Phi angle histogram does not exist for pdg=" << pdg_key
1003 <<
" in interval=" << hist_counter
1004 <<
". The file with the sample histograms was produced by an older version of the "
1005 "equalizing generator, please, recreate it with ProduceSampleHistograms()";
1008 phi_hist->SetDirectory(
nullptr);
1021 if (p_dist_func !=
nullptr) {
1035 if (
fParticleInfos[pdg_key]->fPHistVector[cur_interval]->GetEntries() > 2)
1039 else if ((p_dist_func !=
nullptr)
1045 "There is neither sample statistics nor a significant fitted momentum function for pdg=%d in the "
1046 "momentum interval [%4.2f, %4.2f] GeV: no particles will be added there",
1052 LOG(error) <<
"PDG code " << pdg_key <<
" is not defined in the PDG database";
1060 unique_ptr<TVector3> y0_sigma_t((
TVector3*)hist_file->
Get(vector_name));
1061 if (y0_sigma_t ==
nullptr) {
1062 LOG(error) <<
"The fitted distribution parameters ('" << vector_name
1063 <<
"') do not exist in the file with the sample histograms. It was produced by an older "
1064 "version of the equalizing generator, please, recreate it with ProduceSampleHistograms()";
1076 unique_ptr<TVectorD> efficiency(
1078 if ((efficiency !=
nullptr) && (efficiency->GetNoElements() ==
fIntervalCount)) {
1079 for (
int cur_interval = 0; cur_interval <
fIntervalCount; cur_interval++)
1080 fParticleInfos[pdg_key]->fEfficiency[cur_interval] = (*efficiency)[cur_interval];
1082 if (efficiency !=
nullptr)
1083 LOG(error) <<
"The efficiency map of pdg=" << pdg_key <<
" has " << efficiency->GetNoElements()
1084 <<
" elements instead of " <<
fIntervalCount <<
" momentum intervals, it is ignored";
1085 is_efficiency_map_read =
kFALSE;
1106 TObjArray* generator_list = primGen->GetListOfGenerators();
1107 if ((generator_list ==
nullptr) || (generator_list->
Last() !=
this)) {
1108 LOG(error) <<
"The BmnParticleEqualizer1D generator is not the last one registered in FairPrimaryGenerator: "
1109 "it has to be added by AddGenerator() after all the other generators of the event";
1114 CbmStack* stack = (gMC ==
nullptr) ?
nullptr :
dynamic_cast<CbmStack*
>(gMC->GetStack());
1115 if (stack ==
nullptr) {
1116 LOG(error) <<
"The BmnParticleEqualizer1D generator requires the particle stack of the simulation (CbmStack) "
1117 "to count the particles of the event, but it is not available";
1124 fill(part_iter->second->fParticleNumber.begin(), part_iter->second->fParticleNumber.end(), 0);
1136 if ((part ==
nullptr) || (!part->
IsPrimary()))
1151 if ((interval_number < 0) || (interval_number >=
fIntervalCount))
1155 LOG(debug) <<
TString::Format(
"Found particle: PDG=%i P=%4.2f Eta=%4.2f", part_code, part_p, part_eta);
1172 part_iter->second->fParticleNumber[interval_number] += 1;
1174 if (part_iter->second->fParticleNumber[interval_number] >
fMaxParticles[interval_number])
1175 fMaxParticles[interval_number] = part_iter->second->fParticleNumber[interval_number];
1194 TVector3 beam_x(1., 0., 0.), beam_y(0., 1., 0.), beam_z(0., 0., 1.);
1195 if ((event_header !=
nullptr) && ((event_header->GetRotX() != 0.) || (event_header->GetRotY() != 0.))) {
1197 beam_direction = beam_direction.
Unit();
1199 beam_y.RotateUz(beam_direction);
1205 LOG(debug) <<
TString::Format(
"Current particle type to be equalized: pdg=%i y0=%4.2f sigma_y=%4.2f T_pt=%6.4f",
1215 LOG(debug) <<
"Adding paticle to equalize the numbers...";
1239 particle_debt += particle_number;
1243 if (add_particle < 0)
1245 particle_debt -= add_particle;
1252 <<
" " << add_particle <<
" particle with PDG = " << pdg_key <<
" (" << cur_p <<
" GeV)";
1257 if ((eta_interval < 0) || (phi_interval < 0)) {
1258 LOG(warning) <<
"There is no sample statistics of the pseudorapidity or of the azimuth angle for pdg="
1259 << pdg_key <<
" in any momentum interval, no particles are added";
1262 for (
Int_t k = 0; k < add_particle; k++) {
1267 ?
fParticleInfos[pdg_key]->fPHistVector[cur_interval]->GetRandom()
1281 LOG(warning) <<
"An incorrect momentum (" << p <<
") or pseudorapidity (" << eta
1282 <<
") was sampled for pdg=" << pdg_key <<
", the particle is skipped";
1289 mom.
SetXYZ(mom * beam_x, mom * beam_y, mom * beam_z);
1291 LOG(debug) <<
"Particle generated: pdg=" << pdg_key <<
" p=" << p <<
" eta=" << eta;
1296 primGen->AddTrack(pdg_key, mom.
X(), mom.
Y(), mom.
Z(), 0., 0., 0.);
1303 if (added_particle !=
nullptr)
1315 vector<Int_t>& index_vector)
1317 const Int_t interval_count = (
Int_t)hist_vector.size();
1318 index_vector.assign(interval_count, -1);
1320 for (
Int_t cur_interval = 0; cur_interval < interval_count; cur_interval++) {
1323 for (
Int_t shift = 0; shift < interval_count; shift++) {
1324 const Int_t lower_interval = cur_interval - shift, upper_interval = cur_interval + shift;
1325 if ((lower_interval >= 0) && (hist_vector[lower_interval] !=
nullptr)
1326 && (hist_vector[lower_interval]->GetEntries() > 2))
1328 index_vector[cur_interval] = lower_interval;
1331 if ((upper_interval < interval_count) && (hist_vector[upper_interval] !=
nullptr)
1332 && (hist_vector[upper_interval]->GetEntries() > 2))
1334 index_vector[cur_interval] = upper_interval;
1345 if ((!f) || (!f->IsOpen())) {
1346 cout <<
"ERROR: unable to open ROOT file: " << input_histo_file << endl;
1351 TString::Format(
"Distributions for particle PDG = %d", particle_number), 1000,
1354 if (h1 ==
nullptr) {
1355 cout <<
"ERROR: the momentum histogram is absent for PDG = " << particle_number << endl;
1362 cout <<
"avg_value = " << p_avg << endl;
1363 cout <<
"x_max_value = " << x_max_value << endl;
1364 cout <<
"y_max_value = " << y_max_value << endl;
1369 if (p_distribution !=
nullptr)
1380 if ((!f) || (!f->IsOpen())) {
1381 cout <<
"ERROR: unable to open ROOT file: " << input_histo_file << endl;
1387 TString::Format(
"Distributions for particle PDG = %d", particle_number), 1000,
1390 if (h1 ==
nullptr) {
1391 cout <<
"ERROR: the momentum histogram is absent for PDG = " << particle_number << endl;
1395 if (f1 ==
nullptr) {
1396 cout <<
"ERROR: the fitted momentum function is absent for PDG = " << particle_number << endl;
1414 cout <<
"ERROR: Could not get TDatabasePDG instance" << endl;
1421 if (vecParticlePDG.empty()) {
1424 if (
TMath::Abs(particle->Mass() - mass) < (tolerance > 0 ? tolerance * mass : -1 * tolerance))
1425 return particle->PdgCode();
1428 for (
int particle_number : vecParticlePDG) {
1430 if (particle ==
nullptr)
1432 if (
TMath::Abs(particle->
Mass() - mass) < (tolerance > 0 ? tolerance * mass : -1 * tolerance))
1447 if (global_track ==
nullptr)
1453 if (mc_tracks !=
nullptr) {
1455 if ((mc_index < 0) && (global_match !=
nullptr) && (global_match->
GetNofLinks() > 0))
1457 if (mc_index > -1) {
1461 return (mc_track ==
nullptr) ? 0 : mc_track->
GetPdgCode();
1464 if (global_match !=
nullptr)
1471 if (mass_tof2 == -1000.0)
1472 mass_tof2 = global_track->
GetMass2(2);
1474 if ((mass_tof2 == -1000.0) || (mass_tof2 < 0))
1477 if ((par_first ==
nullptr) || (par_first->GetQp() == 0))
1483 vector<Int_t> candidates;
1486 if ((particle !=
nullptr) && (particle->
Charge() * par_first->GetQp() > 0))
1487 candidates.push_back(pdg_code);
1489 if (candidates.empty())
1501 gSystem->ExpandPathName(input_list_file);
1504 list<string> file_list;
1505 ifstream list_file(input_list_file.
Data());
1507 while (getline(list_file, s))
1508 file_list.push_back(s);
1509 if (file_list.empty()) {
1510 cout <<
"ERROR: There are no files in the list of the input text file: " << input_list_file << endl;
1515 TChain dataChain(
"bmndata");
1516 for (
auto const& cur_file_path : file_list) {
1517 TString strFilePath(cur_file_path);
1518 gSystem->ExpandPathName(strFilePath);
1520 dataChain.
Add(strFilePath);
1525 TClonesArray *mcTracks =
nullptr, *globalTracks =
nullptr, *globalMatches =
nullptr;
1527 if (dataChain.
GetBranch(
"MCTrack") ==
nullptr) {
1528 if (dataChain.
GetBranch(
"BmnMCInfo.") ==
nullptr) {
1529 LOG(error) <<
"'MCTrack' and 'BmnMCInfo.' branches were not found, please, check the structure of the "
1530 "files, exiting...";
1534 if (mcInfo ==
nullptr) {
1536 <<
"'BmnMCInfo.' branch was not read correctly, please, check the structure of the files, exiting...";
1540 if (globalTracks ==
nullptr) {
1541 LOG(error) <<
"'BmnGlobalTrack' branch was not read correctly, please, check the structure of the files, "
1547 if (dataChain.
GetBranch(
"BmnGlobalTrackMatch") !=
nullptr)
1550 LOG(warning) <<
"'BmnGlobalTrackMatch' branch was not found, the particle types of the reconstructed "
1551 "tracks without an MC index are defined by the mass measured by the ToF detectors";
1558 if (mcTracks ==
nullptr) {
1560 <<
"MCTrack' branch was not read correctly, please, check the structure of the files, exiting...";
1569 new TCanvas(
"c_number",
"Multiplicity of different particle types for all the momentum intervals", 1000, 500);
1574 map<int, TH1I*> mapParticleNumberHists;
1576 TH1I* hParticleNumber =
1618 mapParticleNumberHists[particle_number] = hParticleNumber;
1623 map<int, TH1D*> mapPHists, mapPtHists, mapYHists, mapEtaHists, mapThetaHists, mapPhiHists;
1627 mapPHists[particle_number] = hP;
1630 mapPtHists[particle_number] = hPt;
1633 mapYHists[particle_number] = hY;
1636 mapEtaHists[particle_number] = hEta;
1639 mapThetaHists[particle_number] = hTheta;
1642 mapPhiHists[particle_number] = hPhi;
1645 int iEventNumber = dataChain.
GetEntries(), iCurrentEvent = 0;
1646 if (iEventNumber < 1) {
1647 cout <<
"ERROR: There are no correct entries in the file list stored at: \"" << input_list_file <<
"\"" << endl;
1652 for (iCurrentEvent = 0; iCurrentEvent < iEventNumber; iCurrentEvent++) {
1654 if ((iCurrentEvent + 1) % 1000 == 0)
1655 LOG(info) <<
"Processing event #" << iCurrentEvent + 1 <<
" of " << iEventNumber;
1658 Int_t track_count = 0;
1662 track_count = globalTracks->GetEntries();
1664 mc_tracks = mcTracks;
1669 for (
Int_t iTrack = 0; iTrack < track_count; iTrack++) {
1670 Int_t track_pdg = -1;
1672 Double_t track_p = 0, track_pt = 0, track_y = 0, track_eta = 0, track_theta = 0, track_phi = 0;
1678 global_track = (
BmnGlobalTrack*)globalTracks->UncheckedAt(iTrack);
1687 BmnTrackMatch* global_match = ((globalMatches !=
nullptr) && (iTrack < globalMatches->GetEntriesFast()))
1696 track_mass = tof_mass;
1699 if (particle ==
nullptr)
1701 track_mass = particle->
Mass();
1707 if (parFirst ==
nullptr)
1709 Double_t track_qp = parFirst->GetQp();
1712 parFirst->Momentum(vecMom);
1713 track_pt =
TMath::Sqrt(vecMom.
x() * vecMom.
x() + vecMom.
y() * vecMom.
y());
1715 track_y = 0.5 *
TMath::Log((e + vecMom.
z()) / (e - vecMom.
z()));
1716 track_eta = 0.5 *
TMath::Log((track_p + vecMom.
z()) / (track_p - vecMom.
z()));
1717 Double_t track_tx = parFirst->GetTx(), track_ty = parFirst->GetTy();
1726 if (mc_track ==
nullptr)
1746 track_p = mc_track->
GetP();
1747 track_pt = mc_track->
GetPt();
1758 if ((track_p >=
fPMin) && (track_p <
fPMax)) {
1759 mapParticleNumberHists[*iter_pdg]->Fill(track_p);
1760 mapPHists[*iter_pdg]->Fill(track_p);
1761 mapPtHists[*iter_pdg]->Fill(track_pt);
1762 mapYHists[*iter_pdg]->Fill(track_y);
1763 mapEtaHists[*iter_pdg]->Fill(track_eta);
1764 mapThetaHists[*iter_pdg]->Fill(track_theta);
1765 mapPhiHists[*iter_pdg]->Fill(track_phi);
1771 if (iCurrentEvent == 0) {
1772 cout <<
"ERROR: There are no necessary tree branches or DST events in the files from the list: "
1773 << input_list_file << endl;
1774 for (
const auto& pair : mapPHists)
1776 for (
const auto& pair : mapPtHists)
1778 for (
const auto& pair : mapYHists)
1780 for (
const auto& pair : mapEtaHists)
1782 for (
const auto& pair : mapThetaHists)
1784 for (
const auto& pair : mapPhiHists)
1792 for (
const auto& pair_hist : mapParticleNumberHists) {
1793 if (max_y_value < pair_hist.second->GetMaximum())
1794 max_y_value = pair_hist.second->GetMaximum();
1799 TString hist_options =
"bar2,hist,text";
1801 for (
const auto& pair_hist : mapParticleNumberHists) {
1802 if (cur_hist == 0) {
1803 if (pair_hist.second->GetMaximum() < max_y_value)
1804 pair_hist.second->SetMaximum(max_y_value + 10);
1805 pair_hist.second->DrawCopy(hist_options);
1807 pair_hist.second->DrawCopy(hist_options +
",same");
1816 TCanvas* c_p =
new TCanvas(
"c_p",
"Particle Momentum", 1000, 500);
1821 mapPHists[particle_number]->
Draw();
1824 TCanvas* c_pt =
new TCanvas(
"c_pt",
"Transverse Momentum", 1000, 500);
1829 mapPtHists[particle_number]->
Draw();
1837 mapYHists[particle_number]->
Draw();
1840 TCanvas* c_eta =
new TCanvas(
"c_eta",
"Pseudorapidity", 1000, 500);
1844 c_eta->
cd(cur_hist);
1845 mapEtaHists[particle_number]->
Draw();
1848 TCanvas* c_theta =
new TCanvas(
"c_theta",
"Theta angle", 1000, 500);
1852 c_theta->
cd(cur_hist);
1853 mapThetaHists[particle_number]->
Draw();
1860 c_phi->
cd(cur_hist);
1861 mapPhiHists[particle_number]->
Draw();
static Bool_t FitMomentumFunction(TH1D *hP, const TString &func_name, Double_t p_min, Double_t p_max)
static const int kIntervalPhiBinCount
Cut applied to the tracks of the sample (see SetSampleTrackCut).
static const char * kEfficiencyNamePrefix
static Double_t fThetaMax
static const char * kMomentumGridName
static const int kMomentumGridSize
static Double_t fThetaMin
R__EXTERN TSystem * gSystem
TVectorT< Double_t > TVectorD
Int_t GetTof2HitIndex() const
Int_t GetTof1HitIndex() const
Float_t GetMass2(Int_t tofID) const
TClonesArray * GetMCTracks() const
rot. around z-axis [rad]
const BmnLink & GetMatchedLink() const
Int_t GetNofLinks() const
static int FitPHistogram(unique_ptr< TH1D > &hP, int pdg_key, Double_t p_min, Double_t p_max)
static int ProduceEfficiencyMap(TString input_list_file, TString histo_file="$VMCWORKDIR/macro/recotools/particle_hists.root")
Bool_t fUseSampleStatisticsCut
Whether the efficiency map has been found in the sample histogram file.
static Int_t GetPDGCodeByMass(Double_t mass, Double_t tolerance=1.e-6, const vector< int > &vecParticlePDG={})
static Int_t fSampleTrackCut
Cut applied to the tracks of the sample (see SetSampleTrackCut).
static int FitYHistogram(unique_ptr< TH1D > &hY, int pdg_key, Double_t &y0_output, Double_t &sigma_putput)
vector< int > fMaxParticles
Double_t fMinEfficiency
Whether the added particle number is corrected by the efficiency.
static int ShowSampleHistograms(TString input_histo_file="$VMCWORKDIR/macro/recotools/particle_hists.root")
static Int_t GetGlobalTrackPDG(BmnGlobalTrack *global_track, BmnTrackMatch *global_match, TClonesArray *mc_tracks, Double_t &tof_mass)
static int ShowResultDistributions(TString input_list_file)
static Double_t fPMin
Min value of momentum.
Bool_t fUseEfficiencyCorrection
Target particle number per interval, 0 = maximum of the event (see the setter).
static Bool_t CheckMomentumGrid(TFile *hist_file)
Bool_t fIsEfficiencyMapRead
Lower limit of the efficiency used for the correction.
static void FitSampleHistograms(TString input_histo_file="$VMCWORKDIR/macro/recotools/particle_hists.root")
additional functions to check results of fitting and particle equalizing
static void DefineNearestFilledIntervals(const vector< unique_ptr< TH1D > > &hist_vector, vector< Int_t > &index_vector)
Double_t fTargetPerInterval
static int ProduceSampleHistograms(TString input_list_file, TString output_histo_file="$VMCWORKDIR/macro/recotools/particle_hists.root")
Bool_t ReadSampleHistograms(TString input_histo_file="$VMCWORKDIR/macro/recotools/particle_hists.root")
Bool_t SetEfficiencyCorrection(Bool_t is_used, Double_t min_efficiency=0.05)
Switch on the correction of the number of the added particles by the reconstruction efficiency (off b...
static int FitEtaHistogram(unique_ptr< TH1D > &hEta, int pdg_key, Double_t eta_min, Double_t eta_max)
static Int_t fIntervalCount
Interval count for momentum to equalize particles at all the intervals.
static Double_t fPMax
Max value of momentum.
static vector< Int_t > fParticles
Bool_t isActive
Interval step.
map< Int_t, unique_ptr< stParticleInfo > > fParticleInfos
Bool_t Init()
Initializer.
static int FitPtHistogram(unique_ptr< TH1D > &hPt, int pdg_key, Double_t pdg_mass, Double_t pt_min, Double_t pt_max, Double_t &t_output)
BmnParticleEqualizer1D(TString hist_file_name)
Constructor with input histograms.
virtual Bool_t ReadEvent(FairPrimaryGenerator *primGen)
Creates an event with equal number of particles at all momentum intervals.
FairTrackParam * GetParamFirst()
Long64_t GetNPoints(DetectorId detId) const
Accessors to the number of MCPoints in the detectors.
Double_t GetRapidity() const
Int_t GetMotherId() const
Int_t GetPdgCode() const
Accessors.
TClonesArray * GetListOfParticles()
int Index(const std::string &name) const
double Parameter(unsigned int i) const
static void SetDefaultMinimizer(const char *type, const char *algo=nullptr)
static const std::string & DefaultMinimizerType()
virtual void SetLabelSize(Float_t size=0.04)
virtual void SetTitleSize(Float_t size=0.04)
virtual void SetNdivisions(Int_t n1, Int_t n2, Int_t n3, Bool_t optim=kTRUE)
virtual void SetFillColor(Color_t fcolor)
virtual void SetMarkerSize(Size_t msize=1)
virtual Double_t GetBinCenter(Int_t bin) const
virtual Double_t GetBinLowEdge(Int_t bin) const
void CenterTitle(Bool_t center=kTRUE)
virtual Double_t GetBinUpEdge(Int_t bin) const
TVirtualPad * cd(Int_t subpadnumber=0) override
Int_t SetBranchAddress(const char *bname, T **add, TBranch **ptr=nullptr)
virtual Int_t AddFile(const char *name, Long64_t nentries=TTree::kMaxEntries, const char *tname="")
TBranch * GetBranch(const char *name) override
virtual Int_t Add(const char *name, Long64_t nentries=TTree::kMaxEntries)
void SetBranchStatus(const char *bname, bool status=true, UInt_t *found=nullptr) override
Long64_t GetEntries() const override
Int_t GetEntry(Long64_t entry=0, Int_t getall=0) override
static TDatabasePDG * Instance()
const THashList * ParticleList() const
TParticlePDG * GetParticle(const char *name) const
T * Get(const char *namecycle)
virtual void ReleaseParameter(Int_t ipar)
virtual Double_t GetParameter(const TString &name) const
virtual void SetRange(Double_t xmin, Double_t xmax)
virtual void SetNpx(Int_t npx=100)
void Draw(Option_t *option="") override
virtual void SetParLimits(Int_t ipar, Double_t parmin, Double_t parmax)
virtual Double_t GetRandom(Double_t xmin, Double_t xmax, TRandom *rng=nullptr, Option_t *opt=nullptr)
virtual Double_t Eval(Double_t x, Double_t y=0, Double_t z=0, Double_t t=0) const
virtual Double_t GetMaximum(Double_t xmin=0, Double_t xmax=0, Double_t epsilon=1.E-10, Int_t maxiter=100, Bool_t logx=false) const
virtual void SetParameter(const TString &name, Double_t value)
virtual void FixParameter(Int_t ipar, Double_t value)
virtual Int_t GetNpx() const
virtual Bool_t IsOpen() const
static TFile * Open(const char *name, Option_t *option="", const char *ftitle="", Int_t compress=ROOT::RCompressionSetting::EDefaults::kUseCompiledDefault, Int_t netopt=0)
void Close(Option_t *option="") override
virtual void SetLabelFont(Style_t font=62, Option_t *axis="X")
virtual void SetBarOffset(Float_t offset=0.25)
void SetTitle(const char *title) override
virtual TFitResultPtr Fit(const char *formula, Option_t *option="", Option_t *goption="", Double_t xmin=0, Double_t xmax=0)
virtual Int_t GetNbinsX() const
void Draw(Option_t *option="") override
Double_t GetRMS(Int_t axis=1) const
virtual TF1 * GetFunction(const char *name) const
virtual Double_t Integral(Int_t binx1, Int_t binx2, Option_t *option="") const
virtual Int_t GetMaximumBin() const
virtual Double_t GetBinContent(Int_t bin) const
virtual Double_t GetBinWidth(Int_t bin) const
virtual Int_t FindBin(Double_t x, Double_t y=0, Double_t z=0)
virtual void LabelsDeflate(Option_t *axis="X")
virtual void SetBarWidth(Float_t width=0.5)
virtual void SetStats(Bool_t stats=kTRUE)
void Draw(Option_t *option="") override
TLegendEntry * AddEntry(const char *name, const char *label="", Option_t *option="lpf")
virtual void SetTitle(const char *title="")
const char * GetName() const override
Int_t GetEntriesFast() const
TObject * Last() const override
Int_t GetEntries() const override
TObject * At(Int_t idx) const override
TObject * UncheckedAt(Int_t i) const
R__ALWAYS_INLINE Bool_t IsZombie() const
void Divide(Int_t nx=1, Int_t ny=1, Float_t xmargin=0.01, Float_t ymargin=0.01, Int_t color=0) override
const char * Data() const
static TString Format(const char *fmt,...)
void SetXYZ(Double_t x, Double_t y, Double_t z)
void RotateUz(const TVector3 &)
void Draw(Option_t *option="") override=0
Double_t Min(Double_t a, Double_t b)
Double_t Floor(Double_t x)
Double_t ATan2(Double_t y, Double_t x)
Double_t Sqrt(Double_t x)
Bool_t AreEqualAbs(Double_t af, Double_t bf, Double_t epsilon)
Double_t Max(Double_t a, Double_t b)
Double_t Range(Double_t lb, Double_t ub, Double_t x)
vector< Double_t > fEfficiency
Relative reconstruction efficiency of the particle type, 1 for all the intervals if the efficiency ma...
Double_t fY0
Mean rapidity.
vector< EPSampling > fPSampling
Momentum sampling way for the particle type (divided by momentum intervals -> vector).
vector< Double_t > fParticleDebt
Part of the target number of the particles that has not been added yet, kept between the events so th...
stParticleInfo(int pdg_key, Double_t min_p, Double_t max_p, Int_t interval_count)
vector< unique_ptr< TH1D > > fEtaHistVector
Eta histograms for the particle type (divided by momentum intervals -> vector).
Double_t fT
Temperature in the P distribution.
vector< Int_t > fParticleNumber
PDG -> Particle Count (divided by momentum intervals -> vector).
Double_t fSigma
Sigma in the rapidity distribution.
vector< Int_t > fEtaHistIndex
Index of the momentum interval whose Eta histogram is used to sample the pseudorapidity for a given i...
@ kNone
the interval cannot be sampled at all, new particles are not added there
@ kIntervalHist
from the P histogram of the interval itself (there is enough sample statistics)
@ kFitFunction
from the fitted function of the full P histogram (too little sample statistics)
vector< unique_ptr< TH1D > > fPHistVector
P histograms for the particle type (divided by momentum intervals -> vector).
vector< Int_t > fPhiHistIndex
The same for the azimuth angle: index of the momentum interval whose Phi histogram is used.
vector< unique_ptr< TH1D > > fPhiHistVector
Phi histograms for the particle type (divided by momentum intervals -> vector).