ATLAS Offline Software
LArRawChannelMonAlg.py
Go to the documentation of this file.
1 #
2 # Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3 #
4 
5 """!@file LArRawChannelMonAlg.py
6 @date Nov. 2021
7 @brief configuration of LArRawChannels monitoring algorithm following
8 the implementation model of other LAr DQM algorithms, and default
9 settings taken from LArMonTools/LArRawChannelMonTool_joboptions.py
10 """
11 
12 from LArMonitoring.GlobalVariables import lArDQGlobals
13 from GaudiKernel.SystemOfUnits import MeV, GeV
14 
15 _USE_LEGACY_BINNING_IN_ENDCAPS = True
16 
17 
19  from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
20  from AthenaConfiguration.ComponentFactory import CompFactory
21  from AthenaMonitoring import AthMonitorCfgHelper
22  from CaloTools.CaloNoiseCondAlgConfig import CaloNoiseCondAlgCfg
23  from AthenaMonitoring.AtlasReadyFilterConfig import AtlasReadyFilterCfg
24  from AthenaConfiguration.Enums import BeamType
25  cosmics = (flags.Beam.Type is BeamType.Cosmics)
26  stream = _get_stream(flags.DQ)
27  try:
28  signal = flags.LArMon.doLArRawMonitorSignal
29  except AttributeError:
30  signal = False
31  helper = AthMonitorCfgHelper(flags, 'LArRawChannelMonAlgCfg')
33  helper, instance=CompFactory.LArRawChannelMonAlg,
34  flags=flags, cosmics=cosmics, stream=stream, doSignal=signal)
35  noise_alg = CaloNoiseCondAlgCfg(flags, noisetype=alg.NoiseKey.Path)
36  accumulator = ComponentAccumulator()
37  accumulator.merge(noise_alg)
38  alg.AtlasReadyFilterTool.append(
39  accumulator.popToolsAndMerge(AtlasReadyFilterCfg(flags)))
40  accumulator.merge(helper.result())
41  return accumulator
42 
43 
44 def LArRawChannelMonConfigCore(helper, instance, flags, cosmics, stream, doSignal):
45  alg = helper.addAlgorithm(instance, 'LArRawChannelMonAlg')
46  alg.occupancy_thresholds = [
47  100 * MeV, # EMBA
48  100 * MeV, # EMBC
49  100 * MeV, # EMECA
50  100 * MeV, # EMECC
51  500 * MeV, # HECA
52  500 * MeV, # HECC
53  700 * MeV, # FCALA
54  700 * MeV, # FCALC
55  ]
56  alg.signal_thresholds = [-9999. * GeV ] * 8
57  alg.pos_noise_thresholds = [3] * 8
58  alg.neg_noise_thresholds = [3] * 8
59  alg.bcid_signal_threshold = 500. * MeV
60 
61  alg.time_threshold = 5
62  alg.quality_threshold = 65530
63  alg.noise_threshold = 3
64  alg.noise_burst_percent_threshold = [
65  1, # EMBA
66  1, # EMBC
67  1, # EMECA
68  1, # EMECC
69  1, # HECA
70  1, # HECC
71  2, # FCALA
72  2, # FCALC
73  ]
74  alg.noise_burst_nChannel_threshold = [10] * 8
75  alg.monitor_occupancy = True # False
76  if cosmics:
77  alg.NoiseKey = 'electronicNoise'
78  alg.monitor_signal = True
79  alg.monitor_positive_noise = True
80  alg.monitor_negative_noise = True
81  else:
82  alg.NoiseKey = 'totalNoise'
83  alg.monitor_signal = doSignal
84  alg.monitor_positive_noise = doSignal
85  alg.monitor_negative_noise = doSignal
86  alg.monitor_time = False
87  alg.monitor_quality = doSignal
88  alg.monitor_burst = True
89  if stream in ('express', 'RNDM'):
90  alg.noise_streams = ['RNDM']
91  alg.TriggerChain = 'L1_RD0_EMPTY'
92  else:
93  alg.noise_streams = ['RNDM']
94  alg.ProblemsToMask = [
95  'highNoiseHG',
96  'highNoiseMG',
97  'highNoiseLG',
98  'deadReadout',
99  'deadPhys',
100  'almostDead',
101  'short',
102  'sporadicBurstNoise',
103  ]
104  alg.db_and_ofc_only = True
105 
106  from LArConfiguration.LArConfigFlags import RawChannelSource
107  if flags.LAr.RawChannelSource is RawChannelSource.Calculated:
108  alg.LArRawChannelContainerKey="LArRawChannels_FromDigits"
109 
110  # Histograms for different partitions are handled together via a
111  # GenericMonitoringArray, but since some of the ranges and titles
112  # vary between partitions, the definition of histograms must be
113  # done separately for each partition, using the 'pattern' argument:
114  montool = helper.addArray([lArDQGlobals.Partitions], alg,
115  'LArRawChannelMon', topPath='/LAr/RawChannel')
116  for index, partition in enumerate(lArDQGlobals.Partitions):
117  _define_histograms(partition, index, montool, alg)
118  return alg
119 
120 
121 def _define_histograms(partition, part_index, montool, alg):
122  common_args = {
123  'path': '{0}',
124  'pattern': [partition],
125  'opt' : 'kAlwaysCreate'
126  # 'merge' unspecified: the default should suit all histograms
127  }
128  hargs2d = {
129  **common_args,
130  'type': 'TH2I',
131  **_superslot_channel_axis_ranges(partition),
132  }
133  lumiblock_binning = {'xbins': 3000, 'xmin': 0.5, 'xmax': 3000.5}
134  title = ' as a function of FEB and channel in {0};' \
135  'Halfcrate (+ increasing slot);Channel'
136  sigma_pos = '{:g}#sigma'.format(alg.pos_noise_thresholds[part_index])
137  sigma_neg = '{:g}#sigma'.format(alg.neg_noise_thresholds[part_index])
138  montool.defineHistogram(
139  'S,C;{0}_occupancy', **hargs2d,
140  cutmask='occ',
141  title='Number of events above {:g} MeV{}'.format(
142  alg.occupancy_thresholds[part_index] / MeV,
143  title))
144  hargs2d['type'] = 'TProfile2D'
145  title = title.replace('{0}', '{0} (no LArEventInfo::ERROR)')
146  if alg.monitor_signal:
147  montool.defineHistogram(
148  'S,C,E;{0}_signal_AVG', **hargs2d,
149  cutmask='sig',
150  title='{0}{1};{0}'.format('Average Energy (MeV)', title))
151  montool.defineHistogram(
152  'S,C,G;{0}_gain', **hargs2d,
153  cutmask='sig',
154  title='{0}{1};{0}'.format('Average gain', title))
155  title += ';Percentage Accepted'
156  percent = 'Percentage of events '
157  if alg.monitor_positive_noise:
158  montool.defineHistogram(
159  'S,C,posn;{0}_acceptance_AVG', **hargs2d,
160  title='{} above {} total noise{}'.format(
161  percent, sigma_pos, title))
162  if alg.monitor_negative_noise:
163  montool.defineHistogram(
164  'S,C,negn;{0}_noise_acceptance_AVG', **hargs2d,
165  title='{} below -{} total noise{}'.format(
166  percent, sigma_neg, title))
167  if alg.monitor_quality:
168  montool.defineHistogram(
169  'S,C,Q4k;{0}_quality_AVG', **hargs2d,
170  title='{} with q-factor above {:g}{}'.format(
171  percent, alg.quality_threshold, title))
172  if alg.monitor_quality:
173  montool.defineHistogram(
174  'nQ4k;{0}_quality_nChannel', **common_args,
175  type='TH1D', xbins=50, xmin=-0.5, xmax=49.5,
176  title = 'Number of channels in {{0}} with q-factor > {};' \
177  'Number of channels;Number of events per channel'.format(
178  alg.quality_threshold))
179  montool.defineHistogram(
180  'lb;{0}_quality_burst', **common_args,
181  type='TH1D', **lumiblock_binning, cutmask='qburst',
182  title = 'Number of events with more than {:g}% ' \
183  'of all channels in {{0}} reporting q-factor > {};' \
184  'Luminosity Block;Number of events per LB'.format(
185  alg.noise_burst_percent_threshold[part_index],
186  alg.quality_threshold))
187  if alg.monitor_burst:
188  title = 'Yield of channels with E > +{t} in {{0}}{cut};' \
189  'Percent of channels;Number of events per 0.02%'
190  hargs = {
191  **common_args,
192  'type': 'TH1D',
193  'xbins': 375,
194  'xmin': 0.,
195  'xmax': 7.5
196  }
197  name = '%noisy;{0}_noise_fraction'
198  montool.defineHistogram(
199  name, **hargs, title=title.format(t=sigma_pos, cut=''))
200  montool.defineHistogram(
201  '%noisy_neg;{0}_noise_fraction_Neg', **hargs,
202  title=title.replace('> +', '< -').format(t=sigma_neg, cut=''))
203  montool.defineHistogram(
204  name + '_W', **hargs, cutmask='quietW',
205  title=title.format(t=sigma_pos, cut=' (no LArNoisyRO_StdOpt)'))
206  montool.defineHistogram(
207  name + '_NoLArNoisyRO', **hargs, cutmask='quiet',
208  title=title.format(t=sigma_pos, cut=' (no LArNoisyRO_Std)'))
209  montool.defineHistogram(
210  name + '_TimeVetoLArNoisyRO', **hargs, cutmask='quietITW',
211  title=title.format(t=sigma_pos, cut=' (time vetoed)'))
212  title = 'Number of events with Y(3#sigma) > {t} in {{0}}{cut};' \
213  'Luminosity Block;Number of events per LB'
214  hargs = {**common_args, 'type': 'TH1D', **lumiblock_binning}
215  tb = '{:g}%'.format(alg.noise_burst_percent_threshold[part_index])
216  montool.defineHistogram(
217  'lb;{0}_burst', **hargs, cutmask='burst',
218  title=title.format(t=tb, cut=''))
219  montool.defineHistogram(
220  'lb;{0}_timeVetoBurst', **hargs, cutmask='burst_quietW',
221  title=title.format(t=tb, cut=' (time vetoed)'))
222  if alg.monitor_time:
223  montool.defineHistogram(
224  'T;{0}_mean_feb_time', **common_args, type='TH1D',
225  xbins=101, xmin=-50.5, xmax=50.5,
226  title='Average time of channels in each FEB of {{0}} ' \
227  'reporting E > {} #sigma;<t(FEB)> - <t(event)> (ns);' \
228  'Number of FEBs per ns'.format(alg.time_threshold))
229  if alg.monitor_signal:
230  montool.defineHistogram(
231  'lb,detE;{0}_pedestal_evolution', **common_args, type='TProfile',
232  **lumiblock_binning, cutmask='quietW',
233  title='Energy sum (time vetoed) in {0};' \
234  'Luminosity Block;Mean total energy(MeV)')
235  montool.defineHistogram(
236  'bc,detE;{0}_sumE_vs_BCID', **common_args, type='TProfile',
237  xbins=3564, xmin=0.5, xmax=3564.5,
238  title = 'Energy sum per bunch crossing in {0};' \
239  'Bunch Crossing ID;Mean total energy (MeV)')
240 
241 
242 def _get_stream(flags):
243  from AthenaCommon.AthenaCommonFlags import athenaCommonFlags
244  flag = flags.useTrigger
245  if callable(flag): flag = flag()
246  if flag and not athenaCommonFlags.isOnline():
247  from PyUtils.MetaReaderPeeker import metadata
248  return (metadata.get('stream', '') + '_').split('_')[1]
249  return ''
250 
251 
253  n = lArDQGlobals.Feedthrough_Slot_Nbins.get(partition, 1)
254  bins = lArDQGlobals.Feedthrough_Slot_range.get(partition, (0., 1.))
255  labels = ['?'] * n
256  if partition.startswith('EMB'):
257  if len(lArDQGlobals.Feedthrough_Slot_labels_Barrel) == n:
258  labels = lArDQGlobals.Feedthrough_Slot_labels_Barrel
259  elif len(lArDQGlobals.Feedthrough_Slot_labels_Endcap) == n:
260  labels = lArDQGlobals.Feedthrough_Slot_labels_Endcap
261  axis_ranges = {
262  'xbins': n,
263  'xmin': bins[0],
264  'xmax': bins[1],
265  'xlabels': labels,
266  'ybins': lArDQGlobals.FEB_N_channels,
267  'ymin': -0.5,
268  'ymax': lArDQGlobals.FEB_N_channels - 0.5,
269  }
270  if _USE_LEGACY_BINNING_IN_ENDCAPS and not partition.startswith('EMB'):
271  merged_bins = {
272  'EMEC': [
273  (14, 15), (29, 30), (48, 60), (74, 75), (89, 105), (119, 120),
274  (134, 135), (153, 165), (179, 180), (194, 195), (209, 210),
275  (224, 225), (243, 255), (269, 270), (284, 285), (299, 300),
276  (314, 315), (333, 345), (359, 360), (374, 375)
277  ],
278  'HEC': [
279  (1, 49), (56, 154), (161, 244), (251, 334), (341, 375)
280  ],
281  'FCal': [(1, 90), (106, 375)],
282  }
283  bins = [0.5]
284  for b in merged_bins[partition[:-1]]:
285  bins += [x + 0.5 for x in range(int(bins[-1] + 0.5), b[0])]
286  bins.append(b[1] + 0.5)
287  axis_ranges['xbins'] = bins
288  # Try to obtain meaningful bin labels from GlobalVariables.py:
289  if n > 1 and axis_ranges['xmax'] > axis_ranges['xmin']:
290  labels = [''] * (len(bins) - 1)
291  coeff = n / (axis_ranges['xmax'] - axis_ranges['xmin'])
292  nslots = lArDQGlobals.FEB_Slot[partition][1]
293  for b, x in enumerate(bins[:-1]):
294  i = (int(coeff * (x - axis_ranges['xmin'])))
295  i -= (i % nslots)
296  if bins[b+1] - x < 1.5 and 0 <= i < n:
297  txt = axis_ranges['xlabels'][i]
298  if txt not in labels:
299  labels[b] = txt
300  axis_ranges['xlabels'] = labels
301  else:
302  axis_ranges.pop('xlabels')
303  axis_ranges.pop('xmin')
304  axis_ranges.pop('xmax')
305  return axis_ranges
306 
307 
308 if __name__=='__main__':
309  from AthenaConfiguration.AllConfigFlags import initConfigFlags
310  flags = initConfigFlags()
311 
312  from AthenaCommon.Logging import log
313  from AthenaCommon.Constants import WARNING
314  log.setLevel(WARNING)
315 
316  from LArMonitoring.LArMonConfigFlags import addLArMonFlags
317  flags.addFlagsCategory("LArMon", addLArMonFlags)
318 
319  from AthenaConfiguration.TestDefaults import defaultTestFiles
320  from AthenaConfiguration.Enums import BeamType
321  flags.Input.Files = defaultTestFiles.RAW_RUN2
322  flags.Output.HISTFileName = 'LArRawChannelMonOutput.root'
323  flags.DQ.enableLumiAccess = False
324  flags.DQ.useTrigger = False
325  flags.Beam.Type = BeamType.Collisions
326  flags.lock()
327 
328  from CaloRec.CaloRecoConfig import CaloRecoCfg
329  cfg = CaloRecoCfg(flags)
331  cfg.merge(acc)
332  f = open("LArRawChannelMon.pkl", "wb")
333  cfg.store(f)
334  f.close()
335 
336  #in case you need directly run uncomment:
337  #cfg.run(100)
python.CaloRecoConfig.CaloRecoCfg
def CaloRecoCfg(flags, clustersname=None)
Definition: CaloRecoConfig.py:9
LArRawChannelMonAlg.LArRawChannelMonConfigCore
def LArRawChannelMonConfigCore(helper, instance, flags, cosmics, stream, doSignal)
Definition: LArRawChannelMonAlg.py:44
python.JetAnalysisCommon.ComponentAccumulator
ComponentAccumulator
Definition: JetAnalysisCommon.py:302
vtune_athena.format
format
Definition: vtune_athena.py:14
CaloCellPos2Ntuple.int
int
Definition: CaloCellPos2Ntuple.py:24
LArRawChannelMonAlg._get_stream
def _get_stream(flags)
Definition: LArRawChannelMonAlg.py:242
LArRawChannelMonAlg._superslot_channel_axis_ranges
def _superslot_channel_axis_ranges(partition)
Definition: LArRawChannelMonAlg.py:252
master.flag
bool flag
Definition: master.py:29
python.CaloNoiseCondAlgConfig.CaloNoiseCondAlgCfg
def CaloNoiseCondAlgCfg(flags, noisetype="totalNoise")
Definition: CaloNoiseCondAlgConfig.py:11
plotBeamSpotVxVal.range
range
Definition: plotBeamSpotVxVal.py:195
Constants
some useful constants -------------------------------------------------—
LArRawChannelMonAlg.LArRawChannelMonConfig
def LArRawChannelMonConfig(flags)
Definition: LArRawChannelMonAlg.py:18
python.AtlasReadyFilterConfig.AtlasReadyFilterCfg
def AtlasReadyFilterCfg(flags)
Definition: AtlasReadyFilterConfig.py:10
LArRawChannelMonAlg._define_histograms
def _define_histograms(partition, part_index, montool, alg)
Definition: LArRawChannelMonAlg.py:121
Trk::open
@ open
Definition: BinningType.h:40
python.AllConfigFlags.initConfigFlags
def initConfigFlags()
Definition: AllConfigFlags.py:19
Trk::split
@ split
Definition: LayerMaterialProperties.h:38