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