BmnRoot
Loading...
Searching...
No Matches
BmnParticleEqualizer.cxx
Go to the documentation of this file.
1// -------------------------------------------------------------------------
2// ----- BmnParticleEqualizer source file -----
3// ----- Created 01/05/2024 by K. Gertsenberger -----
4// -------------------------------------------------------------------------
5
7
8#include "BmnGlobalTrack.h"
9#include "BmnMCInfoDst.h"
10#include "CbmMCTrack.h"
11#include "CbmStack.h"
12#include "FairLogger.h"
13#include "FairMCEventHeader.h"
14#include "FairRootManager.h"
15#include "FairTrackParam.h"
16#include "Math/MinimizerOptions.h"
17#include "TCanvas.h"
18#include "TChain.h"
19#include "TClonesArray.h"
20#include "TDatabasePDG.h"
21#include "TFile.h"
22#include "TFitResult.h"
23#include "THashList.h"
24#include "TLegend.h"
25#include "TMath.h"
26#include "TParticlePDG.h"
27#include "TRandom.h"
28#include "TSystem.h"
29#include "TTreeReader.h"
30#include "TTreeReaderValue.h"
31#include "TVirtualMC.h"
32
33// iParticleCut: 0 - all primary particles,
34// 1 - exclude tracks without points in Silicon and GEMs,
35// 2 - exclude tracks without points in Silicon, GEM and ToF detectors
36static const int iParticleCut = 2;
37
38Double_t BmnParticleEqualizer::fPMin = 0.4;
39Double_t BmnParticleEqualizer::fPMax = 5.4;
41Int_t BmnParticleEqualizer::fIntervalCount = 25;
42// particle PDG codes to be equalized: p, pi+, pi-, K+, K- , e-, e+
43vector<Int_t> BmnParticleEqualizer::fParticles({2212, 211, -211, 321, -321}); //, 11, -11});
44// their masses in MeV: 938.272,139.6,139.6,493.7,493.7
45
46Double_t fPtMin = 0, fPtMax = 3, fYMin = 0, fYMax = 3, fEtaMin = -4, fEtaMax = 8, fThetaMin = 0, fThetaMax = 3.2,
47 fPhiMin = -3.2, fPhiMax = 3.2;
48
49// Default 'stParticleInfo' constructor for storing particle distrubutons
50BmnParticleEqualizer::stParticleInfo::stParticleInfo(int pdg_key, Double_t min_p, Double_t max_p, Int_t interval_count)
51 : fY0(0)
52 , fSigma(0.72)
53 , fT(0.223)
54{
55 // construct and initialize vector for particle numbers
56 fParticleNumber.resize(interval_count);
57 fill(fParticleNumber.begin(), fParticleNumber.end(), 0);
58
59 // construct vector with P histograms divided by momentum intervals
60 fPHistVector.resize(interval_count);
61 fEtaHistVector.resize(interval_count);
62}
63
64// 'BmnParticleEqualizer' constructor with input histograms
66 : FairGenerator()
67 , fIntervalStep((fPMax - fPMin) / fIntervalCount)
68{
69 fMaxParticles.resize(fIntervalCount);
70 fill(fMaxParticles.begin(), fMaxParticles.end(), 0);
71
72 // initialize map with particle information
73 for (auto pdg_key : fParticles)
74 fParticleInfos.emplace(pdg_key, make_unique<stParticleInfo>(pdg_key, fPMin, fPMax, fIntervalCount));
75
76 isActive = ReadSampleHistograms(hist_file_name);
77 if (!isActive)
78 LOG(error) << "Errors occured while initializing BmnParticleEqualizer generator, it will be skipped";
79}
80
81// Constructor with specified particle types
83 vector<Int_t> pdg_codes,
84 Double_t min_p,
85 Double_t max_p,
86 Int_t intervals)
87 : FairGenerator()
88{
89 fPMin = min_p;
90 fPMax = max_p;
91 fIntervalCount = intervals;
92 fIntervalStep = (max_p - min_p) / intervals;
93
94 // set fParticles to given pdg_codes
95 fParticles.swap(pdg_codes);
96
97 fMaxParticles.resize(fIntervalCount);
98 fill(fMaxParticles.begin(), fMaxParticles.end(), 0);
99
100 // initialize map with particle information
101 for (auto pdg_key : fParticles)
102 fParticleInfos.emplace(pdg_key, make_unique<stParticleInfo>(pdg_key, fPMin, fPMax, fIntervalCount));
103
104 isActive = ReadSampleHistograms(hist_file_name);
105 if (!isActive)
106 LOG(error) << "Errors occured while initializing BmnParticleEqualizer generator, it will be skipped";
107}
108
109// Initialize generator
111{
112 return kTRUE;
113}
114
115// fit P histogram to generate the values according to the analytical functions
116int BmnParticleEqualizer::FitPHistogram(unique_ptr<TH1D>& hP, int pdg_key, Double_t p_min, Double_t p_max)
117{
118 if (hP->GetEntries() == 0) {
119 LOG(warning) << TString::Format("P (momentum) histogram is empty for PDG = %d", pdg_key);
120 return -1;
121 }
122
123 // fit P distribution for the particle type by gaus + landau
124 TString dist_func_name = TString::Format("distP_pdg%d", pdg_key);
125 TF1* p_distribution = new TF1(dist_func_name, "gaus(0)+gaus(3)+landau(6)", p_min, p_max);
126 Double_t p_avg = (p_min + p_max) / 2;
127 // Double_t y_max_value = hP->GetBinContent(hP->GetMaximumBin());
128 Double_t x_max_value = hP->GetXaxis()->GetBinUpEdge(hP->GetMaximumBin());
129 p_distribution->SetParLimits(1, p_min, p_avg);
130 p_distribution->SetParameter(1, p_min);
131 p_distribution->SetParLimits(2, 0.1, p_avg);
132 p_distribution->SetParameter(2, p_avg / 4);
133 p_distribution->SetParLimits(4, x_max_value - 0.1, p_max);
134 p_distribution->SetParameter(4, x_max_value - 0.1);
135 p_distribution->SetParLimits(5, 0.1, p_avg);
136 p_distribution->SetParameter(5, p_avg / 2);
137 p_distribution->SetParLimits(7, p_min, TMath::Min(x_max_value, p_avg));
138 p_distribution->SetParameter(7, p_min);
139 p_distribution->SetParLimits(8, 0.1, p_avg);
140 p_distribution->SetParameter(8, p_avg / 4);
141
142 TFitResultPtr r = hP->Fit(p_distribution, "SQ0");
143 if (!r->IsValid()) {
144 LOG(error) << TString::Format("Fit of the P (momentum) histogram failed for PDG = %d", pdg_key);
145 // return -2;
146 }
147
148 return 0;
149}
150
151// fit Pt histogram to generate the values according to the analytical functions
152int BmnParticleEqualizer::FitPtHistogram(unique_ptr<TH1D>& hPt,
153 int pdg_key,
154 Double_t pdg_mass,
155 Double_t pt_min,
156 Double_t pt_max,
157 Double_t& t_output)
158{
159 if (hPt->GetEntries() == 0) {
160 LOG(warning) << TString::Format("Pt (transverse momentum) histogram is empty for PDG = %d", pdg_key);
161 return -1;
162 }
163
164 // fit Pt distribution for the particle type by expo
165 TString dist_func_name = TString::Format("distPt_pdg%d", pdg_key);
166 TF1* pt_distribution =
167 new TF1(dist_func_name, TString::Format("[0]*x*exp(-sqrt(x*x+%f)/[1])", pdg_mass * pdg_mass), pt_min, pt_max);
168 pt_distribution->SetParameter(1, t_output);
169
170 TFitResultPtr r = hPt->Fit(pt_distribution, "SQ0");
171 t_output = r->Parameter(1);
172
173 return 0;
174}
175
176// fit Y histogram to generate the values according to the analytical functions
177int BmnParticleEqualizer::FitYHistogram(unique_ptr<TH1D>& hY, int pdg_key, Double_t& y0_output, Double_t& sigma_putput)
178{
179 if (hY->GetEntries() == 0) {
180 LOG(warning) << TString::Format("Rapidity histogram is empty for %d PDG code", pdg_key);
181 return -1;
182 }
183
184 // fit rapidity distribution for the particle type by gauss
185 if (pdg_key != 2212) {
186 TFitResultPtr r = hY->Fit("gaus", "SQ0");
187 y0_output = r->Parameter(1);
188 sigma_putput = r->Parameter(2);
189 // if proton (PDG == 2212)
190 } else {
191 Double_t max_bin_value = hY->GetMaximum();
192 const string minimizer_type = ROOT::Math::MinimizerOptions::DefaultMinimizerType();
193 ROOT::Math::MinimizerOptions::SetDefaultMinimizer("Genetic");
194
195 // FITTING ONLY MEDIUM PEAK with background
196 // TF1* fProtonYDistribution = new TF1("distProtonY", "gaus(0)+pol0(3)", 0.3, 2);
197 // fProtonYDistribution->SetParLimits(0, 0, max_bin_value);
198 // fProtonYDistribution->SetParLimits(1, 0.3, 2);
199 // fProtonYDistribution->SetParName(1,"proton_y0");
200 // fProtonYDistribution->SetParLimits(2, 0.05, 1);
201 // fProtonYDistribution->SetParName(2,"proton_sigma");
202 // fProtonYDistribution->SetParLimits(3, 0, max_bin_value);
203 // TFitResultPtr r = hY->Fit(fProtonYDistribution,"SQ0","", 0.3, 2);
204 // FITTING THREE PEAKS: TARGET FRAGMENTATION + PARTICIPANTS + SPECTATORS
205 unique_ptr<TF1> fProtonYDistribution =
206 make_unique<TF1>("distProtonY", "gaus(0)+gaus(3)+gaus(6)", 0.2, 5); // 0, 5);
207 fProtonYDistribution->SetParLimits(0, 0, max_bin_value);
208 fProtonYDistribution->SetParLimits(1, 0, 0.05);
209 fProtonYDistribution->SetParLimits(2, 0.01, 0.4);
210 fProtonYDistribution->SetParameter(2, 0.2);
211 fProtonYDistribution->SetParLimits(3, 0, max_bin_value);
212 fProtonYDistribution->SetParName(4, "proton_y0");
213 fProtonYDistribution->SetParLimits(4, 0.3, 2);
214 fProtonYDistribution->SetParameter(4, 1);
215 fProtonYDistribution->SetParName(5, "proton_sigma");
216 fProtonYDistribution->SetParLimits(5, 0.05, 1);
217 fProtonYDistribution->SetParameter(5, 0.5);
218 fProtonYDistribution->SetParLimits(6, 0, max_bin_value);
219 fProtonYDistribution->SetParLimits(7, 1.5, 3);
220 fProtonYDistribution->SetParameter(7, 2.25);
221 fProtonYDistribution->SetParLimits(8, 0.05, 1);
222 fProtonYDistribution->SetParameter(8, 0.5);
223
224 TFitResultPtr r = hY->Fit(fProtonYDistribution.get(), "SQ0", "", 0, 5);
225 y0_output = r->Parameter(r->Index("proton_y0"));
226 sigma_putput = r->Parameter(r->Index("proton_sigma"));
227
228 ROOT::Math::MinimizerOptions::SetDefaultMinimizer(minimizer_type.c_str());
229 }
230
231 return 0;
232}
233
234// fit Eta (pseudorapidity) histogram to generate the values according to the analytical functions
235int BmnParticleEqualizer::FitEtaHistogram(unique_ptr<TH1D>& hEta, int pdg_key, Double_t eta_min, Double_t eta_max)
236{
237 if (hEta->GetEntries() == 0) {
238 LOG(warning) << TString::Format("Eta (pseudorapidity) histogram is empty for PDG = %d", pdg_key);
239 return -1;
240 }
241
242 // fit P distribution for the particle type by gaus + landau
243 TString dist_func_name = TString::Format("distEta_pdg%d", pdg_key);
244 TF1* eta_distribution = new TF1(dist_func_name, "crystalball", eta_min, eta_max);
245 eta_distribution->SetParLimits(1, 1, 4);
246 eta_distribution->SetParameter(1, 2.5);
247 eta_distribution->SetParLimits(2, 0.1, 1.5);
248 eta_distribution->SetParameter(2, 0.5);
249 eta_distribution->SetParLimits(3, 0.1, 2);
250 eta_distribution->SetParameter(3, 1);
251 eta_distribution->SetParLimits(4, 1, 10);
252 eta_distribution->SetParameter(4, 3);
253
254 TFitResultPtr r = hEta->Fit(eta_distribution, "SQ0");
255 if (!r->IsValid()) {
256 LOG(error) << TString::Format("Fit of the Eta (pseudorapidity) histogram failed for PDG = %d", pdg_key);
257 // return -2;
258 }
259
260 return 0;
261}
262
263int BmnParticleEqualizer::ProduceSampleHistograms(TString input_list_file, TString output_histo_file)
264{
265 gSystem->ExpandPathName(input_list_file);
266
267 // get file list from the input text file
268 list<string> file_list;
269 ifstream list_file(input_list_file.Data());
270 string s;
271 while (getline(list_file, s))
272 file_list.push_back(s);
273 if (file_list.empty()) {
274 cout << "WARNING: There are no files in the list of the input text file: " << input_list_file << endl;
275 return 0;
276 }
277
278 // form ROOT chain for the file list
279 TChain dataChain("bmndata");
280 for (auto const& cur_file_path : file_list) {
281 TString strFilePath(cur_file_path);
282 gSystem->ExpandPathName(strFilePath);
283
284 dataChain.AddFile(strFilePath);
285 }
286
287 if (dataChain.GetEntries() < 1) {
288 cout << "WARNING: There are no correct input files in the text list stored at: \"" << input_list_file << "\""
289 << endl;
290 return 0;
291 }
292
293 // flag whether the input files have SIM or DST format
294 bool isDST = false;
295 TClonesArray* mcTracks = nullptr;
296 BmnMCInfoDst* mcInfo = nullptr;
297 if (dataChain.GetBranch("MCTrack") == nullptr) {
298 LOG(info) << "'MCTrack' branch was not found, searching for 'BmnMCInfo->MCTrack'...";
299 if (dataChain.GetBranch("BmnMCInfo.") == nullptr) {
300 LOG(error) << "'BmnMCInfo.' branch was not found too, please, check the structure of the files, exiting...";
301 return -1;
302 }
303 dataChain.SetBranchAddress("BmnMCInfo.", &mcInfo);
304 if (mcInfo == nullptr) {
305 LOG(error)
306 << "'BmnMCInfo.' branch was not read correctly, please, check the structure of the files, exiting...";
307 return -2;
308 }
309 isDST = true;
310 LOG(info) << "'BmnMCInfo->MCTrack' has been found";
311 dataChain.SetBranchStatus("*", 0);
312 dataChain.SetBranchStatus("BmnMCInfo*", 1);
313 } else {
314 dataChain.SetBranchAddress("MCTrack", &mcTracks);
315 if (mcTracks == nullptr) {
316 LOG(error)
317 << "MCTrack' branch was not read correctly, please, check the structure of the files, exiting...";
318 return -3;
319 }
320 dataChain.SetBranchStatus("*", 0);
321 dataChain.SetBranchStatus("MCTrack*", 1);
322 }
323
324 int iEventNumber = dataChain.GetEntries();
325 if (iEventNumber < 1) {
326 cout << "WARNING: There are no correct entries in the file list stored at: \"" << input_list_file << "\""
327 << endl;
328 return 0;
329 }
330
331 TFile* hist_file = TFile::Open(output_histo_file, "RECREATE");
332
333 // create map with particle infos
334 map<Int_t, unique_ptr<stParticleInfo>> particle_infos;
335 for (auto pdg_key : fParticles)
336 particle_infos.emplace(pdg_key, make_unique<stParticleInfo>(pdg_key, fPMin, fPMax, fIntervalCount));
337
338 Double_t interval_width = (fPMax - fPMin) / fIntervalCount;
339 // create all the histogramавторефератеs using make_unique
340 for (auto pdg_key : fParticles) {
341 TString histogram_name = TString::Format("hP_pdg%d", pdg_key);
342 particle_infos[pdg_key]->fPHist = make_unique<TH1D>(histogram_name, histogram_name, 80, fPMin, fPMax);
343 histogram_name = TString::Format("hPt_pdg%d", pdg_key);
344 particle_infos[pdg_key]->fPtHist = make_unique<TH1D>(histogram_name, histogram_name, 60, fPtMin, fPtMax);
345 histogram_name = TString::Format("hY_pdg%d", pdg_key);
346 particle_infos[pdg_key]->fYHist = make_unique<TH1D>(histogram_name, histogram_name, 60, fYMin, fYMax);
347 histogram_name = TString::Format("hEta_pdg%d", pdg_key);
348 particle_infos[pdg_key]->fEtaHist = make_unique<TH1D>(histogram_name, histogram_name, 60, fEtaMin, fEtaMax);
349 histogram_name = TString::Format("hTheta_pdg%d", pdg_key);
350 particle_infos[pdg_key]->fThetaHist =
351 make_unique<TH1D>(histogram_name, histogram_name, 61, fThetaMin, fThetaMax);
352 histogram_name = TString::Format("hPhi_pdg%d", pdg_key);
353 particle_infos[pdg_key]->fPhiHist = make_unique<TH1D>(histogram_name, histogram_name, 64, fPhiMin, fPhiMax);
354 int hist_counter = 0;
355 for (auto& p_hist : particle_infos[pdg_key]->fPHistVector) {
356 histogram_name = TString::Format("hP%d_pdg%d", ++hist_counter, pdg_key);
357 p_hist = make_unique<TH1D>(histogram_name, histogram_name, 40, fPMin + (hist_counter - 1) * interval_width,
358 fPMin + hist_counter * interval_width);
359 }
360 hist_counter = 0;
361 for (auto& eta_hist : particle_infos[pdg_key]->fEtaHistVector) {
362 histogram_name = TString::Format("hEta%d_pdg%d", ++hist_counter, pdg_key);
363 eta_hist = make_unique<TH1D>(histogram_name, histogram_name, 60, -4, 8);
364 }
365 }
366
367 // fill all the histograms for specified particles by the PDG code
368 int iCurrentEvent = 0;
369 LOG(info) << "Processing events...";
370 for (Int_t iEvent = 0; iEvent < iEventNumber; iEvent++) {
371 // Next Event
372 iCurrentEvent++;
373 if (iCurrentEvent % 1000 == 0)
374 LOG(info) << "Processing event #" << iCurrentEvent << " of " << iEventNumber;
375 dataChain.GetEntry(iEvent);
376
377 TClonesArray* mc_tracks = nullptr;
378 if (isDST)
379 mc_tracks = mcInfo->GetMCTracks();
380 else
381 mc_tracks = mcTracks;
382
383 for (int i = 0; i < mc_tracks->GetEntries(); i++) {
384 CbmMCTrack* pTrack = (CbmMCTrack*)mc_tracks->At(i);
385 Int_t part_code = pTrack->GetPdgCode();
386
387 // exclude secondary particles
388 if (pTrack->GetMotherId() >= 0)
389 continue;
390 // filter particles
391 if (iParticleCut > 0) {
392 // exclude tracks without points in Silicon and GEMs
393 if ((pTrack->GetNPoints(kGEM) < 1) || (pTrack->GetNPoints(kSILICON) < 1))
394 continue;
395 if (iParticleCut > 1) {
396 // exclude tracks without points in ToF detectors
397 if ((pTrack->GetNPoints(kTOF) < 1) && (pTrack->GetNPoints(kTOF1) < 1)
398 && (pTrack->GetNPoints(kTOF701) < 1))
399 continue;
400 }
401 }
402
403 if (auto part_iter = particle_infos.find(part_code); part_iter != particle_infos.end()) {
404 int interval_number = (pTrack->GetP() - fPMin) / interval_width;
405 part_iter->second->fPHist->Fill(pTrack->GetP());
406 part_iter->second->fPtHist->Fill(pTrack->GetPt());
407 part_iter->second->fYHist->Fill(pTrack->GetRapidity());
408 part_iter->second->fEtaHist->Fill(
409 0.5 * TMath::Log((pTrack->GetP() + pTrack->GetPz()) / (pTrack->GetP() - pTrack->GetPz())));
410 part_iter->second->fThetaHist->Fill(
411 TMath::ACos(pTrack->GetPz() / pTrack->GetP())); // *TMath::RadToDeg()
412 part_iter->second->fPhiHist->Fill(
413 TMath::ATan2(pTrack->GetPy(), pTrack->GetPx())); // *TMath::RadToDeg()
414 // compare doubles: abs(min(a,b))*numeric_limits<double>::epsilon()*error_factor
415 if ((pTrack->GetP() >= fPMin) && (isless(pTrack->GetP(), fPMax))) {
416 part_iter->second->fPHistVector[interval_number]->Fill(pTrack->GetP());
417 part_iter->second->fEtaHistVector[interval_number]->Fill(
418 0.5 * TMath::Log((pTrack->GetP() + pTrack->GetPz()) / (pTrack->GetP() - pTrack->GetPz())));
419 }
420 }
421 } // for (int i = 0; i < mc_tracks->GetEntries(); i++) {
422 } // while (sim_reader.Next())
423
424 // check correctness of all the histograms
425 for (auto pdg_key : fParticles) {
426 if (particle_infos[pdg_key]->fPHist->GetEntries() == 0) {
427 LOG(error) << "Momentum histogram is empty for pdg=" << pdg_key;
428 return -4;
429 }
430 if (particle_infos[pdg_key]->fPtHist->GetEntries() == 0) {
431 LOG(error) << "Transverse momentum histogram is empty for pdg=" << pdg_key;
432 return -5;
433 }
434 if (particle_infos[pdg_key]->fYHist->GetEntries() == 0) {
435 LOG(error) << "Rapidity histogram is empty for pdg=" << pdg_key;
436 return -6;
437 }
438 if (particle_infos[pdg_key]->fEtaHist->GetEntries() == 0) {
439 LOG(error) << "Pseudorapidity histogram is empty for pdg=" << pdg_key;
440 return -7;
441 }
442 if (particle_infos[pdg_key]->fThetaHist->GetEntries() == 0) {
443 LOG(error) << "Theta angle histogram is empty for pdg=" << pdg_key;
444 return -8;
445 }
446 if (particle_infos[pdg_key]->fPhiHist->GetEntries() == 0) {
447 LOG(error) << "Phi angle histogram is empty for pdg=" << pdg_key;
448 return -9;
449 }
450 }
451
452 // fit histograms and calculate fY0, fSigma, fT for all the specified particle types
453 Double_t fY0 = 0, fSigma = 0.72, fT = 0.223;
454 for (auto pdg_key : fParticles) {
455 TDatabasePDG* pdgBase = TDatabasePDG::Instance();
456 TParticlePDG* particle = pdgBase->GetParticle(pdg_key);
457 if (!particle) {
458 LOG(fatal) << "PDG code " << pdg_key << "is not defined. exiting...";
459 return -10;
460 }
461 Double_t fPDGMass = particle->Mass();
462
463 // fit full particle momentum histograms
464 if (FitPHistogram(particle_infos[pdg_key]->fPHist, pdg_key, fPMin, fPMax) != 0)
465 return -11;
466
467 // fit Pt momentum histograms
468 if (FitPtHistogram(particle_infos[pdg_key]->fPtHist, pdg_key, fPDGMass, fPtMin, fPtMax, fT) != 0)
469 return -12;
470
471 // fit Y (rapidity) histograms
472 if (FitYHistogram(particle_infos[pdg_key]->fYHist, pdg_key, fY0, fSigma) != 0)
473 return -13;
474 TVector3 Y0SigmaT(fY0, fSigma, fT);
475 TString vector_name = TString::Format("Y0SigmaT_pdg%d", pdg_key);
476 hist_file->WriteObject(&Y0SigmaT, vector_name);
477
478 // fit Eta (pseudorapidity) histograms
479 // if (FitEtaHistogram(particle_infos[pdg_key]->fEtaHist, pdg_key, eta_min, eta_max) != 0)
480 // return -5;
481
482 LOG(info) << TString::Format("pdg=%i y0=%4.2f sigma_y=%4.2f T_pt=%6.4f", pdg_key, fY0, fSigma, fT);
483 }
484
485 // write the histograms to the output ROOT file
486 for (auto pdg_key : fParticles) {
487 particle_infos[pdg_key]->fPHist->Write();
488 particle_infos[pdg_key]->fPtHist->Write();
489 particle_infos[pdg_key]->fYHist->Write();
490 particle_infos[pdg_key]->fEtaHist->Write();
491 particle_infos[pdg_key]->fThetaHist->Write();
492 particle_infos[pdg_key]->fPhiHist->Write();
493 for (auto& p_hist : particle_infos[pdg_key]->fPHistVector)
494 p_hist->Write();
495 for (auto& eta_hist : particle_infos[pdg_key]->fEtaHistVector)
496 eta_hist->Write();
497 // hist_file->WriteObject(&particle_infos[pdg_key]->fPHistVector, "PHistVector");
498 // hist_file->WriteObject(&particle_infos[pdg_key]->fEtaHistVector, "EtaHistVector");
499 }
500
501 hist_file->Close();
502 return 0;
503}
504
505// Calculate parameters for all the particle types
506// according to the given histogram stored in the 'input_histo_file' file
507Bool_t BmnParticleEqualizer::ReadSampleHistograms(TString input_histo_file)
508{
509 // open file with histograms
510 TFile* hist_file = TFile::Open(input_histo_file);
511 // get histograms from the file and estimate parameters for embedding new particles of this type
512 for (auto pdg_key : fParticles) {
513 TString histogram_name = TString::Format("hP_pdg%d", pdg_key);
514 fParticleInfos[pdg_key]->fPHist = unique_ptr<TH1D>((TH1D*)hist_file->Get(histogram_name));
515 if (fParticleInfos[pdg_key]->fPHist.get() == nullptr) {
516 LOG(error) << "Momentum histogram does not exist for pdg=" << pdg_key;
517 return kFALSE;
518 }
519 if (fParticleInfos[pdg_key]->fPHist->GetEntries() == 0) {
520 LOG(error) << "Momentum histogram is empty for pdg=" << pdg_key;
521 return kFALSE;
522 }
523 histogram_name = TString::Format("hPt_pdg%d", pdg_key);
524 fParticleInfos[pdg_key]->fPtHist = unique_ptr<TH1D>((TH1D*)hist_file->Get(histogram_name));
525 if (fParticleInfos[pdg_key]->fPtHist.get() == nullptr) {
526 LOG(error) << "Transverse momentum histogram does not exist for pdg=" << pdg_key;
527 return kFALSE;
528 }
529 if (fParticleInfos[pdg_key]->fPtHist->GetEntries() == 0) {
530 LOG(error) << "Transverse momentum histogram is empty for pdg=" << pdg_key;
531 return kFALSE;
532 }
533 histogram_name = TString::Format("hY_pdg%d", pdg_key);
534 fParticleInfos[pdg_key]->fYHist = unique_ptr<TH1D>((TH1D*)hist_file->Get(histogram_name));
535 if (fParticleInfos[pdg_key]->fYHist.get() == nullptr) {
536 LOG(error) << "Rapidity histogram does not exist for pdg=" << pdg_key;
537 return kFALSE;
538 }
539 if (fParticleInfos[pdg_key]->fYHist->GetEntries() == 0) {
540 LOG(error) << "Rapidity histogram is empty for pdg=" << pdg_key;
541 return kFALSE;
542 }
543 histogram_name = TString::Format("hEta_pdg%d", pdg_key);
544 fParticleInfos[pdg_key]->fEtaHist = unique_ptr<TH1D>((TH1D*)hist_file->Get(histogram_name));
545 if (fParticleInfos[pdg_key]->fEtaHist.get() == nullptr) {
546 LOG(error) << "Pseudorapidity histogram does not exist for pdg=" << pdg_key;
547 return kFALSE;
548 }
549 if (fParticleInfos[pdg_key]->fEtaHist->GetEntries() == 0) {
550 LOG(error) << "Pseudorapidity histogram is empty for pdg=" << pdg_key;
551 return kFALSE;
552 }
553 histogram_name = TString::Format("hTheta_pdg%d", pdg_key);
554 fParticleInfos[pdg_key]->fThetaHist = unique_ptr<TH1D>((TH1D*)hist_file->Get(histogram_name));
555 if (fParticleInfos[pdg_key]->fThetaHist.get() == nullptr) {
556 LOG(error) << "Theta angle histogram does not exist for pdg=" << pdg_key;
557 return kFALSE;
558 }
559 if (fParticleInfos[pdg_key]->fThetaHist->GetEntries() == 0) {
560 LOG(error) << "Theta angle histogram is empty for pdg=" << pdg_key;
561 return kFALSE;
562 }
563 histogram_name = TString::Format("hPhi_pdg%d", pdg_key);
564 fParticleInfos[pdg_key]->fPhiHist = unique_ptr<TH1D>((TH1D*)hist_file->Get(histogram_name));
565 if (fParticleInfos[pdg_key]->fPhiHist.get() == nullptr) {
566 LOG(error) << "Phi angle histogram does not exist for pdg=" << pdg_key;
567 return kFALSE;
568 }
569 if (fParticleInfos[pdg_key]->fPhiHist->GetEntries() == 0) {
570 LOG(error) << "Phi angle histogram is empty for pdg=" << pdg_key;
571 return kFALSE;
572 }
573 int hist_counter = 0;
574 for (auto& p_hist : fParticleInfos[pdg_key]->fPHistVector) {
575 histogram_name = TString::Format("hP%d_pdg%d", ++hist_counter, pdg_key);
576 p_hist = unique_ptr<TH1D>((TH1D*)hist_file->Get(histogram_name));
577 if (p_hist.get() == nullptr) {
578 LOG(error) << "Momentum histogram does not exist for pdg=" << pdg_key
579 << " in interval=" << hist_counter;
580 return kFALSE;
581 }
582 }
583 hist_counter = 0;
584 for (auto& eta_hist : fParticleInfos[pdg_key]->fEtaHistVector) {
585 histogram_name = TString::Format("hEta%d_pdg%d", ++hist_counter, pdg_key);
586 eta_hist = unique_ptr<TH1D>((TH1D*)hist_file->Get(histogram_name));
587 if (eta_hist.get() == nullptr) {
588 LOG(error) << "Pseudorapidity histogram does not exist for pdg=" << pdg_key
589 << " in interval=" << hist_counter;
590 return kFALSE;
591 }
592 }
593
594 TDatabasePDG* pdgBase = TDatabasePDG::Instance();
595 TParticlePDG* particle = pdgBase->GetParticle(pdg_key);
596 if (!particle) {
597 Fatal("PrepareDistribution", "PDG code %d is not defined. exiting...", pdg_key);
598 return kFALSE;
599 }
600 Double_t fPDGMass = particle->Mass();
601
602 // check that there is Pt histogram for the particle type in the file
603 if ((!fParticleInfos[pdg_key]->fPtHist) || (fParticleInfos[pdg_key]->fPtHist->GetEntries() == 0)) {
604 LOG(warning) << "BmnParticleEqualizer: Pt histogram is absent or empty for PDG = " << pdg_key;
605 continue;
606 }
607 // fit Pt distribution for the particle type by expo
608 FitPtHistogram(fParticleInfos[pdg_key]->fPtHist, pdg_key, fPDGMass, fPMin, fPMax, fParticleInfos[pdg_key]->fT);
609
610 Info("PrepareDistribution", "pdg=%i y0=%4.2f sigma_y=%4.2f T_pt=%6.4f", pdg_key, fParticleInfos[pdg_key]->fY0,
611 fParticleInfos[pdg_key]->fSigma, fParticleInfos[pdg_key]->fT);
612
613 // check that there is Y histogram for the particle type in the file
614 if ((!fParticleInfos[pdg_key]->fYHist) || (fParticleInfos[pdg_key]->fYHist->GetEntries() == 0)) {
615 Warning("PrepareDistribution", "Y histogram is absent or empty for %d PDG code", pdg_key);
616 continue;
617 }
618 FitYHistogram(fParticleInfos[pdg_key]->fYHist, pdg_key, fParticleInfos[pdg_key]->fY0,
619 fParticleInfos[pdg_key]->fSigma);
620 }
621
622 return kTRUE;
623}
624
625// Creates an event with equal number of particles at all momentum intervals
626Bool_t BmnParticleEqualizer::ReadEvent(FairPrimaryGenerator* primGen)
627{
628 if (!isActive)
629 return kFALSE;
630
632 // reset particle count for all the particle types
633 for (auto part_iter = fParticleInfos.begin(); part_iter != fParticleInfos.end(); part_iter++)
634 fill(part_iter->second->fParticleNumber.begin(), part_iter->second->fParticleNumber.end(), 0);
635 // clear maximum number of a particle type among all particles (divided by momentum intervals)
636 fill(fMaxParticles.begin(), fMaxParticles.end(), 0);
637
639 // form particle distributions for the current event (obtained by the previous generators)
640 TClonesArray* arrParticles = ((CbmStack*)gMC->GetStack())->GetListOfParticles();
641 for (int i = 0; i < arrParticles->GetEntries(); i++) {
642 // get particle information
643 TParticle* part = (TParticle*)arrParticles->At(i);
644 Int_t part_code = part->GetPdgCode();
645 Double_t part_p = part->P();
646 Double_t part_eta = part->Eta();
647
648 // exclude secondary particles
649 if (!part->IsPrimary())
650 continue;
651
652 // check particle momentum is inside the momentum range
653 int interval_number = (part_p - fPMin) / fIntervalStep;
654 if ((interval_number < 0) || (interval_number >= fIntervalCount))
655 continue;
656
657 // add found particle according to the momentum to the "PDG -> Particle Count" map (increase by 1)
658 LOG(debug) << TString::Format("Found particle: PDG=%i P=%4.2f Eta=%4.2f", part_code, part_p, part_eta);
659 if (auto part_iter = fParticleInfos.find(part_code); part_iter != fParticleInfos.end()) {
660 // filter particles according to the momentum and pseudorapidity in case of empty statistics for the values
661 if (iParticleCut > 0) {
662 if (fParticleInfos[part_code]->fPHistVector[interval_number]->GetBinContent(
663 fParticleInfos[part_code]->fPHistVector[interval_number]->FindBin(part_p))
664 < 1)
665 continue;
666 if (fParticleInfos[part_code]->fEtaHistVector[interval_number]->GetBinContent(
667 fParticleInfos[part_code]->fEtaHistVector[interval_number]->FindBin(part_eta))
668 < 1)
669 continue;
670 // if (fParticleInfos[part_code]->fPtHist->GetBinContent(
671 // fParticleInfos[part_code]->fPtHist->FindBin(part->Pt())) < 1)
672 // continue;
673 // if (fParticleInfos[part_code]->fYHist->GetBinContent(
674 // fParticleInfos[part_code]->fYHist->FindBin(part->Y())) < 1)
675 // continue;
676 // if (fParticleInfos[part_code]->fThetaHist->GetBinContent(
677 // fParticleInfos[part_code]->fThetaHist->FindBin(part->Theta())) < 1)
678 // continue;
679 }
680
681 part_iter->second->fParticleNumber[interval_number] += 1;
682 // update maximum number among all the particle if greater (for the current momentum interval)
683 if (part_iter->second->fParticleNumber[interval_number] > fMaxParticles[interval_number])
684 fMaxParticles[interval_number] = part_iter->second->fParticleNumber[interval_number];
685 }
686 } // for (int i = 0; i < arrParticles->GetEntries(); i++)
687
688 // generate new particles to equalize their numbers for different types
689 for (auto pdg_key : fParticles) {
690 LOG(debug) << TString::Format("Current particle type to be equalized: pdg=%i y0=%4.2f sigma_y=%4.2f T_pt=%6.4f",
691 pdg_key, fParticleInfos[pdg_key]->fY0, fParticleInfos[pdg_key]->fSigma,
692 fParticleInfos[pdg_key]->fT);
693 Double_t cur_p = fPMin;
694 // add a number of particles for all momentum intervals to equalize their count
695 LOG(debug) << "Adding paticle to equalize the numbers...";
696 for (int cur_interval = 0; cur_interval < fIntervalCount; cur_interval++, cur_p += fIntervalStep) {
697 int add_particle = fMaxParticles[cur_interval] - fParticleInfos[pdg_key]->fParticleNumber[cur_interval];
698 LOG(debug) << endl
699 << " " << add_particle << " particle with PDG = " << pdg_key << " (" << cur_p << " GeV)";
700 // cout << "Adding " << add_particle << " particles with PDG = " << pdg_key
701 // << " (" << cur_p << " GeV)" << endl;
702 for (Int_t k = 0; k < add_particle; k++) {
703 Double_t phi = gRandom->Uniform(0, TMath::TwoPi());
704 Double_t p = 0;
705 if (fParticleInfos[pdg_key]->fPHistVector[cur_interval]->GetEntries() > 2)
706 p = fParticleInfos[pdg_key]->fPHistVector[cur_interval]->GetRandom();
707 else {
708 TString dist_func_name = TString::Format("distP_pdg%d", pdg_key);
709 p = fParticleInfos[pdg_key]
710 ->fPHist->GetFunction(dist_func_name)
711 ->GetRandom(cur_p, cur_p + fIntervalStep);
712 }
713 // Double_t pt = fParticleInfos[pdg_key]->fPtDistribution->GetRandom(cur_pt, cur_pt + fIntervalStep);
714 // Double_t y = gRandom->Gaus(particle_info->fY0, particle_info->fSigma);
715 // Double_t mt = TMath::Sqrt(fPDGMass * fPDGMass + pt * pt);
716 // Double_t pz = mt * TMath::SinH(y);
717 Double_t eta = 0;
718 if (fParticleInfos[pdg_key]->fEtaHistVector[cur_interval]->GetEntries() > 2)
719 eta = fParticleInfos[pdg_key]->fEtaHistVector[cur_interval]->GetRandom();
720 else {
721 // TString dist_func_name = TString::Format("distEta_pdg%d", pdg_key);
722 eta = fParticleInfos[pdg_key]->fEtaHist->GetRandom();
723 }
724 Double_t pt = p / TMath::CosH(eta);
725 Double_t px = pt * TMath::Cos(phi);
726 Double_t py = pt * TMath::Sin(phi);
727 Double_t pz = pt * TMath::SinH(eta);
728
729 LOG(debug) << "Particle generated: pdg=" << pdg_key << " p=" << p << " eta=" << eta;
730 FairMCEventHeader* pCurrent = primGen->GetEvent();
731 // AddTrack parameters: pdgid, px, py, pz, vx, vy, vz
732 primGen->AddTrack(pdg_key, px, py, pz, pCurrent->GetX(), pCurrent->GetY(), pCurrent->GetZ());
733 }
734 }
735 }
736
737 return kTRUE;
738}
739
740// static function to fit the obtained sample histograms (to show whether the results are appropriate)
741void BmnParticleEqualizer::FitSampleHistograms(TString input_histo_file)
742{
743 TFile* f = TFile::Open(input_histo_file);
744 for (int particle_number : fParticles) {
745 /*TCanvas* c = */ new TCanvas(TString::Format("c_%d", particle_number),
746 TString::Format("Distributions for particle PDG = %d", particle_number), 1000,
747 500);
748 TH1D* h1 = (TH1D*)f->Get(TString::Format("hP_pdg%d", particle_number));
749
750 Double_t x_max_value = h1->GetXaxis()->GetBinCenter(h1->GetMaximumBin());
751 Double_t y_max_value = h1->GetBinContent(h1->GetMaximumBin());
752 Double_t p_avg = (fPMin + fPMax) / 2;
753 cout << "avg_value = " << p_avg << endl;
754 cout << "x_max_value = " << x_max_value << endl;
755 cout << "y_max_value = " << y_max_value << endl;
756 TF1* p_distribution = new TF1("distFit", "gaus(0)+gaus(3)+landau(6)", fPMin, fPMax);
757 p_distribution->SetParLimits(1, fPMin, p_avg);
758 p_distribution->SetParameter(1, fPMin);
759 p_distribution->SetParLimits(2, 0.1, p_avg);
760 p_distribution->SetParameter(2, p_avg / 4);
761 p_distribution->SetParLimits(4, x_max_value - 0.1, fPMax);
762 p_distribution->SetParameter(4, x_max_value - 0.1);
763 p_distribution->SetParLimits(5, 0.1, p_avg);
764 p_distribution->SetParameter(5, p_avg / 2);
765 p_distribution->SetParLimits(7, fPMin, TMath::Min(x_max_value, p_avg));
766 p_distribution->SetParameter(7, fPMin);
767 p_distribution->SetParLimits(8, 0.1, p_avg);
768 p_distribution->SetParameter(8, p_avg / 4);
769 h1->Fit(p_distribution);
770 h1->Draw();
771 }
772}
773
774// static function to show the obtained sample histograms with obtained fit (to check whether the results are
775// appropriate)
777{
778 TFile* f = TFile::Open(input_histo_file);
779 if ((!f) || (!f->IsOpen())) {
780 cout << "ERROR: unable to open ROOT file: " << input_histo_file << endl;
781 return -1;
782 }
783
784 for (int particle_number : fParticles) {
785 /*TCanvas* c = */ new TCanvas(TString::Format("c_%d", particle_number),
786 TString::Format("Distributions for particle PDG = %d", particle_number), 1000,
787 500);
788 TH1D* h1 = (TH1D*)f->Get(TString::Format("hP_pdg%d", particle_number));
789 TF1* f1 = h1->GetFunction(TString::Format("distP_pdg%d", particle_number));
790 f1->Draw();
791 h1->Draw("SAME");
792 }
793
794 return 0;
795}
796
797// define PDG code of a particle by the given mass
798// among particle types set by 'vecParticlePDG' vector or in the TDatabasePDG if the vector is empty
799// tolerance: relative if tolerance > 0, absolute (in GeV) in case of tolerance <= 0
800// return PDG code or 0 if no corresponding particle was found
801Int_t BmnParticleEqualizer::GetPDGCodeByMass(Double_t mass, Double_t tolerance, const vector<int>& vecParticlePDG)
802{
803 TDatabasePDG* pdg_base = TDatabasePDG::Instance();
804 if (!pdg_base) {
805 cout << "ERROR: Could not get TDatabasePDG instance" << endl;
806 return 0;
807 }
808
809 if (mass < 0)
810 mass *= -1;
811
812 if (vecParticlePDG.empty()) {
813 TIter next(pdg_base->ParticleList());
814 while (TParticlePDG* particle = (TParticlePDG*)next()) {
815 if (TMath::Abs(particle->Mass() - mass) < (tolerance > 0 ? tolerance * mass : -1 * tolerance))
816 return particle->PdgCode();
817 }
818 } else {
819 for (int particle_number : vecParticlePDG) {
820 TParticlePDG* particle = pdg_base->GetParticle(particle_number);
821 if (TMath::Abs(particle->Mass() - mass) < (tolerance > 0 ? tolerance * mass : -1 * tolerance))
822 return particle->PdgCode();
823 }
824 }
825
826 return 0;
827}
828
829// draw histogram with multiplicity of different particle types for all the momentum intervals
830// as well as P, Pt, Y, Eta, Theta, Phi distributions after the equalizing
831// it work both for SIM and DST files listed in the given text file ('input_list_file' var)
833{
834 gSystem->ExpandPathName(input_list_file);
835
836 // get file list from the input text file
837 list<string> file_list;
838 ifstream list_file(input_list_file.Data());
839 string s;
840 while (getline(list_file, s))
841 file_list.push_back(s);
842 if (file_list.empty()) {
843 cout << "WARNING: There are no files in the list of the input text file: " << input_list_file << endl;
844 return 0;
845 }
846
847 // form ROOT chain for the file list
848 TChain dataChain("bmndata");
849 for (auto const& cur_file_path : file_list) {
850 TString strFilePath(cur_file_path);
851 gSystem->ExpandPathName(strFilePath);
852
853 dataChain.Add(strFilePath);
854 }
855
856 // flag whether the input files have SIM or DST format
857 bool isDST = false;
858 TClonesArray *mcTracks = nullptr, *globalTracks = nullptr;
859 BmnMCInfoDst* mcInfo = nullptr;
860 if (dataChain.GetBranch("MCTrack") == nullptr) {
861 if (dataChain.GetBranch("BmnMCInfo.") == nullptr) {
862 LOG(error) << "'MCTrack' and 'BmnMCInfo.' branches were not found, please, check the structure of the "
863 "files, exiting...";
864 return -1;
865 }
866 dataChain.SetBranchAddress("BmnMCInfo.", &mcInfo);
867 if (mcInfo == nullptr) {
868 LOG(error)
869 << "'BmnMCInfo.' branch was not read correctly, please, check the structure of the files, exiting...";
870 return -2;
871 }
872 dataChain.SetBranchAddress("BmnGlobalTrack", &globalTracks);
873 if (globalTracks == nullptr) {
874 LOG(error) << "'BmnGlobalTrack' branch was not read correctly, please, check the structure of the files, "
875 "exiting...";
876 return -4;
877 }
878 isDST = true;
879 // dataChain.SetBranchStatus("*", false);
880 // dataChain.SetBranchStatus("BmnMCInfo*", true);
881 // dataChain.SetBranchStatus("BmnGlobalTrack", true);
882 } else {
883 dataChain.SetBranchAddress("MCTrack", &mcTracks);
884 if (mcTracks == nullptr) {
885 LOG(error)
886 << "MCTrack' branch was not read correctly, please, check the structure of the files, exiting...";
887 return -3;
888 }
889 // dataChain.SetBranchStatus("*", false);
890 // dataChain.SetBranchStatus("MCTrack*", true);
891 }
892
893 // create histogram with bars
894 TCanvas* c_number =
895 new TCanvas("c_number", "Multiplicity of different particle types for all the momentum intervals", 1000, 500);
896 gPad->SetGrid();
897
898 int bin_count = fIntervalCount, cur_hist = 0;
899 // create histograms for particle multiplicities
900 map<int, TH1I*> mapParticleNumberHists;
901 for (int particle_number : fParticles) {
902 TH1I* hParticleNumber =
903 new TH1I(TString::Format("hParticleNumber_%d", particle_number),
904 TString::Format("hParticleNumber_%d", particle_number), bin_count, fPMin, fPMax);
905 // gStyle->SetTitleFontSize(0.03); // only one approach to change histogram title size
906 hParticleNumber->SetStats(kFALSE);
907 hParticleNumber->LabelsDeflate();
908 hParticleNumber->SetLabelFont(62);
909 hParticleNumber->SetMarkerSize(0.6);
910 // hParticleNumber->LabelsOption("v");
911 hParticleNumber->SetTitle("");
912 hParticleNumber->GetXaxis()->SetTitle("momentum interval");
913 hParticleNumber->GetXaxis()->SetTitleSize(0.03);
914 hParticleNumber->GetXaxis()->CenterTitle();
915 hParticleNumber->GetXaxis()->SetLabelSize(0.02 - 0.00017 * bin_count);
916 // hParticleNumber->GetXaxis()->CenterLabels();
917 hParticleNumber->GetXaxis()->SetNdivisions(bin_count);
918 hParticleNumber->GetYaxis()->SetTitle("particle multiplicity");
919 // hParticleNumber->GetYaxis()->SetTitleSize(0.03);
920 // hParticleNumber->GetYaxis()->SetNdivisions(1007);
921 hParticleNumber->GetYaxis()->SetLabelSize(0.02);
922 hParticleNumber->SetBarWidth(0.18);
923 hParticleNumber->SetBarOffset(0.05 + cur_hist * 0.18);
924 switch (cur_hist) {
925 case 0:
926 hParticleNumber->SetFillColor(49);
927 break;
928 case 1:
929 hParticleNumber->SetFillColor(50);
930 break;
931 case 2:
932 hParticleNumber->SetFillColor(42);
933 break;
934 case 3:
935 hParticleNumber->SetFillColor(29);
936 break;
937 case 4:
938 hParticleNumber->SetFillColor(36);
939 break;
940 default:
941 break;
942 }
943
944 mapParticleNumberHists[particle_number] = hParticleNumber;
945 cur_hist++;
946 }
947
948 // create histograms for P, Pt, Y, Eta, Theta, Phi
949 map<int, TH1D*> mapPHists, mapPtHists, mapYHists, mapEtaHists, mapThetaHists, mapPhiHists;
950 for (int particle_number : fParticles) {
951 TH1D* hP = new TH1D(TString::Format("hP_%d", particle_number), TString::Format("hP_%d", particle_number), 80,
952 fPMin, fPMax);
953 mapPHists[particle_number] = hP;
954 TH1D* hPt = new TH1D(TString::Format("hPt_%d", particle_number), TString::Format("hPt_%d", particle_number), 60,
955 fPtMin, fPtMax);
956 mapPtHists[particle_number] = hPt;
957 TH1D* hY = new TH1D(TString::Format("hY_%d", particle_number), TString::Format("hY_%d", particle_number), 60,
958 fYMin, fYMax);
959 mapYHists[particle_number] = hY;
960 TH1D* hEta = new TH1D(TString::Format("hEta_%d", particle_number), TString::Format("hEta_%d", particle_number),
961 60, fEtaMin, fEtaMax);
962 mapEtaHists[particle_number] = hEta;
963 TH1D* hTheta = new TH1D(TString::Format("hTheta_%d", particle_number),
964 TString::Format("hTheta_%d", particle_number), 61, fThetaMin, fThetaMax);
965 mapThetaHists[particle_number] = hTheta;
966 TH1D* hPhi = new TH1D(TString::Format("hPhi_%d", particle_number), TString::Format("hPhi_%d", particle_number),
967 64, fPhiMin, fPhiMax);
968 mapPhiHists[particle_number] = hPhi;
969 }
970
971 int iEventNumber = dataChain.GetEntries(), iCurrentEvent = 0;
972 if (iEventNumber < 1) {
973 cout << "WARNING: There are no correct entries in the file list stored at: \"" << input_list_file << "\""
974 << endl;
975 return 0;
976 }
977
978 // fill all the histograms
979 for (iCurrentEvent = 0; iCurrentEvent < iEventNumber; iCurrentEvent++) {
980 // Next Event
981 if ((iCurrentEvent + 1) % 1000 == 0)
982 LOG(info) << "Processing event #" << iCurrentEvent + 1 << " of " << iEventNumber;
983 dataChain.GetEntry(iCurrentEvent);
984
985 Int_t track_count = 0;
986 TClonesArray* mc_tracks = nullptr;
987 if (isDST) {
988 mc_tracks = mcInfo->GetMCTracks();
989 track_count = globalTracks->GetEntries();
990 } else {
991 mc_tracks = mcTracks;
992 track_count = mc_tracks->GetEntries();
993 }
994
995 // Getting tracks of the event and their corresponding components
996 for (Int_t iTrack = 0; iTrack < track_count; iTrack++) {
997 Int_t track_pdg = -1, track_mass = -1;
998 Double_t track_p = 0, track_pt = 0, track_y = 0, track_eta = 0, track_theta = 0, track_phi = 0;
999 CbmMCTrack* mc_track;
1000 BmnGlobalTrack* global_track;
1001
1002 if (isDST) {
1003 // cout<<"iTrack = "<<iTrack<<", track_count = "<<track_count<<endl;
1004 global_track = (BmnGlobalTrack*)globalTracks->UncheckedAt(iTrack);
1005 if (!global_track->IsPrimary())
1006 continue;
1007
1008 // get corresponding MC track to define PDG
1009 Int_t mc_index = global_track->GetRefIndex();
1010 if (mc_index > -1) {
1011 mc_track = (CbmMCTrack*)mc_tracks->At(mc_index);
1012 track_pdg = mc_track->GetPdgCode();
1013 track_mass = mc_track->GetMass();
1014 } else {
1015 track_pdg = global_track->GetPDG();
1016 if (track_pdg != 0) {
1017 TDatabasePDG* pdg_db = TDatabasePDG::Instance();
1018 TParticlePDG* part_pdg = pdg_db->GetParticle(track_pdg);
1019 if (part_pdg)
1020 track_mass = part_pdg->Mass();
1021 else {
1022 cout << "WARNING: PDG code was not found in the PDG database: " << track_pdg << endl;
1023 continue;
1024 }
1025 } else {
1026 Double_t mass_tof = global_track->GetMass2(1);
1027 if (mass_tof == -1000.0) {
1028 mass_tof = global_track->GetMass2(2);
1029 if (mass_tof == -1000.0) {
1030 // cout << "WARNING: the particle was not identified by the TOF detectors " << endl;
1031 continue;
1032 }
1033 }
1034 // cout<<"Get PDG for mass: "<<mass_tof<<" with tolerance 50 MeV"<<endl;
1035 track_pdg = GetPDGCodeByMass(mass_tof, -0.03, fParticles);
1036 if (track_pdg == 0) {
1037 // cout << "WARNING: the particle PDG code was not defined for its mass = " <<mass_tof<<
1038 // endl;
1039 continue;
1040 }
1041 } // if (track_pdg == 0)
1042 } // if (mc_index == -1)
1043
1044 // Getting track params predicted by Kalman filter ...
1045 FairTrackParam* parFirst = global_track->GetParamFirst();
1046 // FairTrackParam* parLast = track->GetParamLast();
1047 Double_t track_qp = parFirst->GetQp();
1048 track_p = (TMath::Abs(track_qp) > 1.e-4) ? 1. / TMath::Abs(track_qp) : 1.e4;
1049 TVector3 vecMom;
1050 parFirst->Momentum(vecMom);
1051 track_pt = TMath::Sqrt(vecMom.x() * vecMom.x() + vecMom.y() * vecMom.y());
1052 Double_t e = TMath::Sqrt(track_p * track_p + track_mass * track_mass);
1053 track_y = 0.5 * TMath::Log((e + vecMom.z()) / (e - vecMom.z()));
1054 track_eta = 0.5 * TMath::Log((track_p + vecMom.z()) / (track_p - vecMom.z()));
1055 track_phi = TMath::ATan2(parFirst->GetTy(), parFirst->GetTx()); // phi = arctan(tgy/tgx)
1056 track_theta = TMath::ATan2(parFirst->GetTx(), TMath::Cos(track_phi)); // theta = arctan(tgx/cos(phi))
1057 } // if (isDST)
1058 else
1059 {
1060 mc_track = (CbmMCTrack*)mc_tracks->At(iTrack);
1061 if (mc_track->GetMotherId() >= 0)
1062 continue;
1063
1064 // filter particles
1065 if (iParticleCut > 0) {
1066 // exclude tracks without points in Silicon and GEMs
1067 if ((mc_track->GetNPoints(kGEM) < 1) || (mc_track->GetNPoints(kSILICON) < 1))
1068 continue;
1069 if (iParticleCut > 1) {
1070 // exclude tracks without points in ToF detectors
1071 if ((mc_track->GetNPoints(kTOF) < 1) && (mc_track->GetNPoints(kTOF1) < 1)
1072 && (mc_track->GetNPoints(kTOF701) < 1))
1073 continue;
1074 }
1075 }
1076
1077 track_pdg = mc_track->GetPdgCode();
1078 track_p = mc_track->GetP();
1079 track_pt = mc_track->GetPt();
1080 track_y = mc_track->GetRapidity();
1081 track_eta = 0.5 * TMath::Log((track_p + mc_track->GetPz()) / (track_p - mc_track->GetPz()));
1082 track_theta = TMath::ATan2(track_pt, mc_track->GetPz());
1083 track_phi = TMath::ATan2(mc_track->GetPy(), mc_track->GetPx());
1084 } // if not (isDST)
1085
1086 auto iter_pdg = find(fParticles.begin(), fParticles.end(), track_pdg);
1087 if (iter_pdg == fParticles.end())
1088 continue;
1089
1090 if ((track_p >= fPMin) && (track_p < fPMax)) {
1091 mapParticleNumberHists[*iter_pdg]->Fill(track_p);
1092 mapPHists[*iter_pdg]->Fill(track_p);
1093 mapPtHists[*iter_pdg]->Fill(track_pt);
1094 mapYHists[*iter_pdg]->Fill(track_y);
1095 mapEtaHists[*iter_pdg]->Fill(track_eta);
1096 mapThetaHists[*iter_pdg]->Fill(track_theta);
1097 mapPhiHists[*iter_pdg]->Fill(track_phi);
1098 }
1099 } // for (Int_t iTrack = 0; iTrack < track_count; iTrack++)
1100 } // for (Int_t iEvent = 0; iEvent < iEventNumber; iEvent++) {
1101
1102 // if no required branches in the tree or events then clear memory and exit
1103 if (iCurrentEvent == 0) {
1104 cout << "ERROR: There are no necessary tree branches or DST events in the files from the list: "
1105 << input_list_file << endl;
1106 for (const auto& pair : mapPHists)
1107 delete pair.second;
1108 for (const auto& pair : mapPtHists)
1109 delete pair.second;
1110 for (const auto& pair : mapYHists)
1111 delete pair.second;
1112 for (const auto& pair : mapEtaHists)
1113 delete pair.second;
1114 for (const auto& pair : mapThetaHists)
1115 delete pair.second;
1116 for (const auto& pair : mapPhiHists)
1117 delete pair.second;
1118 delete c_number;
1119 return 0;
1120 }
1121
1122 // find max Y-axis value
1123 Double_t max_y_value = 0;
1124 for (const auto& pair_hist : mapParticleNumberHists) {
1125 if (max_y_value < pair_hist.second->GetMaximum())
1126 max_y_value = pair_hist.second->GetMaximum();
1127 }
1128
1129 // draw bar histogram with particle multiplicity for all the particle types
1130 TLegend* legend = new TLegend(0.7, 0.74, 0.85, 0.88);
1131 TString hist_options = "bar2,hist,text"; // 'text' option for vertical captions with event count
1132 cur_hist = 0;
1133 for (const auto& pair_hist : mapParticleNumberHists) {
1134 if (cur_hist == 0) {
1135 if (pair_hist.second->GetMaximum() < max_y_value)
1136 pair_hist.second->SetMaximum(max_y_value + 10);
1137 pair_hist.second->DrawCopy(hist_options);
1138 } else {
1139 pair_hist.second->DrawCopy(hist_options + ",same");
1140 }
1141
1142 legend->AddEntry(pair_hist.second, TString::Format("Multiplitcity for %d", pair_hist.first), "f");
1143 legend->Draw();
1144 cur_hist++;
1145 }
1146
1147 // draw histograms (P, Pt, Y, Eta, Theta, Phi) for different particle types
1148 TCanvas* c_p = new TCanvas("c_p", "Particle Momentum", 1000, 500);
1149 c_p->Divide((fParticles.size() / 3) + 1, 3);
1150 cur_hist = 1;
1151 for (int particle_number : fParticles) {
1152 c_p->cd(cur_hist);
1153 mapPHists[particle_number]->Draw();
1154 cur_hist++;
1155 }
1156 TCanvas* c_pt = new TCanvas("c_pt", "Transverse Momentum", 1000, 500);
1157 c_pt->Divide((fParticles.size() / 3) + 1, 3);
1158 cur_hist = 1;
1159 for (int particle_number : fParticles) {
1160 c_pt->cd(cur_hist);
1161 mapPtHists[particle_number]->Draw();
1162 cur_hist++;
1163 }
1164 TCanvas* c_y = new TCanvas("c_y", "Rapidity", 1000, 500);
1165 c_y->Divide((fParticles.size() / 3) + 1, 3);
1166 cur_hist = 1;
1167 for (int particle_number : fParticles) {
1168 c_y->cd(cur_hist);
1169 mapYHists[particle_number]->Draw();
1170 cur_hist++;
1171 }
1172 TCanvas* c_eta = new TCanvas("c_eta", "Pseudorapidity", 1000, 500);
1173 c_eta->Divide((fParticles.size() / 3) + 1, 3);
1174 cur_hist = 1;
1175 for (int particle_number : fParticles) {
1176 c_eta->cd(cur_hist);
1177 mapEtaHists[particle_number]->Draw();
1178 cur_hist++;
1179 }
1180 TCanvas* c_theta = new TCanvas("c_theta", "Theta angle", 1000, 500);
1181 c_theta->Divide((fParticles.size() / 3) + 1, 3);
1182 cur_hist = 1;
1183 for (int particle_number : fParticles) {
1184 c_theta->cd(cur_hist);
1185 mapThetaHists[particle_number]->Draw();
1186 cur_hist++;
1187 }
1188 TCanvas* c_phi = new TCanvas("c_phi", "Phi Angle", 1000, 500);
1189 c_phi->Divide((fParticles.size() / 3) + 1, 3);
1190 cur_hist = 1;
1191 for (int particle_number : fParticles) {
1192 c_phi->cd(cur_hist);
1193 mapPhiHists[particle_number]->Draw();
1194 cur_hist++;
1195 }
1196
1197 return 0;
1198}
Double_t fThetaMax
Double_t fYMin
Double_t fPtMin
Double_t fYMax
Double_t fPhiMin
Double_t fEtaMax
Double_t fPtMax
Double_t fEtaMin
Double_t fPhiMax
Double_t fThetaMin
int i
Definition P4_F32vec4.h:22
float f
Definition P4_F32vec4.h:21
@ kSILICON
@ kGEM
@ kTOF
@ kTOF1
@ kTOF701
Double_t GetMass2(Int_t tofID)
Bool_t IsPrimary() const
TClonesArray * GetMCTracks() const
rot. around z-axis [rad]
static int FitEtaHistogram(unique_ptr< TH1D > &hEta, int pdg_key, Double_t eta_min, Double_t eta_max)
BmnParticleEqualizer(TString hist_file_name)
static int ShowSampleHistograms(TString input_histo_file="$VMCWORKDIR/macro/recotools/particle_hists.root")
static void FitSampleHistograms(TString input_histo_file="$VMCWORKDIR/macro/recotools/particle_hists.root")
static int FitPHistogram(unique_ptr< TH1D > &hP, int pdg_key, Double_t p_min, Double_t p_max)
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)
virtual Bool_t ReadEvent(FairPrimaryGenerator *primGen)
static int ShowResultDistributions(TString input_list_file)
static int ProduceSampleHistograms(TString input_list_file, TString output_histo_file="$VMCWORKDIR/macro/recotools/particle_hists.root")
static int FitYHistogram(unique_ptr< TH1D > &hY, int pdg_key, Double_t &y0_output, Double_t &sigma_putput)
FairTrackParam * GetParamFirst()
Definition BmnTrack.h:72
Double_t GetMass() const
Double_t GetPy() const
Definition CbmMCTrack.h:59
Long64_t GetNPoints(DetectorId detId) const
Double_t GetPt() const
Definition CbmMCTrack.h:67
Double_t GetPz() const
Definition CbmMCTrack.h:60
Double_t GetPx() const
Definition CbmMCTrack.h:58
Double_t GetRapidity() const
Int_t GetMotherId() const
Definition CbmMCTrack.h:57
Double_t GetP() const
Definition CbmMCTrack.h:68
Int_t GetPdgCode() const
Definition CbmMCTrack.h:56
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)
vector< unique_ptr< TH1D > > fPHistVector
P histograms for the particle type (divided by momentum intervals -> vector)
vector< Int_t > fParticleNumber
PDG -> Particle Count (divided by momentum intervals -> vector)