1+ #!/usr/bin/env python3
2+
3+ #
4+ # Script that determines final accounting numbers / event statistics
5+ # for reporting back to MonaLisa.
6+ #
7+ # Analyses the AO2D / kinematics output of an O2DPG simulation run
8+ # and creates a file of the form
9+ #
10+ # inputN_passedN_errorsN_outputN.stat
11+ #
12+ # which is picked up and used by the MonaLisa system.
13+ #
14+ # See discussion in https://alice.its.cern.ch/jira/browse/O2-4553;
15+ # Here outputN would be the number of events/collisions produced in this job.
16+
17+ import ROOT
18+ import argparse
19+ import os
20+ import re
21+
22+ parser = argparse .ArgumentParser (description = '' ,
23+ formatter_class = argparse .ArgumentDefaultsHelpFormatter )
24+
25+ parser .add_argument ('-f' ,'--aod-file' , default = "AO2D.root" , help = 'AO2D file to check' )
26+ args = parser .parse_args ()
27+
28+ def write_stat_file (eventcount ):
29+ """
30+ writes a file conforming to MonaLisa convention
31+ """
32+
33+ filename = '0_0_0_' + str (eventcount ) + '.stat'
34+ # touche/create a new file
35+ with open (filename , 'w' ) as f :
36+ print ("#This file is autogenerated" , file = f )
37+ print ("#It tells MonaLisa about the number of produced MC events" , file = f )
38+ print ("#Numer of MC collisions in AOD : " + str (eventcount ), file = f )
39+
40+ def read_collisioncontext_eventcount (file ):
41+ """
42+ determines MC eventcount from collision context files
43+ """
44+ pass
45+
46+ def find_files_matching_pattern (directory = '.' , pattern = '.*' ):
47+ matching_files = []
48+
49+ # Walk through the directory and its subdirectories
50+ for root , dirs , files in os .walk (directory ):
51+ for file_name in files :
52+ # Check if the filename matches the regular expression pattern
53+ if re .match (pattern , file_name ):
54+ matching_files .append (os .path .join (root , file_name ))
55+
56+ return matching_files
57+
58+ def read_GEANT_eventcount (file ):
59+ # Open the ROOT file
60+ eventcount = 0
61+ tfile = ROOT .TFile .Open (file )
62+ if tfile :
63+ simtree = tfile .Get ("o2sim" )
64+ if simtree and isinstance (simtree , ROOT .TTree ):
65+ eventcount = simtree .GetEntries ()
66+
67+ tfile .Close ()
68+ return eventcount
69+
70+ def read_accumulated_GEANT_eventcount (directory = "." ):
71+ """
72+ Determines the MC eventcount from GEANT kinematics files sitting
73+ in directory/tfX/ subdirectories.
74+ """
75+ pattern_to_match = r'sgn.*_Kine.root'
76+ kine_files = find_files_matching_pattern (directory , pattern_to_match )
77+ eventcount = 0
78+ for f in kine_files :
79+ eventcount = eventcount + read_GEANT_eventcount (f )
80+ return eventcount
81+
82+ def read_AO2D_eventcount (file ):
83+ """
84+ determines MC eventcount from (final) AO2D file
85+ """
86+ eventcount = 0
87+
88+ # Open the ROOT file
89+ tfile = ROOT .TFile .Open (file )
90+
91+ # Get the list of keys (TKeys) in the ROOT files
92+ keys = tfile .GetListOfKeys ()
93+
94+ # Iterate through the keys "DF_" keys and accumulate
95+ # stored MC collisions
96+ for key in keys :
97+ key_name = key .GetName ()
98+ if key_name .startswith ("DF_" ):
99+ obj = key .ReadObj ()
100+ # the O2mccollision tree contains the simulated collisions
101+ coltree = obj .Get ("O2mccollision" )
102+ if coltree and isinstance (coltree , ROOT .TTree ):
103+ eventcount = eventcount + coltree .GetEntries ()
104+
105+ # Close the files
106+ tfile .Close ()
107+ return eventcount
108+
109+ AO2D_eventcount = read_AO2D_eventcount (args .aod_file )
110+ GEANT_eventcount = read_accumulated_GEANT_eventcount ()
111+ if AO2D_eventcount != GEANT_eventcount :
112+ print ("WARN: AO2D MC event count and GEANT event count differ" )
113+
114+ write_stat_file (AO2D_eventcount )
0 commit comments