FairShip
Loading...
Searching...
No Matches
make_nTuple_Tr.py
Go to the documentation of this file.
1#!/usr/bin/env python
2# SPDX-License-Identifier: LGPL-3.0-or-later
3# SPDX-FileCopyrightText: Copyright CERN for the benefit of the SHiP Collaboration
4
5"""Script to collect muons hitting the 1st Tracking Station (including soft interaction products) to a ROOT file."""
6
7import argparse
8import csv
9import logging
10import os
11
12import ROOT as r
13import shipunit as u
14from tabulate import tabulate
15
16pdg = r.TDatabasePDG.Instance()
17
18
19logging.basicConfig(level=logging.INFO)
20
21
22parser = argparse.ArgumentParser(description=__doc__)
23parser.add_argument("--test", dest="testing_code", help="Run Test", action="store_true")
24parser.add_argument(
25 "-o",
26 "--outputfile",
27 default="muonsProduction_wsoft_Tr.root",
28 help="custom outputfile name",
29)
30parser.add_argument(
31 "-p",
32 "--path",
33 help="path to muon background files",
34 default="/eos/experiment/ship/simulation/bkg/MuonBack_2024helium/8070735",
35)
36args = parser.parse_args()
37
38if args.testing_code:
39 print("test code, output file name overwritten as: muonsProduction_wsoft_Tr_test.root")
40 args.outputfile = "muonsProduction_wsoft_Tr_test.root"
41 selectedmuons = "SelectedMuonsTr_test.txt"
42else:
43 selectedmuons = "SelectedMuonsTr.txt"
44
45path = args.path
46logging.info(f"Path to MuonBackground : {path}")
47
48fsel = open(selectedmuons, "w") # noqa: SIM115
49csvwriter = csv.writer(fsel)
50
51output_file = r.TFile.Open(args.outputfile, "recreate")
52output_tree = r.TTree("MuonAndSoftInteractions", "Muon information and soft interaction tracks")
53
54imuondata = r.TVectorD(10) # 10 values: pid, px, py, pz, x, y, z, weight,time_of_hit,nmuons_in_event
55output_tree.Branch("imuondata", imuondata)
56
57track_array = r.TObjArray()
58output_tree.Branch("tracks", track_array)
59
60muon_vetoPoints = r.TClonesArray("vetoPoint")
61output_tree.Branch("muon_vetoPoints", muon_vetoPoints)
62
63muon_UpstreamTaggerPoints = r.TClonesArray("UpstreamTaggerPoint")
64output_tree.Branch("muon_UpstreamTaggerPoints", muon_UpstreamTaggerPoints)
65
66h = {}
67h["PvPt_muon"] = r.TH2F(
68 "PvPt_muon",
69 "The momentum of the muons hitting Tracking Station 1 (unweighted);P(GeV/c);Pt(GeV/c)",
70 200,
71 0.0,
72 400,
73 40,
74 0.0,
75 20,
76)
77h["n_muon"] = r.TH2I(
78 "n_muon",
79 "Number of muons hitting the Tracking Station 1 per Event;number of mu- per event (unweighted) bin width =1;number of mu+ per event (unweighted) bin width=1",
80 6,
81 0.0,
82 6,
83 6,
84 0.0,
85 6,
86)
87h["n_softtracks"] = r.TH1I("n_softtracks", "Number of soft tracks per muon;;(unweighted)", 200, 0, 2000)
88
89
90def printMCTrack(n: int, MCTrack) -> None:
91 """Print MCTrack truth."""
92 mcp = MCTrack[n]
93
94 RED = "\033[91m" # ANSI code Red
95 RESET = "\033[0m" # ANSI code Reset to default
96
97 try:
98 particle_name = pdg.GetParticle(mcp.GetPdgCode()).GetName()
99
100 if particle_name == "mu+" or particle_name == "mu-":
101 particle_name = f"{RED}{particle_name}{RESET} " # Highlight muons in red
102
103 print(
104 " %6s %-10s %10i %6.3F %6.3F %7.3F %7.3F %7.3F %7.3F %6s %10.3F %28s"
105 % (
106 n,
107 particle_name,
108 mcp.GetPdgCode(),
109 mcp.GetPx() / u.GeV,
110 mcp.GetPy() / u.GeV,
111 mcp.GetPz() / u.GeV,
112 mcp.GetStartX() / u.m,
113 mcp.GetStartY() / u.m,
114 mcp.GetStartZ() / u.m,
115 mcp.GetMotherId(),
116 mcp.GetWeight(),
117 mcp.GetProcName().Data(),
118 )
119 )
120 except Exception:
121 print(
122 " %6s %-10s %10i %6.3F %6.3F %7.3F %7.3F %7.3F %7.3F %6s %10.3F %28s"
123 % (
124 n,
125 "----",
126 mcp.GetPdgCode(),
127 mcp.GetPx() / u.GeV,
128 mcp.GetPy() / u.GeV,
129 mcp.GetPz() / u.GeV,
130 mcp.GetStartX() / u.m,
131 mcp.GetStartY() / u.m,
132 mcp.GetStartZ() / u.m,
133 mcp.GetMotherId(),
134 mcp.GetWeight(),
135 mcp.GetProcName().Data(),
136 )
137 )
138
139
140def dump(event, pcut: float = 0, print_whole_event: bool = True) -> None:
141 """Dump the whole event."""
142 if print_whole_event:
143 print(
144 "\n %6s %-10s %10s %6s %6s %7s %7s %7s %7s %6s %10s %18s"
145 % (
146 "#",
147 "particle",
148 "pid",
149 "px",
150 "py",
151 "pz",
152 "vx",
153 "vy",
154 "vz",
155 "mid",
156 "w",
157 "Process",
158 )
159 )
160 print(
161 " %6s %10s %10s %6s %6s %7s %7s %7s %7s %6s %10s %18s\n "
162 % (
163 " ",
164 "--------",
165 "---",
166 "--",
167 "--",
168 "--",
169 "--",
170 "--",
171 "--",
172 "---",
173 "---",
174 "-------",
175 )
176 )
177 n = -1
178 for mcp in event.MCTrack:
179 n += 1
180 if mcp.GetP() / u.GeV < pcut:
181 continue
182 if print_whole_event:
183 printMCTrack(n, event.MCTrack)
184
185 return
186
187
188events_ = {"Tr": {}, "Tr_SBT": {}, "Tr_noSBT": {}}
189global_event_nr = 0
190processed_events = {}
191
192P_threshold = 3
193
194headers = [
195 f"nMuons in event>{P_threshold}GeV",
196 "Muon PID",
197 "Momentum[GeV/c]",
198 "x[m]",
199 "y[m]",
200 "z[m]",
201 "t_muon [ns]",
202 "nSoft Tracks",
203 "nSBT Hits(muon)",
204 "nUBT Hits(muon)",
205 "Weight_muon",
206]
207csvwriter.writerow(headers)
208
209for inputFolder in os.listdir(path):
210 if not os.path.isdir(os.path.join(path, inputFolder)):
211 continue
212
213 if args.testing_code and len(events_["Tr_noSBT"]) >= 12:
214 break
215
216 logging.info(f"Processing folder: {inputFolder}")
217 f = None
218 try:
219 f = r.TFile.Open(
220 os.path.join(path, inputFolder, "ship.conical.MuonBack-TGeant4.root"),
221 "read",
222 )
223 tree = f.cbmsim
224 except Exception as e:
225 print(f"Error :{e}")
226
227 if f:
228 f.Close()
229 continue
230
231 for event in tree:
232 nmu = {"mu+": 0, "mu-": 0}
233
234 muon_table = []
235 global_event_nr += 1
236
237 muon_ids = []
238
239 # Collect track IDs of muons which hit the Tracking Station
240 for hit in event.strawtubesPoint:
241 trackingstation_id = hit.GetStationNumber()
242 pid = hit.PdgCode()
243 P = r.TMath.Sqrt(hit.GetPx() ** 2 + hit.GetPy() ** 2 + hit.GetPz() ** 2)
244 if abs(pid) == 13 and trackingstation_id == 1 and P_threshold / u.GeV < P:
245 track_id = hit.GetTrackID()
246 particle_name = pdg.GetParticle(hit.PdgCode()).GetName()
247 if track_id not in muon_ids:
248 muon_ids.append(track_id)
249
250 if global_event_nr not in events_["Tr"]:
251 events_["Tr"][global_event_nr] = set()
252
253 events_["Tr"][global_event_nr].add(track_id)
254
255 if not len(muon_ids):
256 continue
257 # dump(event)
258
259 for muon_ in muon_ids:
260 muon_vetoPoints.Clear()
261
262 if global_event_nr not in events_["Tr_SBT"]:
263 events_["Tr_SBT"][global_event_nr] = set()
264
265 for hit in event.vetoPoint:
266 detID = hit.GetDetectorID()
267 pid = hit.PdgCode()
268 track_id = hit.GetTrackID()
269 P = r.TMath.Sqrt(hit.GetPx() ** 2 + hit.GetPy() ** 2 + hit.GetPz() ** 2)
270
271 if track_id == muon_:
272 events_["Tr_SBT"][global_event_nr].add(track_id)
273 continue
274
275 if muon_ in events_["Tr_SBT"][global_event_nr]:
276 continue
277
278 track_array.Clear()
279 for track in event.MCTrack:
280 if track.GetMotherId() == muon_ and track.GetProcName().Data() != "Muon nuclear interaction":
281 track_array.Add(track)
282
283 muon_UpstreamTaggerPoints.Clear()
284
285 ubt_index = 0
286
287 for hit in event.UpstreamTaggerPoint:
288 track_id = hit.GetTrackID()
289
290 if track_id != muon_:
291 continue
292
293 if muon_UpstreamTaggerPoints.GetSize() == ubt_index:
294 muon_UpstreamTaggerPoints.Expand(ubt_index + 1)
295 muon_UpstreamTaggerPoints[ubt_index] = hit
296
297 ubt_index += 1
298
299 for hit in event.strawtubesPoint:
300 track_id = hit.GetTrackID()
301 pid = hit.PdgCode()
302
303 P = r.TMath.Sqrt(hit.GetPx() ** 2 + hit.GetPy() ** 2 + hit.GetPz() ** 2)
304 Pt = r.TMath.Sqrt(hit.GetPx() ** 2 + hit.GetPy() ** 2)
305
306 trackingstation_id = hit.GetStationNumber()
307
308 if abs(hit.PdgCode()) == 13 and trackingstation_id == 1 and P_threshold / u.GeV < P:
309 if global_event_nr not in events_["Tr_noSBT"]:
310 events_["Tr_noSBT"][global_event_nr] = set()
311
312 events_["Tr_noSBT"][global_event_nr].add(track_id)
313
314 if global_event_nr not in processed_events:
315 processed_events[global_event_nr] = []
316
317 if track_id not in processed_events[global_event_nr]: # only save the info of first SBT hit
318 processed_events[global_event_nr].append(track_id)
319
320 particle_name = pdg.GetParticle(hit.PdgCode()).GetName()
321
322 nmu[particle_name] += 1
323
324 weight = event.MCTrack[track_id].GetWeight()
325
326 # Fill imuondata
327 imuondata[0] = float(hit.PdgCode())
328 imuondata[1] = float(hit.GetPx() / u.GeV)
329 imuondata[2] = float(hit.GetPy() / u.GeV)
330 imuondata[3] = float(hit.GetPz() / u.GeV)
331 imuondata[4] = float(hit.GetX() / u.m)
332 imuondata[5] = float(hit.GetY() / u.m)
333 imuondata[6] = float(hit.GetZ() / u.m)
334 imuondata[7] = float(weight)
335 imuondata[8] = float(hit.GetTime())
336 imuondata[9] = len(muon_ids)
337 muon_table.append(
338 [
339 track_id,
340 len(muon_ids),
341 imuondata[0],
342 P,
343 imuondata[4],
344 imuondata[5],
345 imuondata[6],
346 imuondata[8],
347 len(track_array),
348 len(muon_vetoPoints),
349 len(muon_UpstreamTaggerPoints),
350 imuondata[7],
351 ]
352 )
353 h["PvPt_muon"].Fill(P, Pt)
354 h["n_softtracks"].Fill(len(track_array))
355 output_tree.Fill()
356
357 if len(muon_table):
358 h["n_muon"].Fill(nmu["mu-"], nmu["mu+"])
359 csvwriter.writerows(row[1:] for row in muon_table)
360 logging.debug(
361 f"EVENT ID:{global_event_nr}\n\tMuon Summary:\n{tabulate(muon_table, headers=headers, tablefmt='grid')}\n\n"
362 )
363
364for type_ in events_:
365 # Calculate total number of muons
366 total_muons = sum(len(muons) for muons in events_[type_].values())
367 print(f"{type_}, \tnEvents:{sum(bool(len(muons)) for muons in events_[type_].values())}, \tnMuons:{total_muons}")
368output_file.cd()
369output_tree.Write()
370for histname in h:
371 h[histname].Write()
372output_file.Close()
373fsel.close()
374
375
376print(
377 "------------------------------------------------------file saved, reading",
378 args.outputfile,
379 " now----------------------------------------------------------------",
380)
381event_data = []
382with r.TFile.Open(args.outputfile, "read") as file:
383 try:
384 tree = file.MuonAndSoftInteractions
385 except Exception as e:
386 print(f"Error: {e}")
387 exit(1)
388
389 print(f"Processing tree: {tree.GetName()}")
390 print(f"Total number of entries: {tree.GetEntries()}")
391
392 for event in tree:
393 imuondata = event.imuondata
394 pid = imuondata[0]
395 px = imuondata[1]
396 py = imuondata[2]
397 pz = imuondata[3]
398 x = imuondata[4]
399 y = imuondata[5]
400 z = imuondata[6]
401
402 weight = imuondata[7]
403 time_hit = imuondata[8]
404 nmuons = imuondata[9]
405
406 num_tracks = len(event.tracks)
407 num_muonhits = len(event.muon_vetoPoints)
408 num_ubthits = len(event.muon_UpstreamTaggerPoints)
409
410 P = r.TMath.Sqrt(px**2 + py**2 + pz**2)
411
412 event_data.append(
413 [
414 nmuons,
415 pid,
416 P,
417 x,
418 y,
419 z,
420 time_hit,
421 num_tracks,
422 num_muonhits,
423 num_ubthits,
424 weight,
425 ]
426 )
427print(tabulate(event_data, headers=headers, tablefmt="grid"))
None printMCTrack(int n, MCTrack)
None dump(event, float pcut=0, bool print_whole_event=True)
Coord add(Coord c1, Coord c2)
Definition: restypedef.cpp:23
int open(const char *, int)
Opens a file descriptor.