Belle II Software  release-05-01-25
klm_strip_efficiency.py
1 # -*- coding: utf-8 -*-
2 
3 '''
4 Validation of KLM strip efficiency calibration.
5 '''
6 
7 
8 import basf2
9 from prompt import ValidationSettings
10 import ROOT
11 from ROOT.Belle2 import BKLMElementNumbers, KLMCalibrationChecker, KLMElementNumbers
12 import sys
13 import subprocess
14 import math
15 
16 
17 
18 settings = ValidationSettings(name='KLM strip efficiency',
19  description=__doc__,
20  download_files=['stdout'],
21  expert_config=None)
22 
23 
24 def save_graph_to_root(graph_name):
25  '''
26  Save a TGraph in a ROOT file.
27  '''
28  graph = ROOT.gPad.GetPrimitive('Graph')
29  assert isinstance(graph, ROOT.TGraph) == 1
30  graph.SetName(graph_name)
31  graph.Write()
32 
33 
34 def save_graph_to_pdf(canvas, root_file, graph_name, exp, chunk):
35  '''
36  Save a drawn TGraph in a PDF file.
37  '''
38  graph = root_file.Get(graph_name)
39  assert isinstance(graph, ROOT.TGraph) == 1
40  graph.SetMarkerStyle(ROOT.EMarkerStyle.kFullDotSmall)
41  graph.SetMarkerColor(ROOT.EColor.kRed + 1)
42  graph.GetXaxis().SetTitle(f'Exp. {exp} -- Run number')
43  graph.GetYaxis().SetTitle('Plane efficiency')
44  graph.SetMinimum(0.)
45  graph.SetMaximum(1.)
46  graph.Draw('AP')
47  ROOT.gPad.SetGridy()
48  canvas.SaveAs(f'efficiency_exp{exp}_chunk{chunk}_{graph_name}.pdf')
49 
50 
51 def run_validation(job_path, input_data_path, requested_iov, expert_config, **kwargs):
52  '''
53  Run the validation.
54  Nota bene:
55  - job_path will be replaced with path/to/calibration_results
56  - input_data_path will be replaced with path/to/data_path used for calibration, e.g. /group/belle2/dataprod/Data/PromptSkim/
57  '''
58 
59  # TODO: replace it with an expert dictionary when it will be possible.
60  chunk_size = 100
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 = f'{job_path}/KLMStripEfficiency/outputdb/database.txt'
73 
74  # Dictionary with the definition of the validation plots.
75  bklm = KLMElementNumbers.c_BKLM
76  eklm = KLMElementNumbers.c_EKLM
77  first_rpc = BKLMElementNumbers.c_FirstRPCLayer
78  graph_dictionary = {'barrel_rpcs': f'subdetector=={bklm} && layer>={first_rpc}',
79  'barrel_scintillators': f'subdetector=={bklm} && layer<{first_rpc}',
80  'endcap_scintillators': f'subdetector=={eklm}'}
81 
82  # Check the list of runs from the file database.txt.
83  exp_run_dict = {}
84  previous_exp = -666
85  with open(database_file) as f:
86  for line in f:
87  fields = line.split(' ')
88  if (fields[0] == 'dbstore/KLMStripEfficiency'):
89  iov = fields[2].split(',')
90  exp = int(iov[0])
91  run = int(iov[1])
92  if (exp != previous_exp):
93  exp_run_dict[exp] = [run]
94  previous_exp = exp
95  else:
96  exp_run_dict[exp].append(run)
97 
98  # Tweak the IoV range if the first run is 0.
99  # This is needed for display purposes.
100  for exp, run_list in exp_run_dict.items():
101  run_list.sort()
102  if len(run_list) > 1:
103  if run_list[0] == 0 and run_list[1] > 5:
104  run_list[0] = run_list[1] - 5
105 
106  # Run the KLMCalibrationChecker class.
107  for exp, run_list in exp_run_dict.items():
108  for run in run_list:
109  checker = KLMCalibrationChecker()
110  checker.setExperimentRun(exp, run)
111  checker.setTestingPayload(database_file)
112  basf2.B2INFO(f'Creating strip efficiency results tree for experiment {exp}, run {run}.')
113  checker.setStripEfficiencyResultsFile(f'strip_efficiency_exp{exp}_run{run}.root')
114  checker.checkStripEfficiency()
115 
116  # Run the validation.
117  for exp, run_list in exp_run_dict.items():
118  # For each experiment, merge the files in chunks of some runs.
119  chunks = math.ceil(len(run_list) / chunk_size)
120  for chunk in range(chunks):
121  file_name = f'strip_efficiency_exp{exp}_chunk{chunk}.root'
122  run_file_names = [f'strip_efficiency_exp{exp}_run{run}.root' for run in run_list[chunk:(chunk + chunk_size)]]
123  subprocess.run(['hadd', '-f', file_name] + run_file_names, check=True)
124  input_file = ROOT.TFile(f'{file_name}')
125  output_file = ROOT.TFile(f'histograms_{file_name}', 'recreate')
126  output_file.cd()
127  tree = input_file.Get('efficiency')
128  assert isinstance(tree, ROOT.TTree) == 1
129  canvas = ROOT.TCanvas(f'canvas_exp{exp}_chunk{chunk}', 'canvas', 800, 500)
130  canvas.cd()
131  for graph_name, graph_cut in graph_dictionary.items():
132  tree.Draw('efficiency:run', graph_cut)
133  save_graph_to_root(graph_name)
134  save_graph_to_pdf(canvas, output_file, graph_name, exp, chunk)
135  input_file.Close()
136  output_file.Close()
137 
138 
139 if __name__ == "__main__":
140  run_validation(*sys.argv[1:])