FairShip
Loading...
Searching...
No Matches
MuonBackGenerator.cxx
Go to the documentation of this file.
1// SPDX-License-Identifier: LGPL-3.0-or-later
2// SPDX-FileCopyrightText: Copyright CERN for the benefit of the SHiP
3// Collaboration
4
5#include "MuonBackGenerator.h"
6
7#include <algorithm>
8#include <cmath>
9#include <unordered_map>
10
11#include "BeamSmearingUtils.h"
12#include "FairPrimaryGenerator.h"
13#include "ShipMCTrack.h"
14#include "ShipUnit.h"
15#include "TChain.h"
16#include "TDatabasePDG.h" // for TDatabasePDG
17#include "TFile.h"
18#include "TMCProcess.h"
19#include "TMath.h" // for Sqrt
20#include "TROOT.h"
21#include "TRandom.h"
22#include "TSystem.h"
23#include "TVector.h"
24#include "TVirtualMC.h"
25#include "vetoPoint.h"
26
27using ShipUnit::cm;
28using ShipUnit::mm;
29// read events from Pythia8/Geant4 base simulation (only target + hadron
30// absorber
31
32// ----- Default constructor -------------------------------------------
34 : MCTrack_vec(nullptr), vetoPoints_vec(nullptr), fUseSTL(false) {
35 followMuons = true;
36}
37// -------------------------------------------------------------------------
38// ----- Default constructor -------------------------------------------
39Bool_t MuonBackGenerator::Init(const char* fileName) {
40 return Init(fileName, 0);
41}
42
43Bool_t MuonBackGenerator::Init(const std::vector<std::string>& fileNames) {
44 return Init(fileNames, 0);
45}
46
47Bool_t MuonBackGenerator::Init(const std::vector<std::string>& fileNames,
48 const int startEvent) {
49 LOG(info) << "Opening input file to find keys " << fileNames.at(0);
50 TFile testFile(fileNames.at(0).c_str());
51 auto testKeys = testFile.GetListOfKeys();
52 if (testKeys == nullptr) {
53 LOG(fatal) << "Error opening the Signal file: " << fileNames.at(0);
54 }
55 fn = startEvent;
56 fPaintBeam = 5 * cm; // default value for painting beam
57 fSameSeed = 0;
58 fPhiRandomize = false; // default value for phi randomization
59 fsmearBeam = 8 * mm; // default value for smearing beam
60 fdownScaleDiMuon = kFALSE; // only needed for muflux simulation
61 if (testKeys->FindObject("pythia8-Geant4")) {
62 fTree = new TChain("pythia8-Geant4");
63 for (auto& f : fileNames) {
64 LOG(info) << "Opening input file " << f;
65 fTree->Add(f.c_str());
66 }
67 fNevents = fTree->GetEntries();
68 LOG(info) << "Reading " << fNevents << " entries";
69 // count only events with muons
70 fTree->SetBranchAddress("id", &id); // particle id
71 fTree->SetBranchAddress("parentid",
72 &parentid); // parent id, could be different
73 fTree->SetBranchAddress("pythiaid",
74 &pythiaid); // pythiaid original particle
75 fTree->SetBranchAddress("ecut", &ecut); // energy cut used in simulation
76 fTree->SetBranchAddress("w", &w); // weight of event
77 // check if ntuple has information of momentum at origin
78 if (fTree->GetListOfLeaves()->GetSize() < 17) {
79 fTree->SetBranchAddress(
80 "x", &vx); // position with respect to startOfTarget at -89.27m
81 fTree->SetBranchAddress("y", &vy);
82 fTree->SetBranchAddress("z", &vz);
83 fTree->SetBranchAddress("px", &px); // momentum
84 fTree->SetBranchAddress("py", &py);
85 fTree->SetBranchAddress("pz", &pz);
86 } else {
87 fTree->SetBranchAddress(
88 "ox", &vx); // position with respect to startOfTarget at -50m
89 fTree->SetBranchAddress("oy", &vy);
90 fTree->SetBranchAddress("oz", &vz);
91 fTree->SetBranchAddress("opx", &px); // momentum
92 fTree->SetBranchAddress("opy", &py);
93 fTree->SetBranchAddress("opz", &pz);
94 }
95 } else {
96 id = -1;
97 fTree = new TChain("cbmsim");
98 for (auto& f : fileNames) {
99 LOG(info) << "Opening input file " << f;
100 fTree->Add(f.c_str());
101 }
102 fNevents = fTree->GetEntries();
103 LOG(info) << "Reading " << fNevents << " entries";
104 // Detect format by checking branch name:
105 // STL format uses PlaneHAPoint, TClonesArray uses vetoPoint
106 TBranch* mcBranch = fTree->GetBranch("MCTrack");
107 if (!mcBranch) {
108 LOG(fatal) << "MCTrack branch not found in input file";
109 }
110
111 if (fTree->GetBranch("PlaneHAPoint")) {
112 // New STL format
113 fUseSTL = true;
114 MCTrack_vec = nullptr;
115 vetoPoints_vec = nullptr;
116 auto mcStatus = fTree->SetBranchAddress("MCTrack", &MCTrack_vec);
117 auto vetoStatus =
118 fTree->SetBranchAddress("PlaneHAPoint", &vetoPoints_vec);
119 if (mcStatus < 0 || vetoStatus < 0) {
120 LOG(fatal) << "Failed to set branch addresses for STL vector format";
121 }
122 LOG(info) << "Using STL vector format (PlaneHAPoint)";
123 } else if (fTree->GetBranch("vetoPoint")) {
124 // Old TClonesArray format
125 fUseSTL = false;
126 MCTrack = new TClonesArray("ShipMCTrack");
127 vetoPoints = new TClonesArray("vetoPoint");
128 auto mcStatus = fTree->SetBranchAddress("MCTrack", &MCTrack);
129 auto vetoStatus = fTree->SetBranchAddress("vetoPoint", &vetoPoints);
130 if (mcStatus < 0 || vetoStatus < 0) {
131 LOG(fatal) << "Failed to set branch addresses for TClonesArray format";
132 }
133 LOG(info) << "Using TClonesArray format (vetoPoint)";
134 } else {
135 LOG(fatal)
136 << "Neither PlaneHAPoint nor vetoPoint branch found in input file";
137 }
138 }
139 return kTRUE;
140}
141
142// ----- Default constructor -------------------------------------------
143Bool_t MuonBackGenerator::Init(const char* fileName, const int startEvent) {
144 std::vector<std::string> fileNames = {fileName};
145 return Init(fileNames, startEvent);
146}
147// ----- Destructor ----------------------------------------------------
149 if (!fUseSTL) {
150 delete MCTrack;
151 delete vetoPoints;
152 }
153}
154// -------------------------------------------------------------------------
155Bool_t MuonBackGenerator::checkDiMuon(Int_t muIndex) {
156 ShipMCTrack* mu = fUseSTL ? &(*MCTrack_vec)[muIndex]
157 : dynamic_cast<ShipMCTrack*>(MCTrack->At(muIndex));
158 TString pName = mu->GetProcName();
159 if (strncmp("Hadronic inelastic", pName.Data(), 18) == 0 ||
160 strncmp("Positron annihilation", pName.Data(), 21) == 0 ||
161 strncmp("Lepton pair production", pName.Data(), 22) == 0) {
162 return true;
163 }
164 Int_t motherId = mu->GetMotherId();
165 if (motherId < 0) {
166 return false;
167 }
168 ShipMCTrack* mother = fUseSTL
169 ? &(*MCTrack_vec)[motherId]
170 : dynamic_cast<ShipMCTrack*>(MCTrack->At(motherId));
171 Int_t Pcode = TMath::Abs(mother->GetPdgCode());
172 return (Pcode == 221 || Pcode == 223 || Pcode == 333 || Pcode == 113 ||
173 Pcode == 331);
174}
175
176// ----- Passing the event ---------------------------------------------
177Bool_t MuonBackGenerator::ReadEvent(FairPrimaryGenerator* cpg) {
178 auto* pdgBase = TDatabasePDG::Instance();
179 Double_t mass = 0., e = 0., tof = 0.;
180 std::unordered_map<int, int> muList;
181 std::unordered_map<int, std::vector<int>> moList;
182
183 // Helper lambdas to abstract STL vs TClonesArray access
184 auto getVetoSize = [this]() -> int {
185 return fUseSTL ? vetoPoints_vec->size() : vetoPoints->GetEntries();
186 };
187 auto getVetoPoint = [this](int i) -> vetoPoint* {
188 return fUseSTL ? &(*vetoPoints_vec)[i]
189 : dynamic_cast<vetoPoint*>(vetoPoints->At(i));
190 };
191 auto getMCTrack = [this](int i) -> ShipMCTrack* {
192 return fUseSTL ? &(*MCTrack_vec)[i]
193 : dynamic_cast<ShipMCTrack*>(MCTrack->At(i));
194 };
195 auto getMCTrackSize = [this]() -> int {
196 return fUseSTL ? MCTrack_vec->size() : MCTrack->GetEntries();
197 };
198
199 bool found_muon = false;
200 while (fn < fNevents) {
201 fTree->GetEntry(fn);
202 muList.clear();
203 moList.clear();
204 fn++;
205 if (fn % 100000 == 0) {
206 LOGF(info, "Reading event %i", fn);
207 }
208 // test if we have a muon, don't look at neutrinos:
209 if (TMath::Abs(static_cast<int>(id)) == 13) {
210 mass = pdgBase->GetParticle(id)->Mass();
211 e = TMath::Sqrt(px * px + py * py + pz * pz + mass * mass);
212 tof = 0;
213 found_muon = true;
214 break;
215 }
216 if (id == -1) { // use tree as input file
217 Bool_t found = false;
218 for (int i = 0; i < getVetoSize(); i++) {
219 auto* v = getVetoPoint(i);
220 Int_t abspid = TMath::Abs(v->PdgCode());
221 if (abspid == 13 || (!followMuons && abspid != 12 && abspid != 14)) {
222 found = true;
223 Int_t muIndex = v->GetTrackID();
224 if (!fdownScaleDiMuon) {
225 muList.insert({muIndex, i});
226 } else if (abspid == 13) {
227 if (checkDiMuon(muIndex)) {
228 moList[getMCTrack(muIndex)->GetMotherId()].push_back(i);
229 } else {
230 muList.insert({muIndex, i});
231 }
232 }
233 }
234 }
235 // reject muon if comes from boosted channel
236
237 for (auto it = moList.begin(); it != moList.end(); it++) {
238 if (gRandom->Uniform(0., 1.) > 0.99) {
239 std::vector<int> list = it->second;
240 for (unsigned i = 0; i < list.size(); i++) {
241 auto* v = getVetoPoint(list.at(i));
242 Int_t muIndex = v->GetTrackID();
243 muList.insert({muIndex, i});
244 }
245 }
246 }
247 if (!found) {
248 LOGF(debug, "No muon found %i", fn - 1);
249 }
250 if (found) {
251 found_muon = true;
252 break;
253 }
254 }
255 }
256 if (fn >= fNevents && !found_muon) {
257 LOGF(info, "End of tree reached %i", fNevents);
258 gMC->StopRun();
259 return kTRUE;
260 }
261 if (fSameSeed) {
262 Int_t theSeed = fn + fSameSeed * fNevents;
263 LOGF(debug, "Seed: %d", theSeed);
264 gRandom->SetSeed(theSeed);
265 }
266 auto [dx, dy] = CalculateBeamOffset(fsmearBeam, fPaintBeam);
267 if (id == -1) {
268 for (int i = 0; i < getMCTrackSize(); i++) {
269 auto* track = getMCTrack(i);
270 Int_t abspid = TMath::Abs(track->GetPdgCode());
271 px = track->GetPx();
272 py = track->GetPy();
273 pz = track->GetPz();
274 if (fPhiRandomize) {
275 double phi_random = gRandom->Uniform(0., 2 * TMath::Pi());
276 Double_t pt = track->GetPt();
277 px = pt * TMath::Cos(phi_random);
278 py = pt * TMath::Sin(phi_random);
279 }
280 vx = track->GetStartX() + dx;
281 vy = track->GetStartY() + dy;
282 vz = track->GetStartZ();
283 tof = track->GetStartT() / 1E9; // convert back from ns to sec;
284 e = track->GetEnergy();
285 Bool_t wanttracking = false; // only transport muons
286 for (std::pair<int, int> element : muList) {
287 if (element.first == i) {
288 wanttracking = true;
289 if (!followMuons) {
290 auto* v = getVetoPoint(element.second);
291 TVector3 lpv = v->LastPoint();
292 TVector3 lmv = v->LastMom();
293 if (abspid == 22) {
294 e = lmv.Mag();
295 } else {
296 e = TMath::Sqrt(lmv.Mag2() +
297 (track->GetMass()) * (track->GetMass()));
298 }
299 px = lmv[0];
300 py = lmv[1];
301 pz = lmv[2];
302 vx = lpv[0];
303 vy = lpv[1];
304 vz = lpv[2];
305 tof = v->GetTime() / 1E9; // convert back from ns to sec
306 }
307 break;
308 }
309 }
310 cpg->AddTrack(track->GetPdgCode(), px, py, pz, vx, vy, vz,
311 track->GetMotherId(), wanttracking, e, tof,
312 track->GetWeight(), (TMCProcess)track->GetProcID());
313 }
314 } else {
315 vx += dx / 100.;
316 vy += dy / 100.;
317 if (fPhiRandomize) {
318 double phi_random = gRandom->Uniform(0., 2 * TMath::Pi());
319 Double_t pt = TMath::Sqrt(px * px + py * py);
320 px = pt * TMath::Cos(phi_random);
321 py = pt * TMath::Sin(phi_random);
322 }
323 cpg->AddTrack(static_cast<int>(pythiaid), px, py, pz, vx * 100., vy * 100.,
324 vz * 100., -1., false, e, pythiaid, parentid);
325 cpg->AddTrack(static_cast<int>(id), px, py, pz, vx * 100., vy * 100.,
326 vz * 100., -1., true, e, tof, w);
327 }
328 return kTRUE;
329}
330
331// -------------------------------------------------------------------------
334 fInputFile->Close();
335 fInputFile->Delete();
336 delete fInputFile;
337}
std::pair< Double_t, Double_t > CalculateBeamOffset(Double_t smearBeam, Double_t paintBeam)
const Int_t debug
Double_t cm
Double_t mm
TClonesArray * MCTrack
TClonesArray * vetoPoints
Bool_t checkDiMuon(Int_t muIndex)
std::vector< vetoPoint > * vetoPoints_vec
Bool_t ReadEvent(FairPrimaryGenerator *) override
TFile * fInputFile
flag to indicate if using STL vectors
std::vector< ShipMCTrack > * MCTrack_vec
Bool_t Init(const char *, int) override
Int_t GetPdgCode() const
Definition: ShipMCTrack.h:53