Belle II Software development
klm_time.py
1
8
9'''
10Validation of KLM time calibration (cable delay and time constants).
11'''
12
13
14import basf2
15from prompt import ValidationSettings
16import ROOT
17from ROOT.Belle2 import KLMCalibrationChecker
18import sys
19import subprocess
20import math
21import os
22import json
23from ROOT import TH1F, TH2F, TCanvas, TFile, gStyle
24
25
26settings = ValidationSettings(name='KLM time',
27 description=__doc__,
28 download_files=['stdout'],
29 expert_config={
30 "chunk_size": 100,
31 "LowerTimeBoundaryRPC": -800.0,
32 "UpperTimeBoundaryRPC": -600.0,
33 "LowerTimeBoundaryScintillatorsBKLM": -4800.0,
34 "UpperTimeBoundaryScintillatorsBKLM": -4600.0,
35 "LowerTimeBoundaryScintillatorsEKLM": -4850.0,
36 "UpperTimeBoundaryScintillatorsEKLM": -4600.0,
37 })
38
39
40def run_validation(job_path, input_data_path, requested_iov, expert_config):
41 '''
42 Run the validation.
43 Note:
44 - job_path will be replaced with path/to/calibration_results
45 - input_data_path will be replaced with path/to/data_path used for calibration, e.g. /group/belle2/dataprod/Data/PromptSkim/
46 '''
47
48 # Grab the expert configurations.
49 expert_config = json.loads(expert_config)
50 print(expert_config)
51 chunk_size = expert_config['chunk_size']
52 LowerTimeBoundaryRPC = expert_config['LowerTimeBoundaryRPC']
53 UpperTimeBoundaryRPC = expert_config['UpperTimeBoundaryRPC']
54 LowerTimeBoundaryScintillatorsBKLM = expert_config['LowerTimeBoundaryScintillatorsBKLM']
55 UpperTimeBoundaryScintillatorsBKLM = expert_config['UpperTimeBoundaryScintillatorsBKLM']
56 LowerTimeBoundaryScintillatorsEKLM = expert_config['LowerTimeBoundaryScintillatorsEKLM']
57 UpperTimeBoundaryScintillatorsEKLM = expert_config['UpperTimeBoundaryScintillatorsEKLM']
58
59 # Ignore the ROOT command line options.
60 ROOT.PyConfig.IgnoreCommandLineOptions = True # noqa
61 # Run ROOT in batch mode.
62 ROOT.gROOT.SetBatch(True)
63 # Set the Belle II style.
64 ROOT.gROOT.SetStyle("BELLE2")
65 # And unset the stat box.
66 ROOT.gStyle.SetOptStat(0)
67
68 # Path to the database.txt file.
69 database_file = os.path.join(f'{job_path}', 'KLMTime', 'outputdb', 'database.txt')
70
71 # Check the list of runs from the file database.txt for both payloads.
72 exp_run_dict_cabledelay = {}
73 exp_run_dict_constants = {}
74 previous_exp_cabledelay = -666
75 previous_exp_constants = -666
76
77 with open(database_file) as f:
78 for line in f:
79 fields = line.split(' ')
80 if fields[0] == 'dbstore/KLMTimeCableDelay':
81 iov = fields[2].split(',')
82 exp = int(iov[0])
83 run = int(iov[1])
84 if exp != previous_exp_cabledelay:
85 exp_run_dict_cabledelay[exp] = [run]
86 previous_exp_cabledelay = exp
87 else:
88 exp_run_dict_cabledelay[exp].append(run)
89 elif fields[0] == 'dbstore/KLMTimeConstants':
90 iov = fields[2].split(',')
91 exp = int(iov[0])
92 run = int(iov[1])
93 if exp != previous_exp_constants:
94 exp_run_dict_constants[exp] = [run]
95 previous_exp_constants = exp
96 else:
97 exp_run_dict_constants[exp].append(run)
98
99 # Tweak the IoV range if the first run is 0.
100 # This is needed for display purposes.
101 for exp, run_list in exp_run_dict_cabledelay.items():
102 run_list.sort()
103 if len(run_list) > 1:
104 if run_list[0] == 0 and run_list[1] > 5:
105 run_list[0] = run_list[1] - 5
106
107 for exp, run_list in exp_run_dict_constants.items():
108 run_list.sort()
109 if len(run_list) > 1:
110 if run_list[0] == 0 and run_list[1] > 5:
111 run_list[0] = run_list[1] - 5
112
113 # Run the KLMCalibrationChecker class for cable delay.
114 for exp, run_list in exp_run_dict_cabledelay.items():
115 for run in run_list:
116 checker = KLMCalibrationChecker()
117 checker.setExperimentRun(exp, run)
118 checker.setTestingPayload(database_file)
119 basf2.B2INFO(f'Creating time cable delay results tree for experiment {exp}, run {run}.')
120 checker.setTimeCableDelayResultsFile(f'time_cabledelay_exp{exp}_run{run}.root')
121 checker.checkTimeCableDelay()
122
123 # Run the KLMCalibrationChecker class for time constants.
124 for exp, run_list in exp_run_dict_constants.items():
125 for run in run_list:
126 checker = KLMCalibrationChecker()
127 checker.setExperimentRun(exp, run)
128 checker.setTestingPayload(database_file)
129 basf2.B2INFO(f'Creating time constants results tree for experiment {exp}, run {run}.')
130 checker.setTimeConstantsResultsFile(f'time_constants_exp{exp}_run{run}.root')
131 checker.checkTimeConstants()
132
133 # Run the validation for cable delay.
134 for exp, run_list in exp_run_dict_cabledelay.items():
135 # For each experiment, merge the files in chunks of some runs.
136 chunks = math.ceil(len(run_list) / chunk_size)
137 chunk_files = []
138 for chunk in range(chunks):
139 file_name = f'time_cabledelay_exp{exp}_chunk{chunk}.root'
140 run_files = [
141 f'time_cabledelay_exp{exp}_run{run}.root' for run in run_list[chunk * chunk_size:(chunk + 1) * chunk_size]]
142 subprocess.run(['hadd', '-f', file_name] + run_files, check=True)
143 chunk_files.append(file_name)
144
145 # Let's delete the files for single IoVs.
146 for run_file in run_files:
147 try:
148 os.remove(run_file)
149 except OSError as e:
150 basf2.B2ERROR(f'The file {run_file} can not be removed: {e.strerror}')
151
152 # Now merge all chunks into one final file for plotting
153 final_file_name = f'time_cabledelay_exp{exp}_all.root'
154 subprocess.run(['hadd', '-f', final_file_name] + chunk_files, check=True)
155 input_file = ROOT.TFile(final_file_name)
156
157 gStyle.SetOptStat(1111111)
158
159 barrel_RPC = TH1F("barrel_RPC", "time cable delay for Barrel RPC", 100, LowerTimeBoundaryRPC, UpperTimeBoundaryRPC)
160 barrel_scintillator = TH1F("barrel_scintillator", "time cable delay for Barrel scintillator",
161 100, LowerTimeBoundaryScintillatorsBKLM, UpperTimeBoundaryScintillatorsBKLM)
162 endcap_scintillator = TH1F("endcap_scintillator", "time cable delay for endcap scintillator",
163 100, LowerTimeBoundaryScintillatorsEKLM, UpperTimeBoundaryScintillatorsEKLM)
164
165 tree = input_file.Get("cabledelay")
166 assert isinstance(tree, ROOT.TTree) == 1
167 myC = TCanvas("myC")
168
169 tree.Draw("timeDelay>>barrel_RPC", "subdetector==1 & layer>=3")
170 barrel_RPC.GetXaxis().SetTitle("T_{cable} (ns)")
171 barrel_RPC.GetYaxis().SetTitle("Entries")
172 myC.Print("barrel_RPC.png")
173
174 tree.Draw("timeDelay>>barrel_scintillator", "subdetector==1 & layer<3")
175 barrel_scintillator.GetXaxis().SetTitle("T_{cable} (ns)")
176 barrel_scintillator.GetYaxis().SetTitle("Entries")
177 myC.Print("barrel_scintillator.png")
178
179 tree.Draw("timeDelay>>endcap_scintillator", "subdetector==2")
180 endcap_scintillator.GetXaxis().SetTitle("T_{cable} (ns)")
181 endcap_scintillator.GetYaxis().SetTitle("Entries")
182 myC.Print("endcap_scintillator.png")
183
184 # Write out histograms
185 fout = TFile("KLMTimeCableDelay.root", "recreate")
186 barrel_RPC.Write()
187 barrel_scintillator.Write()
188 endcap_scintillator.Write()
189 input_file.Close()
190 fout.Close()
191
192 # Delete the chunk files
193 for chunk_file in chunk_files:
194 try:
195 os.remove(chunk_file)
196 except OSError as e:
197 basf2.B2ERROR(f'The file {chunk_file} can not be removed: {e.strerror}')
198
199 # Run the validation for time constants.
200 for exp, run_list in exp_run_dict_constants.items():
201 # For each experiment, merge the files in chunks of some runs.
202 chunks = math.ceil(len(run_list) / chunk_size)
203 chunk_files = []
204 for chunk in range(chunks):
205 file_name = f'time_constants_exp{exp}_chunk{chunk}.root'
206 run_files = [
207 f'time_constants_exp{exp}_run{run}.root' for run in run_list[chunk * chunk_size:(chunk + 1) * chunk_size]]
208 subprocess.run(['hadd', '-f', file_name] + run_files, check=True)
209 chunk_files.append(file_name)
210
211 # Let's delete the files for single IoVs.
212 for run_file in run_files:
213 try:
214 os.remove(run_file)
215 except OSError as e:
216 basf2.B2ERROR(f'The file {run_file} can not be removed: {e.strerror}')
217
218 # Now merge all chunks into one final file for plotting
219 final_file_name = f'time_constants_exp{exp}_all.root'
220 subprocess.run(['hadd', '-f', final_file_name] + chunk_files, check=True)
221 input_file = ROOT.TFile(final_file_name)
222 gStyle.SetOptStat(1111111)
223
224 barrel_RPCPhi = TH2F("barrel_RPCPhi",
225 "time constants for Barrel RPC phi readout", 100, 30000, 65000, 100, 0.004, 0.015)
226 barrel_RPCZ = TH2F("barrel_RPCZ",
227 "time constants for Barrel RPC Z readout", 100, 30000, 65000, 100, 0.0, 0.0025)
228 barrel_scintillator_constants = TH2F("barrel_scintillator_constants",
229 "time constants for Barrel scintillator", 100, 30000, 65000, 100, 0.075, 0.09)
230 endcap_scintillator_constants = TH2F("endcap_scintillator_constants",
231 "time constants for endcap scintillator", 100, 0, 16000, 100, 0.060, 0.075)
232
233 tree = input_file.Get("constants")
234 assert isinstance(tree, ROOT.TTree) == 1
235 myC = TCanvas("myC")
236
237 tree.Draw("delayRPCPhi:channelNumber>>barrel_RPCPhi", "subdetector==1 & layer>=3", "colz")
238 barrel_RPCPhi.GetXaxis().SetTitle("Channel number")
239 barrel_RPCPhi.GetYaxis().SetTitle("Time Delay constants")
240 myC.Print("barrel_RPCPhi.png")
241
242 tree.Draw("delayRPCZ:channelNumber>>barrel_RPCZ", "subdetector==1 & layer>=3", "colz")
243 barrel_RPCZ.GetXaxis().SetTitle("Channel number")
244 barrel_RPCZ.GetYaxis().SetTitle("Time Delay constants")
245 myC.Print("barrel_RPCZ.png")
246
247 tree.Draw("delayBKLM:channelNumber>>barrel_scintillator_constants", "subdetector==1 & layer<3", "colz")
248 barrel_scintillator_constants.GetXaxis().SetTitle("Channel number")
249 barrel_scintillator_constants.GetYaxis().SetTitle("Time Delay constants")
250 myC.Print("barrel_scintillator_constants.png")
251
252 tree.Draw("delayEKLM:channelNumber>>endcap_scintillator_constants", "subdetector==2", "colz")
253 endcap_scintillator_constants.GetXaxis().SetTitle("Channel number")
254 endcap_scintillator_constants.GetYaxis().SetTitle("Time Delay constants")
255 myC.Print("endcap_scintillator_constants.png")
256
257 fout = TFile("KLMTimeConstants.root", "recreate")
258 barrel_RPCPhi.Write()
259 barrel_RPCZ.Write()
260 barrel_scintillator_constants.Write()
261 endcap_scintillator_constants.Write()
262 input_file.Close()
263 fout.Close()
264
265 # Delete the chunk files
266 for chunk_file in chunk_files:
267 try:
268 os.remove(chunk_file)
269 except OSError as e:
270 basf2.B2ERROR(f'The file {chunk_file} can not be removed: {e.strerror}')
271
272
273if __name__ == "__main__":
274 run_validation(*sys.argv[1:])