Belle II Software development
klm_strip_efficiency.py
1
8
9'''
10Validation of KLM strip efficiency calibration.
11'''
12
13
14import basf2
15from prompt import ValidationSettings
16import ROOT
17from ROOT.Belle2 import BKLMElementNumbers, KLMCalibrationChecker, KLMElementNumbers
18import sys
19import subprocess
20import math
21import os
22import json
23
24
25settings = ValidationSettings(name='KLM strip efficiency',
26 description=__doc__,
27 download_files=['stdout'],
28 expert_config={
29 "chunk_size": 100
30 })
31
32
33def save_graph_to_root(graph_name):
34 '''
35 Save a TGraph in a ROOT file.
36 '''
37 graph = ROOT.gPad.GetPrimitive('Graph')
38 assert isinstance(graph, ROOT.TGraph) == 1
39 graph.SetName(graph_name)
40 graph.Write()
41
42
43def save_graph_to_pdf(canvas, root_file, graph_name, exp, chunk):
44 '''
45 Save a drawn TGraph in a PDF file.
46 '''
47 graph = root_file.Get(graph_name)
48 assert isinstance(graph, ROOT.TGraph) == 1
49 graph.SetMarkerStyle(ROOT.EMarkerStyle.kFullDotSmall)
50 graph.SetMarkerColor(ROOT.EColor.kAzure + 10)
51 graph.GetXaxis().SetTitle(f'Exp. {exp} -- Run number')
52 graph.GetYaxis().SetTitle('Plane efficiency')
53 graph.SetMinimum(0.)
54 graph.SetMaximum(1.)
55 graph.Draw('AP')
56 ROOT.gPad.SetGridy()
57 canvas.SaveAs(f'efficiency_exp{exp}_chunk{chunk}_{graph_name}.pdf')
58
59
60def run_validation(job_path, input_data_path, requested_iov, expert_config):
61 '''
62 Run the validation.
63 Nota bene:
64 - job_path will be replaced with path/to/calibration_results
65 - input_data_path will be replaced with path/to/data_path used for calibration, e.g. /group/belle2/dataprod/Data/PromptSkim/
66 '''
67
68 # Grab the expert configurations.
69 expert_config = json.loads(expert_config)
70 chunk_size = expert_config['chunk_size']
71
72 # Ignore the ROOT command line options.
73 ROOT.PyConfig.IgnoreCommandLineOptions = True # noqa
74 # Run ROOT in batch mode.
75 ROOT.gROOT.SetBatch(True)
76 # Set the Belle II style.
77 ROOT.gROOT.SetStyle("BELLE2")
78 # And unset the stat box.
79 ROOT.gStyle.SetOptStat(0)
80
81 # Path to the database.txt file.
82 database_file = f'{job_path}/KLMStripEfficiency/outputdb/database.txt'
83
84 # Dictionary with the definition of the validation plots.
85 bklm = KLMElementNumbers.c_BKLM
86 eklm = KLMElementNumbers.c_EKLM
87 first_rpc = BKLMElementNumbers.c_FirstRPCLayer
88 graph_dictionary = {'barrel_rpcs': f'subdetector=={bklm} && layer>={first_rpc}',
89 'barrel_scintillators': f'subdetector=={bklm} && layer<{first_rpc}',
90 'endcap_scintillators': f'subdetector=={eklm}'}
91
92 # Check the list of runs from the file database.txt.
93 exp_run_dict = {}
94 previous_exp = -666
95 with open(database_file) as f:
96 for line in f:
97 fields = line.split(' ')
98 if (fields[0] == 'dbstore/KLMStripEfficiency'):
99 iov = fields[2].split(',')
100 exp = int(iov[0])
101 run = int(iov[1])
102 if (exp != previous_exp):
103 exp_run_dict[exp] = [run]
104 previous_exp = exp
105 else:
106 exp_run_dict[exp].append(run)
107
108 # Tweak the IoV range if the first run is 0.
109 # This is needed for display purposes.
110 for exp, run_list in exp_run_dict.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.
117 for exp, run_list in exp_run_dict.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 strip efficiency results tree for experiment {exp}, run {run}.')
123 checker.setStripEfficiencyResultsFile(f'strip_efficiency_exp{exp}_run{run}.root')
124 checker.checkStripEfficiency()
125
126 # Run the validation.
127 for exp, run_list in exp_run_dict.items():
128 # For each experiment, merge the files in chunks of some runs.
129 chunks = math.ceil(len(run_list) / chunk_size)
130 for chunk in range(chunks):
131 file_name = f'strip_efficiency_exp{exp}_chunk{chunk}.root'
132 run_files = [
133 f'strip_efficiency_exp{exp}_run{run}.root' for run in run_list[chunk * chunk_size:(chunk + 1) * chunk_size]]
134 subprocess.run(['hadd', '-f', file_name] + run_files, check=True)
135 input_file = ROOT.TFile(f'{file_name}')
136 output_file = ROOT.TFile(f'histograms_{file_name}', 'recreate')
137 output_file.cd()
138 tree = input_file.Get('efficiency')
139 assert isinstance(tree, ROOT.TTree) == 1
140 canvas = ROOT.TCanvas(f'canvas_exp{exp}_chunk{chunk}', 'canvas', 800, 500)
141 canvas.cd()
142 for graph_name, graph_cut in graph_dictionary.items():
143 tree.Draw('efficiency:run', graph_cut)
144 save_graph_to_root(graph_name)
145 save_graph_to_pdf(canvas, output_file, graph_name, exp, chunk)
146 input_file.Close()
147 output_file.Close()
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
156if __name__ == "__main__":
157 run_validation(*sys.argv[1:])