Belle II Software  release-08-01-10
channelMasking_hltdqm.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 
4 
11 
12 import sys
13 import os
14 import glob
15 import logging
16 from ROOT import TFile, TH1F
17 
18 
19 # checks if the run can be analyzed based on the HLT histograms, returns -1 if not and the number of events otherwise
20 def checkIfRunUsable(file):
21  # consider only runs identified as physics runs (possible since experiment 8)
22  h = file.FindObject('DQMInfo/rtype')
23  if not h:
24  logging.warning(fileName + ' ... histogram runtype not found')
25  return -1
26  if not h.GetTitle() == "physics":
27  logging.info(fileName + ' ... not a physics run, skipping')
28  return -1
29 
30  # check if we have enough events for meaningful masking
31  h = file.FindObject('TOP/good_hits_per_event1')
32  if not h:
33  logging.warning(fileName + ' ... histogram good_hits_per_event1 not found')
34  return -1
35  nev = int(h.GetEntries())
36  if nev < 10000:
37  logging.warning(fileName + 'run =' + str(run) + 'events =' + str(nev) + ' ... skipped, not enough events')
38  return -1
39 
40  # check if we have the necessary histogram to determine masking
41  h = file.FindObject('TOP/good_hits')
42  if not h:
43  logging.warning(fileName + ' ... histogram good_hits not found')
44  return -1
45  if h.GetEntries() == 0:
46  logging.warning(fileName + ' ... histogram good_hits has no entries ... skipped')
47  return -1
48  return nev
49 
50 
51 # creates a file with histograms for masked channels and returns the total number of masked channels in a run
52 def makeChannelMasks(file, outFileName):
53 
54  masks = [TH1F('slot_' + str(slot), 'Channel mask for slot ' + str(slot),
55  512, 0.0, 512.0) for slot in range(1, 17)]
56  masked = 0
57 
58  # dead/hot channels: <10% or >1000% of the average in this slot
59  for slot in range(1, 17):
60  h = file.FindObject('TOP/good_channel_hits_' + str(slot))
61  if not h:
62  logging.error('no good_channel_hits found for slot'+str(slot))
63  continue
64  # calculate average number of hits per channel
65  mean = 0
66  n = 0
67  for chan in range(h.GetNbinsX()):
68  y = h.GetBinContent(chan+1)
69  if y > 0:
70  mean += y
71  n += 1
72  if n > 0:
73  mean /= n
74  # define threshold for dead and hot
75  deadCut = mean / 10
76  hotCut = mean * 10
77  for chan in range(h.GetNbinsX()):
78  y = h.GetBinContent(chan+1)
79  if y <= deadCut:
80  masks[slot-1].SetBinContent(chan+1, 1) # 1 = dead
81  masked += 1
82  elif y > hotCut:
83  masks[slot-1].SetBinContent(chan+1, 2) # 2 = noisy
84  masked += 1
85 
86  # asics with window corruption
87  for slot in range(1, 17):
88  h = file.FindObject('TOP/window_vs_asic_' + str(slot))
89  if not h:
90  logging.error('Error: no window_vs_asic found for slot' + str(slot))
91  continue
92  h0 = h.ProjectionX()
93  h1 = h.ProjectionX('_tmp', 222, 245)
94  for asic in range(h.GetNbinsX()):
95  if h0.GetBinContent(asic+1) > 0:
96  r = 1 - h1.GetBinContent(asic+1) / h0.GetBinContent(asic+1)
97  if r > 0.20:
98  for chan in range(8):
99  masks[slot-1].SetBinContent(asic*8+chan+1, 2) # mark as noisy
100  masked += 1
101 
102  # save to file
103  if masked < 3000: # don't save for nonsense
104  outfile = TFile(outFileName, 'recreate')
105  for h in masks:
106  h.Write()
107  outfile.Close()
108  return masked
109 
110 
111 experiment = 10
112 experimentstring = "{:04d}".format(experiment)
113 outdir = 'masks'
114 if not os.path.exists(outdir):
115  os.makedirs(outdir)
116 fileNames = sorted(glob.glob('/group/belle2/phase3/dqm/dqmsrv1/e'+experimentstring+'/dqmhisto/hltdqm*.root'))
117 
118 logging.basicConfig(level=logging.INFO, filename="channelmasking.log")
119 logging.info("Starting channelmasking from HLT histograms")
120 logging.info("Experiment: "+str(experiment))
121 
122 numFiles = len(fileNames)
123 if numFiles == 0:
124  logging.error('No files found, exiting')
125  sys.exit()
126 
127 for fileName in fileNames:
128  run = ((fileName.split('/')[-1]).split('r')[1]).split('.')[0] # exp7-8
129  outFileName = outdir + '/channelMask_e' + experimentstring + '_r' + run + '.root'
130 
131  # skip run if we analyzed this run already
132  if os.path.exists(outFileName) or os.path.exists(outFileName.replace('masks/', 'masks/imported/')):
133  logging.debug('Output file exists for run ='+str(run)+', skipping')
134  continue
135 
136  # open file and check if it is a good physics run
137  file = TFile(fileName)
138  if not file:
139  logging.error(fileName + ' ... cannot open')
140  continue
141  file.ReadAll()
142  nev = checkIfRunUsable(file)
143  if nev == -1:
144  file.Close()
145  continue
146 
147  masked = makeChannelMasks(file, outFileName)
148  logging.info(fileName + 'run =' + str(run) + 'events =' + str(nev) + 'masked channels =' + str(masked))
149  if masked > 3000:
150  logging.critical("Result looks completely wrong, over 3000 masked channels. Inspect run "+str(run))
151  file.Close()