ATLAS Offline Software
CTPfragment.py
Go to the documentation of this file.
1 # Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
2 
3 """
4 Minimal python module for CTP fragment access/modification
5 
6 For C++ implementation see:
7 https://gitlab.cern.ch/atlas-tdaq-software/CTPfragment
8 """
9 
10 import sys
11 import eformat
12 import cppyy
13 
14 from PyUtils.Helpers import ROOT6Setup
15 ROOT6Setup()
16 
17 cppyy.load_library('libTrigByteStreamToolsDict')
18 cppyy.load_library('libCTPfragment')
19 from ROOT import CTPdataformat
20 from ROOT import CTPfragment as _CTPfragment
21 from ROOT.CTPfragment import getFolderUpdates # noqa: F401 (import into our namespace)
22 
23 # Import classes from C++ namespace
24 FolderEntry = _CTPfragment.FolderEntry
25 ExtraPayload = _CTPfragment.ExtraPayload
26 
27 def _versioned(obj, name, version):
28  """Helper to return versioned members of CTPdataformat"""
29  attr = ''
30  v = version
31  while v>=0: # decrement version until found
32  attr = '%s_v%d' % (name, v)
33  if hasattr(obj,attr):
34  break
35  v -= 1
36  return getattr(obj,attr)
37 
38 def _setBits32(bitset, value, shift, mask):
39  """Set value in bitset using mask and shifting n bits to the left"""
40  v = bitset & (0xffffffff ^ (mask << shift))
41  v = v | (value << shift)
42  return v
43 
45  """Return list of bits [0,1,1,0,...] from list of 32-bit trigger words"""
46  if type(info)==int:
47  info=[info]
48  bits=[]
49  cnt=0
50  for word in info:
51  for i in range(32):
52  if word&(1<<i):
53  bits+=[cnt]
54  cnt+=1
55  return bits
56 
57 def encodeTriggerBits(bits,len=1):
58  """Return list of trigger words from list of bits"""
59  words = [0] * len
60  for bit in bits:
61  words[bit//32] |= 1<<(bit%32)
62  return words
63 
65  """Get CTP fragment format version"""
66  v = (rob.rod_minor_version() >> CTPdataformat.CTPFormatVersionShift) & CTPdataformat.CTPFormatVersionMask
67  return v
68 
69 def setCtpFormatVersion(rob, version):
70  """Set CTP fragment format version"""
71  V = _setBits32(rob.rod_minor_version(), version,
72  CTPdataformat.CTPFormatVersionShift, CTPdataformat.CTPFormatVersionMask)
73  rob.rod_minor_version(V)
74 
75 def hltCounter(rob):
76  """Get HLT counter"""
77  v = ctpFormatVersion(rob)
78  return (rob.rod_detev_type() >> _versioned(CTPdataformat,'HltCounterShift',v) & _versioned(CTPdataformat,'HltCounterMask',v))
79 
80 def setHltCounter(rob, hltCounter):
81  """Set HLT counter"""
82  v = ctpFormatVersion(rob)
83  c = _setBits32(rob.rod_detev_type(), hltCounter, _versioned(CTPdataformat,'HltCounterShift',v), _versioned(CTPdataformat,'HltCounterMask',v))
84  rob.rod_detev_type(c)
85 
86 def lumiBlock(rob):
87  return (rob.rod_detev_type() >> CTPdataformat.LumiBlockShift & CTPdataformat.LumiBlockMask)
88 
89 def setLumiBlock(rob, lb):
90  lbits = _setBits32(rob.rod_detev_type(), lb, CTPdataformat.LumiBlockShift, CTPdataformat.LumiBlockMask)
91  rob.rod_detev_type(lbits)
92 
94  """Number extra payload words (this includes the time since last L1A)"""
95  v = ctpFormatVersion(rob)
96  if v < 2:
97  return 0
98  else:
99  return ((rob.rod_minor_version() >> _versioned(CTPdataformat,'ProgrammableExtraWordsShift',v)
100  & _versioned(CTPdataformat,'ProgrammableExtraWordsMask',v)))
101 
103  """Number extra payload words (this does NOT include the time since last L1A)"""
104  return max(numberExtraPayloadWords(rob)-1, 0)
105 
108  offset = 0
109  if ctpFormatVersion(rob)>=3:
110  offset = 1 # for turn counter
111  return rob.rod_data()[-numberHltExtraPayloadWords(rob)+offset:] if n>0 else []
112 
114  """Return CTPfragment::ExtraPayload object created from CTP ROB"""
115  v = cppyy.gbl.std.vector('unsigned int')()
116  for p in hltExtraPayloadWords(rob):
117  v.push_back(p)
118 
119  x = _CTPfragment.ExtraPayload(v)
120  return x
121 
122 def setHltExtraPayloadWords(rob, extraWords):
123 
124  # Make writable ROB
125  wrob = eformat.write.ROBFragment(rob)
126  # Copy ROD data, except extra words
127  data = [d for d in wrob.rod_data()]
129  if n>0:
130  data = data[:-n]
131  # Append new extra words and set in ROB
132  v = ctpFormatVersion(wrob)
133  if v<2:
134  setCtpFormatVersion(wrob, 2) # need at least V2
135  data.extend([0]) # time since last L1A
136  data.extend(extraWords)
137  wrob.rod_data(data)
138 
139  # Set new payload length (including words reserved by CTP)
140  ctp_extras = 1 # time since last L1A
141  if v>=3:
142  ctp_extras = 2 # turn counter
143  V = _setBits32(wrob.rod_minor_version(), len(extraWords)+ctp_extras,
144  _versioned(CTPdataformat,'ProgrammableExtraWordsShift',v),
145  _versioned(CTPdataformat,'ProgrammableExtraWordsMask',v))
146  wrob.rod_minor_version(V)
147 
148  return wrob.readonly()
149 
151  """Get position of LVL1-Accept Bunch from ROD Fragment"""
152 
153  v = ctpFormatVersion(rob)
154  shift = _versioned(CTPdataformat,'L1APositionShift',v)
155  if v==0:
156  return (rob.rod_detev_type() >> shift) & CTPdataformat.L1APositionMask
157  else:
158  return (rob.rod_minor_version() >> shift) & CTPdataformat.L1APositionMask
159 
160 def getTriggerWords(rob,name='TAV'):
161  """Get trigger words"""
162 
163  name = name.upper()
164  v = ctpFormatVersion(rob)
165  pos = _versioned(CTPdataformat,name+'pos',min(v,4))
166  words = _versioned(CTPdataformat,name+'words',min(v,4))
167  # No TAP in RoI ROB
168  if v>4 and rob.source_id().module_id()==1:
169  pos = _versioned(CTPdataformat,name+'pos',5)
170  if name=='TAP':
171  return []
172 
173  l1abunch = 0 if rob.source_id().module_id()==1 else lvl1AcceptBunch(rob)
174 
175  data = [d for d in rob.rod_data()]
176  pos = l1abunch*_versioned(CTPdataformat,'DAQwordsPerBunch',v) + pos
177  return data[pos:pos+words]
178 
179 #
180 # For testing
181 #
182 
183 def main():
184  from optparse import OptionParser
185  import eformat
186 
187  parser = OptionParser(usage='%prog FILE')
188  parser.add_option('-m', '--moduleid', type='int', action='store', default=0,
189  help='Module ID of CTP fragment [%default]')
190 
191  (opt, args) = parser.parse_args()
192  if len(args)!=1:
193  parser.print_help()
194  return 1
195 
196  for event in eformat.istream(args[0]):
197  ctp_robs = [rob for rob in event.children()
198  if rob.source_id().subdetector_id() == eformat.helper.SubDetector.TDAQ_CTP
199  and rob.source_id().module_id() == opt.moduleid]
200 
201  if len(ctp_robs)==0:
202  print("Cannot find CTP ROB with module ID %d" % opt.moduleid)
203  continue
204 
205  rob = ctp_robs[0]
206  fe = _CTPfragment.FolderEntry()
207  fe.folderIndex = 1
208  fe.lumiBlock = 54
209 
210  fe2 = _CTPfragment.FolderEntry()
211  fe2.folderIndex = 2
212  fe2.lumiBlock = 59
213 
214  #x = getExtraPayloadObject(rob)
215  x = _CTPfragment.ExtraPayload()
216  x.setL1PSK(255)
217  x.updateFolder(fe)
218  x.updateFolder(fe2)
219  new_ctp_rob = setHltExtraPayloadWords(rob, [d for d in x.serialize()])
220  new_event = eformat.write.FullEventFragment()
221  new_event.copy_header(event)
222  for r in event.children():
223  if r.source_id().subdetector_id() != eformat.helper.SubDetector.TDAQ_CTP:
224  new_event.append(eformat.write.ROBFragment(r))
225 
226  new_event.append(eformat.write.ROBFragment(new_ctp_rob))
227 
228  event = new_event.readonly()
229  #new_ctp_rob = eformat.write.ROBFragment(new_ctp_rob)
230  #setHltCounter(new_ctp_rob,100)
231  rob = new_ctp_rob
232 
233  x = getExtraPayloadObject(rob)
234  folderUpdates = _CTPfragment.getFolderUpdates(x)
235  upd = ''
236  for f in folderUpdates:
237  upd += ('[%d,%d]' % (f.second.folderIndex,f.second.lumiBlock))
238 
239  print("L1ID %10d, LB %4d, Version %d, Bunch %d, HLT counter: %3d, Payload #%d %s L1PSK %d BGK %d COOLUPD %s" % (
240  event.lvl1_id(),
241  event.lumi_block(),
242  ctpFormatVersion(rob),
243  lvl1AcceptBunch(rob),
244  hltCounter(rob),
247  x.getL1PSK(),
248  x.getBGK(),
249  upd
250  ))
251 
252 if __name__ == "__main__":
253  sys.exit(main())
254 
python.CTPfragment.setHltExtraPayloadWords
def setHltExtraPayloadWords(rob, extraWords)
Definition: CTPfragment.py:122
max
#define max(a, b)
Definition: cfImp.cxx:41
python.CTPfragment._versioned
def _versioned(obj, name, version)
Definition: CTPfragment.py:27
python.CTPfragment.numberExtraPayloadWords
def numberExtraPayloadWords(rob)
Definition: CTPfragment.py:93
python.CTPfragment.setCtpFormatVersion
def setCtpFormatVersion(rob, version)
Definition: CTPfragment.py:69
python.CTPfragment.getExtraPayloadObject
def getExtraPayloadObject(rob)
Definition: CTPfragment.py:113
python.CTPfragment._setBits32
def _setBits32(bitset, value, shift, mask)
Definition: CTPfragment.py:38
python.CTPfragment.getTriggerWords
def getTriggerWords(rob, name='TAV')
Definition: CTPfragment.py:160
plotBeamSpotVxVal.range
range
Definition: plotBeamSpotVxVal.py:195
python.Helpers.ROOT6Setup
def ROOT6Setup(batch=False)
Definition: Tools/PyUtils/python/Helpers.py:19
python.CTPfragment.main
def main()
Definition: CTPfragment.py:183
python.CTPfragment.setHltCounter
def setHltCounter(rob, hltCounter)
Definition: CTPfragment.py:80
python.CTPfragment.decodeTriggerBits
def decodeTriggerBits(info)
Definition: CTPfragment.py:44
min
#define min(a, b)
Definition: cfImp.cxx:40
python.CTPfragment.numberHltExtraPayloadWords
def numberHltExtraPayloadWords(rob)
Definition: CTPfragment.py:102
python.CTPfragment.ctpFormatVersion
def ctpFormatVersion(rob)
Definition: CTPfragment.py:64
python.CTPfragment.setLumiBlock
def setLumiBlock(rob, lb)
Definition: CTPfragment.py:89
python.CTPfragment.lvl1AcceptBunch
def lvl1AcceptBunch(rob)
Definition: CTPfragment.py:150
python.CTPfragment.hltCounter
def hltCounter(rob)
Definition: CTPfragment.py:75
python.CaloScaleNoiseConfig.type
type
Definition: CaloScaleNoiseConfig.py:78
python.CTPfragment.hltExtraPayloadWords
def hltExtraPayloadWords(rob)
Definition: CTPfragment.py:106
dbg::print
void print(std::FILE *stream, std::format_string< Args... > fmt, Args &&... args)
Definition: SGImplSvc.cxx:70
python.CTPfragment.encodeTriggerBits
def encodeTriggerBits(bits, len=1)
Definition: CTPfragment.py:57
python.CTPfragment.lumiBlock
def lumiBlock(rob)
Definition: CTPfragment.py:86