CbmRoot
Loading...
Searching...
No Matches
LmvmEventMix.cxx
Go to the documentation of this file.
1/* Copyright (C) 2023-2025 UGiessen, Giessen
2 SPDX-License-Identifier: GPL-3.0-only
3 Authors: Cornelius Feier-Riesen [committer] */
4
5#include "LmvmEventMix.h"
6
7#include "CbmHistManager.h"
8#include "CbmUtils.h"
9#include "LmvmDef.h"
10#include "LmvmKinePar.h"
11#include "LmvmSimParam.h"
12#include "LmvmUtils.h"
13#include "TF1.h"
14#include "TFile.h"
15#include "TH1.h"
16#include "TH1D.h"
17#include "TH2D.h"
18#include "TStopwatch.h"
19#include "TSystem.h"
20#include "TSystemDirectory.h"
21
22#include <iomanip>
23#include <iostream>
24#include <string>
25
26using namespace std;
27using namespace Cbm;
28
29/*********************************************************************************************************************
30* This class is for providing invariant mass histograms from same and mixed events for like-sign and unlike-sign *
31* pairs to be used for the calculation of the combinatorial background in LmvmDrawAll. For this, in the analysis *
32* (LmvmTask) a root file is created that contains one vector<LmvmCand> (stored in file "lmvmcand.taskId.root") filled*
33* with all LmvmCand candidates obtained in one job (max. 1000 events). From LmvmCand all necessary information can be*
34* obtained for the required histograms. The parameter 'fNofFilesToMix' determines how many files are used for event *
35* mixing. That means, if fNofFilesToMix=10 and each file contains 1,000 events, the mixing depth is 10,000 events. *
36* In the same-event loop a 'vector<LmvmCand> candsSame' is filled with the vector elements extracted from the file *
37* with number 'taskId' and handed over to the function FillMinvHistos() with option "same". In the mixed-event loop *
38* a 'vector<LmvmCand> candsMix' is filled with the vector elements of exactly fNofFilesToMix files, starting at file *
39* #taskId until file #taskId+fNofFilesToMix-1. If one of these files can not be opened or does not exist, the range *
40* is extended by 1 to make sure to mix exactly fNofFilesToMix files. After that, candsMix is handed over to *
41* FillMinvHistos() with the option "mix". *
42* In FillMinvHistos() the invariant mass for each possible pair combination is calculated and filled into an *
43* according histogram (like-sign or unlike-sign pair, same or mixed events). *
44**********************************************************************************************************************/
45
46void LmvmEventMix::DoEventMix(const string& dataDir, const string& outputDir, const string& outFile,
47 const string& taskIdStr, int nofFilesToMix)
48{
50
51 fDataDir = dataDir;
52 fOutputDir = outputDir;
53 fFileName = outFile;
54 fNofFilesToMix = nofFilesToMix;
55 int taskId = std::stoi(taskIdStr);
56 cout << endl;
57 LOG(info) << "LmvmEventMix::DoEventMix: Energy string = " << fEnergy
58 << ". Mind this for calculation of weighting values!" << endl;
59 fHMean.FillH1("hmx_nofJobs", 0.5);
60
61 TStopwatch timer;
62 timer.Start();
63
64 // Choose signal (only one of five signals per run)
65 int iSig = taskId % fHMean.fNofSignals;
66 fSignal = fHMean.fSignalNames[iSig];
67 LOG(info) << "taskId = " << taskId << ", iSig = " << iSig << ", fSignal = " << fSignal;
68
69 // Correct assignment of folder names to number 'iSig' is essential!
70 string folder = (iSig == 0) ? "inmed/"
71 : (iSig == 1) ? "qgp/"
72 : (iSig == 2) ? "omegaepem/"
73 : (iSig == 3) ? "phi/"
74 : (iSig == 4) ? "omegadalitz/"
75 : "";
76 if (folder == "") LOG(error) << "LmvmEventMix::DoEventMix(): No folder name specified. Check!";
77
78 // Get lmvmcand file with highest number; needed in mixed-event loop
79 int iFileMax = 0;
80 for (int iF = 1; iF <= 1000; iF++) {
81 string iFString = Cbm::NumberToString(iF, 0);
82 string filename = fDataDir + folder + "lmvmcand." + iFString + ".root";
83 TFile* file(TFile::Open(filename.c_str()));
84 if (file) iFileMax = iF;
85 }
86 LOG(info) << "iFileMax = " << iFileMax;
87
88 // Filling candidate vectors (same and mixed events)
89
90 // Loop for same events (use each file exactly once)
91 vector<LmvmCand> candsSame;
92 fNofEvents = 0;
93 for (const string name : {"inmed", "omegaepem", "omegadalitz", "phi", "qgp"}) {
94 candsSame.clear();
95 string filename = fDataDir + name + "/lmvmcand." + taskIdStr + ".root";
96 TFile* file(TFile::Open(filename.c_str()));
97 if (!file) {
98 LOG(info) << "file " << filename << " cannot be opened.";
99 continue;
100 }
101 vector<LmvmCand>* cands(file->Get<vector<LmvmCand>>("fCandsTotal"));
102 if (cands != nullptr) {
103 LOG(info) << "File taken for same events: " << filename;
104 candsSame.insert(candsSame.end(), cands->begin(), cands->end());
105 string filenameAna = fDataDir + name + "/analysis." + taskIdStr + ".root";
106 TFile* anafile(TFile::Open(filenameAna.c_str()));
107 if (anafile) {
108 TH1D* h(anafile->Get<TH1D>("hEventNumber"));
109 fNofEvents += h->GetEntries();
110 }
111 else
112 LOG(warning) << "LmvmEventMix (loop 'same'): anafile " << filenameAna
113 << " could not be opened or does not exist.";
114 }
115 else
116 LOG(warning) << "LmvmEventMix::DoEventMix(): Loop 'same' with filename = " << filename
117 << ": candsSame = nullptr!";
118 FillMinvHistos(candsSame, "same");
119 }
120
121 // Fill histograms for number of events and number of files
122 // NOTE: why do the first lines not return the right number after 'hadd'??
123 //fHMean.FillH1("hmx_EventNumber", 0.5, static_cast<double>(fNofEvents));
124 //fHMean.FillH1("hmx_NofFilesToMix", 0.5, static_cast<double>(fNofFilesToMix));
125 //fHMean.FillH1("hmx_EventNumber", 0.5, fNofEvents);
126 //fHMean.FillH1("hmx_NofFilesToMix", 0.5, fNofFilesToMix);
127 for (int i = 1; i <= fNofEvents; i++) {
128 fHMean.FillH1("hmx_EventNumber", 0.5);
129 }
130 for (int i = 1; i <= fNofFilesToMix; i++) {
131 fHMean.FillH1("hmx_NofFilesToMix", 0.5);
132 }
133
134 // Loop for mixed events (use exactly fNofFilesToMix files)
135 vector<LmvmCand> candsMix;
136 candsMix.clear();
137 int iter = -1;
138 int nMixedFiles = 0;
139 while (nMixedFiles < fNofFilesToMix) {
140 iter++; // to stop loop if e.g. no file is to open and nMixedFiles would not increase
141 if (iter > 1000) {
142 LOG(error) << "LmvmEventMix::DoEventMix(): iter = " << iter << ". Is too large. Check!";
143 return;
144 }
145 int iFile = (taskId + iter == iFileMax) ? taskId + iter : (taskId + iter) % iFileMax; // because no file #0 exists
146 string iFileString = Cbm::NumberToString(iFile, 0);
147 string filename = fDataDir + folder + "lmvmcand." + iFileString + ".root";
148 TFile* file(TFile::Open(filename.c_str()));
149 if (!file) continue;
150 vector<LmvmCand>* cands(file->Get<vector<LmvmCand>>("fCandsTotal"));
151 if (cands != nullptr) {
152 LOG(info) << "File taken for mixing: " << filename;
153 candsMix.insert(candsMix.end(), cands->begin(), cands->end());
154 nMixedFiles++;
155 }
156 else
157 LOG(warning) << "LmvmEventMix::DoEventMix(): Loop 'mix': filename = " << filename << ", candsMix = nullptr!";
158 }
159 if (nMixedFiles < fNofFilesToMix) LOG(warn) << "nMixedFiles < fNofFilesToMix. Check cause!";
160 FillMinvHistos(candsMix, "mix");
161
162 // Finish
163 double bW = fHMean.H1("hmx_MinvPM_sameEv_elid")->GetBinWidth(1);
164 fHMean.fHM.ScaleByPattern("hmx_Minv.*", 1. / bW);
165
166 int nCandsMix = candsMix.size();
167 int nCandsSame = candsSame.size();
168 LOG(info) << "fNofEvents = " << fNofEvents;
169 LOG(info) << "nCandsSame = " << nCandsSame << ", nCandsMix = " << nCandsMix;
170
171 timer.Stop();
172 LOG(info) << "Real time " << timer.RealTime() << " s, CPU time " << timer.CpuTime() << " s.";
173 fHMean.FillH1("hmx_time", timer.RealTime());
174
175 CheckMemory("End");
176 SaveHist();
177}
178
179void LmvmEventMix::FillMinvHistos(const vector<LmvmCand>& cands, const string& mode)
180{
181 if (mode != "same" && mode != "mix")
182 LOG(error) << "LmvmEventMix::FillMinvHistos: event mode must be 'same' or 'mix'!";
183 int nCands = cands.size();
184 for (int iC1 = 0; iC1 < nCands - 1; iC1++) {
185 const auto& cand1 = cands[iC1];
186 if (cand1.fCharge == 0) LOG(error) << "LmvmEventMix::FillMinvHistos: Charge of cand1 is 0. Check!";
187 for (int iC2 = iC1 + 1; iC2 < nCands; iC2++) {
188 const auto& cand2 = cands[iC2];
189 if (cand2.fCharge == 0) LOG(error) << "LmvmEventMix::FillMinvHistos: Charge of cand2 is 0. Check!";
190 if (cand1.fTaskId == "" || cand2.fTaskId == "")
191 LOG(error) << "LmvmEventMix::FillMinvHistos: String 'fTaskId' of at least one candidate is empty. Check!";
192 bool isSameEvent =
193 (cand1.fEventNumber == cand2.fEventNumber && cand1.fTaskId == cand2.fTaskId && cand1.fName == cand2.fName);
194 if ((mode == "same" && !isSameEvent) || (mode == "mix" && isSameEvent)) continue;
195 string evmode = "";
196 if (mode == "same" && isSameEvent) evmode = "_sameEv";
197 if (mode == "mix" && !isSameEvent) evmode = "_mixedEv";
198 if (evmode == "") {
199 LOG(error) << "LmvmEventMix::FillMinvHistos: string 'evmode' is not defined. Check!";
200 continue;
201 } // TODO: should not occur; delete this line
202 string comb = (cand1.fCharge * cand2.fCharge < 0) ? "PM"
203 : (cand1.fCharge < 0 && cand2.fCharge < 0) ? "MM"
204 : (cand1.fCharge > 0 && cand2.fCharge > 0) ? "PP"
205 : "";
206 if (comb == "")
207 LOG(error)
208 << "LmvmEventMix::FillMinvHistos: 'comb' is empty. Check!"; // TODO: should not occur; delete this line and shorten line before (without last condition)
209
210 double w = (isSameEvent) ? LmvmUtils::GetWeightPair(cand1, cand2) : cand1.fWeight * cand2.fWeight;
211 LmvmKinePar pRec = LmvmKinePar::Create(&cand1, &cand2);
212 for (auto step : fHMean.fAnaSteps) {
213 if (step < ELmvmAnaStep::ElId) continue;
214 if (!(cand1.IsCutTill(step) && cand2.IsCutTill(step))) continue;
215 fHMean.FillH1("hmx_Minv" + comb + evmode, step, pRec.fMinv, w);
216 if (std::abs(cand1.fMcPdg) == 11 && std::abs(cand2.fMcPdg) == 11)
217 fHMean.FillH1("hmx_Minv" + comb + "_trueEl" + evmode, step, pRec.fMinv, w);
218 if (!cand1.IsMcSignal() && !cand2.IsMcSignal())
219 fHMean.FillH1("hmx_Minv" + comb + "_urqmdAll" + evmode, step, pRec.fMinv, w);
220 if (!cand1.IsMcSignal() && !cand2.IsMcSignal() && std::abs(cand1.fMcPdg) == 11 && std::abs(cand2.fMcPdg) == 11)
221 fHMean.FillH1("hmx_Minv" + comb + "_urqmdEl" + evmode, step, pRec.fMinv, w);
222 }
223 }
224 }
225}
226
228{
229 for (const string comb : {"PM", "PP", "MM"}) {
230 string hName = "hmx_Minv" + comb;
231 for (const string cat : {"", "_trueEl", "_urqmdAll", "_urqmdEl"}) {
232 string hNameCat = hName + cat;
233 fHMean.CreateH1(hNameCat, {"sameEv", "mixedEv"}, fHMean.fAnaStepNames, "M_{ee} [GeV/c^{2}]",
234 "dN/dM_{ee}/N_{Ev} [GeV/c^{2}]^{-1}", 250, 0., 2.5, true);
235 }
236 }
237 fHMean.CreateH1("hmx_EventNumber", "", "", 1, 0, 1.); // TODO: needed?
238 fHMean.CreateH1("hmx_nofJobs", "", "", 1, 0, 1.); // for correct scaling in LmvmDrawAll
239 fHMean.CreateH1("hmx_NofFilesToMix", "", "", 1, 0, 1.); // To get mixing depth in LmvmDrawAll
240 fHMean.CreateH1("hmx_time", "Time [s]", "a.u.", 100, 0., 200.);
241}
242
243void LmvmEventMix::CheckMemory(const string& text)
244{
245 static ProcInfo_t info;
246 const float toMB = 1.f / 1024.f;
247 gSystem->GetProcInfo(&info);
248 cout << Form((text + ": Memory res|vir: %g|%g Mbytes\n").c_str(), info.fMemResident * toMB, info.fMemVirtual * toMB);
249 cout << endl;
250}
251
253{
254 if (fOutputDir != "") {
255 gSystem->mkdir(fOutputDir.c_str(), true);
256 TFile* f = TFile::Open(string(fFileName).c_str(), "RECREATE");
257 fHMean.WriteToFile();
258 f->Close();
259 }
260 fHMean.fHM.SaveCanvasToImage(fOutputDir, "png");
261}
262
Histogram manager.
ClassImp(LmvmEventMix)
Generates beam ions for transport simulation.
std::string fFileName
std::string fDataDir
LmvmHist fHMean
std::string fEnergy
std::string fOutputDir
std::string fSignal
void CheckMemory(const std::string &text)
void DoEventMix(const std::string &dataDir, const std::string &outputDir, const std::string &outFile, const std::string &taskIdStr, int nofFilesToMix)
void FillMinvHistos(const std::vector< LmvmCand > &cands, const std::string &mode)
Double_t fMinv
Definition LmvmKinePar.h:20
static LmvmKinePar Create(const CbmMCTrack *mctrackP, const CbmMCTrack *mctrackM)
Definition LmvmKinePar.h:26
static double GetWeightPair(const LmvmCand &cand1, const LmvmCand &cand2)
std::string NumberToString(const T &value, int precision=1)
Definition CbmUtils.h:34
Hash for CbmL1LinkKey.