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