ATLAS Offline Software
Loading...
Searching...
No Matches
dbgEventInfo.py
Go to the documentation of this file.
1#!/usr/bin/env python
2
3# Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
4
5# @brief: This is the dbgEventInfo class for the Debug Stream event analysis
6
7import eformat
8from ROOT import gStyle, gROOT, addressof, TTree, vector, string
9from TrigByteStreamTools.hltResultMT import get_collections
10
11import logging
12msg = logging.getLogger('PyJobTransforms.' + __name__)
13
15
16 def __init__(self, dbgStep='_Default', inputFile=''):
17 # Event Info Tree values
18 self.Run_Number = 0
19 self.Stream_Tag_Name = 'None'
20 self.Stream_Tag_Type = 'None'
21 self.Lvl1_ID = 0
22 self.Global_ID = 0
23 self.Lumiblock = 0
24 self.Node_ID = 0
25 self.HLT_Result = 'None'
28 self.HLT_Decision = 0
31 self.EventStatusNames = 'None'
32
33 #define the string length
34 self.strlength = 150
35
36 self.eventCounter = 0
37 self.rootDefinitions(dbgStep, inputFile)
38
39
40 # Full event Specific Status - based on ATL-DAQ-98-129
41 self.EventSpecificStatus = ['Reserved',
42 'Reserved',
43 'Reserved',
44 'HLTSV_DUPLICATION_WARN',
45 'Reserved',
46 'Reserved',
47 'Reserved',
48 'Reserved',
49 'DCM_PROCESSING_TIMEOUT',
50 'HLTPU_PROCESSING_TIMEOUT',
51 'DCM_DUPLICATION_WARN',
52 'DCM_RECOVERED_EVENT',
53 'PSC_PROBLEM',
54 'DCM_FORCED_ACCEPT',
55 'Reserved',
56 'PARTIAL_EVENT']
57
58 # Copied from TrigSteeringEvent/OnlineErrorCode.h
59 self.onlineErrorCode = ['UNCLASSIFIED',
60 'BEFORE_NEXT_EVENT',
61 'CANNOT_RETRIEVE_EVENT',
62 'NO_EVENT_INFO',
63 'SCHEDULING_FAILURE',
64 'CANNOT_ACCESS_SLOT',
65 'PROCESSING_FAILURE',
66 'NO_HLT_RESULT',
67 'OUTPUT_BUILD_FAILURE',
68 'OUTPUT_SEND_FAILURE',
69 'AFTER_RESULT_SENT',
70 'COOL_UPDATE',
71 'TIMEOUT',
72 'RESULT_TRUNCATION',
73 'MISSING_CTP_FRAGMENT',
74 'BAD_CTP_FRAGMENT']
75
76
77 def eventCount(self, event):
78 self.eventCounter += 1
79 msg.info('Running debug_stream analysis on event :{0}'.format(self.eventCounter))
80
81
82 def eventInfo(self, event, L1ChainNames, HLTChainNames):
83 # Fill all necessary information based on bs event info
84 self.Run_Number = event.run_no()
85 self.Global_ID = event.global_id()
86 self.Lumiblock = event.lumi_block()
87 self.Lvl1_ID = event.lvl1_id()
88
89 msg.debug("Event Counter Lvl1 ID = %s", self.Lvl1_ID & 0xffffff)
90 msg.debug("Event Counter Reset Counter Lvl1 ID = %s", (self.Lvl1_ID & 0xff000000) >> 24)
91
92 self.L1_Chain_Names = L1ChainNames
93 self.HLT_Chain_Names = HLTChainNames
94
95 streamtagNames = ','.join([tag.name for tag in event.stream_tag()])
96 self.Stream_Tag_Name = streamtagNames
97
98 streamtagTypes = ','.join([tag.type for tag in event.stream_tag()])
99 self.Stream_Tag_Type = streamtagTypes
100
101
102 # Check if the length of the Stream_Tag_Name & Stream_Tag_Type
103 # if too long then cut off the end so that the Root file can fill properly
104 if (len(self.Stream_Tag_Name) > self.strlength):
105 # print warning and cut out the string characters > strlength char
106 msg.warn("Stream_Tag_Name has length %s reducing to length %s",len(self.Stream_Tag_Name), self.strlength)
107 self.Stream_Tag_Name = self.Stream_Tag_Name[0:self.strlength]
108
109 if (len(self.Stream_Tag_Type) > self.strlength):
110 # print warning and cut out the string characters > strlength char
111 msg.warn("Stream_Tag_Type has length %s reducing to length %s",len(self.Stream_Tag_Type), self.strlength)
112 self.Stream_Tag_Type = self.Stream_Tag_Type[0:self.strlength]
113
114 self.eventStatus(event)
115 self.lvl1Info(event, L1ChainNames)
116 self.hltInfo(event, HLTChainNames)
117 self.hltResult(event)
118
119
120 def eventConfig(self, configKeys=None, event=None):
121 # Set configuration data: PSK and SMK
122 if configKeys:
123 for key in configKeys['HLTPSK']:
124 if event.lumi_block() >= key[1] and event.lumi_block() <= key[2]:
125 self.HLTPrescaleKey = key[0]
126 break
127
128 self.SuperMasterKey = configKeys['SMK']
129 elif event:
130 # Find TrigConfKeys EDM collection and extract data
131 for rob in event.children():
132 if rob.source_id().subdetector_id() != eformat.helper.SubDetector.TDAQ_HLT:
133 continue
134 collections = get_collections(rob, skip_payload=False)
135 configList = [c for c in collections if 'xAOD::TrigConfKeys_v' in c.name_persistent]
136
137 for conf in configList:
138 configKeys = conf.deserialise()
139 if configKeys:
140 self.HLTPrescaleKey = configKeys.hltpsk()
141 self.SuperMasterKey = configKeys.smk()
142 return
143
144 msg.info("Smk and hltpskey unavailable in this event")
145 else:
146 msg.info("Cannot retrieve smk and hltpskey")
147
148 msg.info('HLT_Configuration smk:{0} hltpskey :{1}'.format(self.SuperMasterKey, self.HLTPrescaleKey))
149
150
151 def eventStatus(self, event):
152 # Get full event specific status
153 # Based on ATL-DAQ-98-129 section 5.8.3
154
155 # Helper function to check if bit was on.
156 def getBit(word, index):
157 return (word >> index) & 0x1
158
159 # Get list of statuses based on passed bits
160 def checkBits(word, firstBit, lastBit, status):
161 statusList = []
162 for i in range(firstBit, lastBit):
163 if getBit(word, i):
164 # Get and index in status list
165 statusIdx = i - firstBit
166 statusList.append(status[statusIdx])
167
168 return statusList
169
170 # Check if the number of status words is >= 1
171 if event.status():
172 # Check second word of first status element with Full Event specific status
173 statusList = checkBits(event.status()[0], 16, 32, self.EventSpecificStatus)
174
175 # Check if PSC_PROBLEM bit was on and retrieve Online Error Codes
176 # stored in following event status words
177 if getBit(event.status()[0], 28):
178 statusLen = len(event.status())
179 if statusLen > 1:
180 # Skip first event - already analyzed
181 for i in range(1, statusLen):
182 #To protect against the repetition of the first event status element
183 #If the integer value of the current event status element is greater than the length of the onlineErrorCode list
184 #then skip over this element to the next
185 if int(event.status()[i]) >= len(self.onlineErrorCode):
186 continue
187 statusList.append(self.onlineErrorCode[int(event.status()[i])])
188 else:
189 msg.warn("Cannot find additional words for PSC_PROBLEM")
190
191 #If the number of status words is 0, set the statusList to an empty list
192 else:
193 statusList = []
194
195 #ensure EventStatusNames are None if statusList is empty
196 if statusList:
197 self.EventStatusNames = ','.join(str(name) for name in statusList)
198
199 msg.info('Event Status :%s', self.EventStatusNames)
200
201 # Check if the length of the EventStatusNames
202 # if too long then cut off the end so that the Root file can fill properly
203 if (len(self.EventStatusNames) > self.strlength):
204 # print warning and cut out the string characters > strlength char
205 msg.warn("EventStatusNames has length %s reducing to length %s",len(self.EventStatusNames), self.strlength)
207
208
209 def lvl1Info(self, event, L1ItemNames):
210 # Get LVL1 info for BP AV and AV-TrigIDs and store them in ROOT vectors
211 self.L1_Triggered_BP.clear()
212 self.L1_Triggered_AV.clear()
213 self.L1_Triggered_IDs.clear()
214
215 # Map not available
216 if not L1ItemNames:
217 return
218
219 # Decode Lvl1 trigger info
220 info = event.lvl1_trigger_info()
221 l1Bits = self.decodeTriggerBits(info, 3) # TBP, TAP, TAV
222
223 for id in l1Bits[0]:
224 if id in L1ItemNames:
225 self.L1_Triggered_BP.push_back(L1ItemNames[id])
226 else:
227 msg.debug('Item %s not found in the menu - probably is disabled', id)
228
229 for id in l1Bits[2]:
230 self.L1_Triggered_IDs.push_back(id)
231 try:
232 self.L1_Triggered_AV.push_back(L1ItemNames[id])
233 except TypeError:
234 msg.warn("Item name for ctpid %s not found!", id)
235
236 msg.info('LVL1 Triggered ID Chains AV : %s', l1Bits[2])
237
238
239 def hltInfo(self, event, HLTChainNames):
240 # Get HLT info and store it in ROOT vectors
241 self.HLT_Triggered_Names.clear()
242 self.HLT_Triggered_IDs.clear()
243
244 # Map not available
245 if not HLTChainNames:
246 return
247
248 # Find ROD minor version
249 version = (1,1)
250 for rob in event.children():
251 if rob.source_id().subdetector_id() == eformat.helper.SubDetector.TDAQ_HLT:
252 rod_version = rob.rod_version()
253 minor_version = rod_version.minor_version()
254 minor_version_M = (minor_version & 0xff00) >> 8
255 minor_version_L = minor_version & 0xff
256 version = (minor_version_M, minor_version_L)
257 break
258
259 # Version 1.0 has {passed, prescaled, rerun}, 1.1 and later only {passed, prescaled}
260 num_sets = 3 if version[0] < 1 or version==(1,0) else 2
261
262 # Decode HLT trigger info
263 info = event.event_filter_info()
264 chainList = self.decodeTriggerBits(info, num_sets)
265
266 for id in chainList[0]:
267 self.HLT_Triggered_IDs.push_back(id)
268 try:
269 self.HLT_Triggered_Names.push_back(HLTChainNames[id])
270 except TypeError:
271 msg.warn("Chain name for counter %s not found!", id)
272
273 msg.info('HLT Triggered ID Chains : %s', chainList[0])
274
275
276 # Copied from ​TrigTools/TrigByteStreamTools/trigbs_dumpHLTContentInBS_run3.py
277 def decodeTriggerBits(self, words, num_sets, base=32):
278 assert len(words) % num_sets == 0
279 n_words_per_set = len(words) // num_sets
280 result = []
281 for iset in range(num_sets):
282 words_in_set = words[iset*n_words_per_set:(iset+1)*n_words_per_set]
283 bit_indices = []
284 for iw in range(len(words_in_set)):
285 bit_indices.extend([base*iw+i for i in range(base) if words_in_set[iw] & (1 << i)])
286 result.append(bit_indices)
287 return result
288
289
290 # If line 246 not possible - to delete
291 def getChain(self, counter, s):
292 # Prints chains and their information
293 from cppyy.gbl import HLT
294 ch = HLT.Chain(s)
295 ch.deserialize(s)
296 try:
297 msg.info('.... chain {0:-3d}: {1} Counter: {2:-4d} Passed: {3} (Raw: {4} Prescaled: {5} PassThrough: {6}) Rerun: {7} LastStep: {8} Err: {9}'
298 .format(counter, self.HLT_Chain_Names[ch.getChainCounter()], ch.getChainCounter(), ch.chainPassed(), ch.chainPassedRaw(),
299 ch.isPrescaled(), ch.isPassedThrough(), ch.isResurrected(), ch.getChainStep(), ch.getErrorCode().str()))
300 except IndexError:
301 msg.warn("Chain with counter %s not found", ch.getChainCounter())
302
303
304 # If line 246 not possible - to delete
305 def getAllChains(self, blob):
306 msg.info('... chains: %s', len(blob))
307 for i in range(len(blob)):
308 self.getChain(i, blob[i])
309
310
311 def hltResult(self, event):
312 # Get the hlt result, status, decision etc if hlt_result exist
313 hltResultFound = False
314 for rob in event.children():
315 if rob.source_id().subdetector_id() == eformat.helper.SubDetector.TDAQ_HLT:
316 msg.info('.. {0} source: {1} source ID: 0x{2:x} size: {3}'
317 .format(rob.__class__.__name__, rob.source_id(), rob.source_id().code(), rob.fragment_size_word()*4))
318 try:
319 msg.info('version :%s', rob.rod_version())
320 msg.info('l1id :%s', event.lvl1_id())
321
322 self.Node_ID = rob.source_id().module_id()
323
324 # TODO chains and navigation printouts - needs ATR-22653
325
326 # ROBs are created only for accepted events
327 self.HLT_Decision = 1
328 hltResultFound = True
329
330 except Exception as ex:
331 msg.info('... **** problems in analyzing payload %s', ex)
332 msg.info('... **** raw data[:10] %s', list(rob.rod_data())[:10])
333 msg.info('.. EOF HLTResult for HLT')
334
335 if not hltResultFound:
336 msg.info('No HLT Result for HLT')
337
338 msg.info('HLT Decision :%s', self.HLT_Decision)
339
340
341 def fillTree(self):
342 # Fill Event_Info Tree
343 self.Event_Info.Run_Number = self.Run_Number
344 self.Event_Info.Stream_Tag_Name = self.Stream_Tag_Name
345 self.Event_Info.Stream_Tag_Type = self.Stream_Tag_Type
346 self.Event_Info.Lvl1_ID = self.Lvl1_ID
347 self.Event_Info.Global_ID = self.Global_ID
348 self.Event_Info.Node_ID = self.Node_ID
349 self.Event_Info.Lumiblock = self.Lumiblock
350 self.Event_Info.SuperMasterKey = self.SuperMasterKey
351 self.Event_Info.HLTPrescaleKey = self.HLTPrescaleKey
352 self.Event_Info.HLT_Decision = self.HLT_Decision
353 self.Event_Info.EventStatusNames = self.EventStatusNames
354
355 self.event_info_tree.Fill()
356
357
358 def rootDefinitions(self,dbgStep,inputFile):
359 gStyle.SetCanvasColor(0)
360 gStyle.SetOptStat(000000)
361 gROOT.SetStyle("Plain")
362
363
364 # Create new ROOT Tree to store debug info
365 if dbgStep == "_Pre" :
366 gROOT.ProcessLine("#define STRINGLENGTH "+str(self.strlength))
367 gROOT.ProcessLine(
368 "struct EventInfoTree {\
369 Int_t Run_Number;\
370 Char_t Stream_Tag_Name[STRINGLENGTH];\
371 Char_t Stream_Tag_Type[STRINGLENGTH];\
372 UInt_t Lvl1_ID;\
373 ULong_t Global_ID;\
374 Int_t Lumiblock;\
375 Int_t Node_ID;\
376 ULong_t SuperMasterKey;\
377 ULong_t HLTPrescaleKey;\
378 Int_t HLT_Decision;\
379 Char_t EventStatusNames[STRINGLENGTH];\
380 };" )
381
382 # Bind the ROOT tree with EventInfo class members
383 from ROOT import EventInfoTree
384 self.Event_Info = EventInfoTree()
385 self.event_info_tree = TTree('Event_Info' + dbgStep, inputFile)
386
387 self.event_info_tree.Branch('Run_Number', addressof(self.Event_Info, 'Run_Number'), 'run_Number/I')
388 self.event_info_tree.Branch('Stream_Tag_Name', addressof(self.Event_Info, 'Stream_Tag_Name'), 'stream_Tag_Name/C')
389 self.event_info_tree.Branch('Stream_Tag_Type', addressof(self.Event_Info, 'Stream_Tag_Type'), 'stream_Tag_Type/C')
390 self.event_info_tree.Branch('Lvl1_ID', addressof(self.Event_Info, 'Lvl1_ID'), 'lvl1_ID/I')
391 self.event_info_tree.Branch('Global_ID', addressof(self.Event_Info, 'Global_ID'), 'global_ID/I')
392 self.event_info_tree.Branch('Lumiblock', addressof(self.Event_Info, 'Lumiblock'), 'lumiblock/I')
393 self.event_info_tree.Branch('Node_ID', addressof(self.Event_Info, 'Node_ID'), 'node_ID/I')
394 self.event_info_tree.Branch('SuperMasterKey', addressof(self.Event_Info, 'SuperMasterKey'), 'superMasterKey/I')
395 self.event_info_tree.Branch('HLTPrescaleKey', addressof(self.Event_Info, 'HLTPrescaleKey'), 'hltPrescaleKey/I')
396 self.event_info_tree.Branch('HLT_Decision', addressof(self.Event_Info, 'HLT_Decision'), 'hLT_Decision/I')
397 self.event_info_tree.Branch('EventStatusNames', addressof(self.Event_Info, 'EventStatusNames'), 'eventStatusNames/C')
398
399 # Setup vector data
400 self.L1_Triggered_AV = vector( string )()
401 self.L1_Triggered_BP = vector( string )()
402 self.L1_Triggered_IDs = vector( int )()
403 self.HLT_Triggered_Names = vector( string )()
404 self.HLT_Triggered_IDs = vector( int )()
405
406 self.event_info_tree._L1_Triggered_BP = self.L1_Triggered_BP
407 self.event_info_tree._L1_Triggered_AV = self.L1_Triggered_AV
408 self.event_info_tree._L1_Triggered_IDs = self.L1_Triggered_IDs
409 self.event_info_tree._HLT_Triggered_Names = self.HLT_Triggered_Names
410 self.event_info_tree._HLT_Triggered_IDs = self.HLT_Triggered_IDs
411
412 self.event_info_tree.Branch('L1_Triggered_BP', self.L1_Triggered_BP)
413 self.event_info_tree.Branch('L1_Triggered_AV', self.L1_Triggered_AV)
414 self.event_info_tree.Branch('L1_Triggered_IDs', self.L1_Triggered_IDs)
415 self.event_info_tree.Branch('HLT_Triggered_Names', self.HLT_Triggered_Names)
416 self.event_info_tree.Branch('HLT_Triggered_IDs', self.HLT_Triggered_IDs)
417
static bool getBit(unsigned char field, unsigned num)
This class represents one chain of signatures, i.e.
Definition Chain.h:64
__init__(self, dbgStep='_Default', inputFile='')
hltInfo(self, event, HLTChainNames)
rootDefinitions(self, dbgStep, inputFile)
eventInfo(self, event, L1ChainNames, HLTChainNames)
decodeTriggerBits(self, words, num_sets, base=32)
eventConfig(self, configKeys=None, event=None)
lvl1Info(self, event, L1ItemNames)