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