Belle II Software  release-08-01-10
klm_strip_efficiency.py
1 
8 
9 '''
10 Validation of KLM strip efficiency calibration.
11 '''
12 
13 
14 import basf2
15 from prompt import ValidationSettings
16 import ROOT
17 from ROOT.Belle2 import BKLMElementNumbers, KLMCalibrationChecker, KLMElementNumbers
18 import sys
19 import subprocess
20 import math
21 import os
22 import json
23 
24 
25 settings = ValidationSettings(name='KLM strip efficiency',
26  description=__doc__,
27  download_files=['stdout'],
28  expert_config={
29  "chunk_size": 100
30  })
31 
32 
33 def 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 
43 def 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 
60 def 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 
156 if __name__ == "__main__":
157  run_validation(*sys.argv[1:])