ATLAS Offline Software
LumiResultsGetter.py
Go to the documentation of this file.
1 # Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
2 
3 # module LumiResultsGetter
4 # Tool that gets all data for the RunDependentMC configuration.
5 
6 import sys
7 from PyCool import cool
8 
9 from CoolConvUtilities.AtlCoolLib import indirectOpen,RangeList
10 from DetectorStatus.DetStatusCoolLib import statusCutsToRange
11 
12 from LumiBlockComps.LumiCalculator import IOVCache,lumiResult,coolLumiCalc
13 
14 class coolLumiResultsGetter(coolLumiCalc):
15  """Queries the DB to determine the RunDependentMC configuration for each luminosity block."""
16  def __init__(self, cooldbconn, **kw):
17  """Initialize the tool.
18  cooldbconn = main database connection (to /TRIGGER/...) so should be COOLONL.
19  kw = argument list. Clients should stay up-to-date with CoolLumiCalc when they supply optional arguments. For more information, try
20  help(LumiBlockComps.LumiCalculator.coolLumiCalc)
21  child arguments: coolfolderlumi, useprescale
22  """
23  self.lumidbname=kw.pop('lumidb','COOLOFL_TRIGGER/COMP200')
24  self.lumifoldername=kw.pop('coolfolderlumi','/TRIGGER/OFLLUMI/LBLESTOFL')
25  self.lumitag = kw.pop('coolfoldertag','OflLumi-7TeV-002')
26  self.lumimethod = kw.pop('lumimethod','ATLAS_PREFERRED')
27  self.useprescale=kw.pop('useprescale',False)
28 
29  kwkeep = kw.copy()
30  kw.update({'readoracle':False,'loglevel':1,'detStatus':"",'detStatusTag':""})#supply defaults
31  kw.update(kwkeep) #restore user choices
32  print ("Trying to open", cooldbconn)
33  coolLumiCalc.__init__(self, cooldbconn, **kw)
34  #also need the online database
35  try:
36  print ("Now trying to open", self.lumidbname)
37  self.cooldblumi=indirectOpen(self.lumidbname,debug=kw.get('loglevel',1)>1)
38  except Exception as e:
39  print (e)
40  sys.exit(-1)
41  pass
42 
43  def getLumiMuCache(self,since,until):
44  "Return a lumicache (pairs of inst lumi, eventsbx) for given range"
45  lumicache=IOVCache()
46  folderLUMI=self.cooldblumi.getFolder(self.lumifoldername)
47  if (not folderLUMI.existsChannel(self.lumimethod)):
48  if self.lumimethod != 'EXTERNAL': raise RuntimeError('This luminosity method is not supported by %s' % self.lumifoldername)
49  chid=cool.ChannelSelection(998)
50  else:
51  chid = cool.ChannelSelection(folderLUMI.channelId(self.lumimethod))
52  itr=folderLUMI.browseObjects(since,until-1,chid,self.lumitag)
53  while (itr.goToNext()):
54  obj=itr.currentRef()
55  # OnlineLumiDel is the integrated luminosity in the block
56  # in units of ub^-1/s (1e30 cm-2 s-1)
57  payload=obj.payload()
58  instlumi=payload['LBAvInstLumi']
59  if (instlumi>0):
60  evtsbx=payload['LBAvEvtsPerBX']
61  else:
62  evtsbx=0
63  pass
64  lumicache.add(obj.since(),obj.until(),(instlumi,evtsbx))
65  pass
66  itr.close()
67  return lumicache
68  def calcFromList(self,triggername,lblist):
69  """ Calculate the integrated luminosity for a list of LBs, returning
70  a list of (run,lb,lumiResult,evts) object tuples
71  (note, this is the only difference in functionality between coolLumiCalc and coolLumiResultsGetter)
72  """
73  lumiResults = []
74  # setup the triggerlevel
75  triggerlevel=self.triggerLevel(triggername)
76  if triggerlevel != 1:
77  raise Exception("Please use a L1 trigger for this tool.")
78  totalL=0
79  totaltime=0.
80  totalacc=3*[0]
81  totalgoodblock=0
82  totalbadblock=0
83  # get counters, prescales LB timest folders
84  folderLBCOUNTL1=self.cooldb.getFolder('/TRIGGER/LUMI/LVL1COUNTERS')
85  folderL1PRESCALE=self.cooldb.getFolder('/TRIGGER/LVL1/Prescales')
86  folderL1LB=self.cooldb.getFolder('/TRIGGER/LUMI/LBLB')
87  # loop over LBList
88  for lbinfo in lblist:
89  # get the trigger configuration for this run
90  runstat,chainnums,hltprescale=self._getChains(lbinfo.run,triggername,triggerlevel)
91  if (self.loglevel>1):
92  print ("L1 chain number", chainnums[0])
93  if (runstat):
94  since,until=lbinfo.IOVRange()
95  # check for detector status requirements
96  if (self.detstatus!=""):
97  if (self.loglevel>0):
98  print (lbinfo, ": Applying detector status cuts: %s" % self.detstatus)
99  gooddetstatus=statusCutsToRange(self.detstatusdb,'/GLOBAL/DETSTATUS/LBSUMM',since,until,self.detstatustag,self.detstatus)
100  else:
101  gooddetstatus=RangeList(since,until)
102 
103  if (self.loglevel>1):
104  print ("LumiB L1-Acc L1-pre LiveTime MeanInts IntL/ub-1")
105  # get and cache the LVL1 prescales for this run; note these can have >1 LB intervals
106  l1precache=IOVCache()
107  itr=folderL1PRESCALE.browseObjects(since,until-1,cool.ChannelSelection(chainnums[0]))
108  while (itr.goToNext()):
109  obj=itr.currentRef()
110  l1precache.add(obj.since(),obj.until(),obj.payload()['Lvl1Prescale'])
111  itr.close()
112  # get and cache the lumiosity estimates for this run; note these can have >1 LB intervals
113  lumicache=self.getLumiMuCache(since,until)
114  # loop through the LBs for this range
115  # looping is driven by the LVL1COUNTERS folder which has 1 LB IOVs.
116  # Should be matched by LBLB which is also 1 LB IOVs.
117  l1countitr=folderLBCOUNTL1.browseObjects(since,until-1,cool.ChannelSelection(chainnums[0]))
118  l1lbiter=folderL1LB.browseObjects(since,until-1,cool.ChannelSelection(0)) #just one channel in this folder.
119  while l1countitr.goToNext():
120  # access LVL1 information
121  l1countobj=l1countitr.currentRef()
122  lb=l1countobj.since() & 0xFFFFFFFF
123  l1lbiter.goToNext()
124  lblbobj=l1lbiter.currentRef()
125  if (lblbobj.since()!=l1countobj.since()):
126  raise Exception("L1 counter/lumiblock synchronisation error. Cannot get length of Lumiblocks!")
127  l1payload=l1countobj.payload()
128  lblbpayload =lblbobj.payload()
129  l1acc=l1payload['L1Accept']
130  l1dt=(lblbpayload['EndTime']-lblbpayload['StartTime'])*1.0e-09
131  l1tstart=lblbpayload['StartTime']
132  # calculate livefraction from LVL1 (events accepted after mask and busy veto)/(events accepted by prescale)
133  # this will be a poor estimate when prescales are large.
134  if (l1payload['AfterPrescale']>0):
135  livefrac=float(l1payload['L1Accept'])/float(l1payload['AfterPrescale'])
136  else:
137  livefrac=1.
138  pass
139  if (len(gooddetstatus.getAllowedRanges(l1countobj.since(),l1countobj.until()))>0):
140  # calculate intL for block
141  # lumi is being given in units of 10^33 cm^-2s^-1
142  # equivalent to 1 nb^-1s^-1
143  # instantaneous and time increment lumi
144  try:
145  (lumi,evtsbx)=lumicache.find(l1countobj.since())
146  except TypeError:
147  if (self.lumimethod != 'EXTERNAL'):
148  print ("WARNING: No payload in", self.lumifoldername, "for run", lbinfo.run, "[", lb, "]!")
149  lumi=0
150  evtsbx=0
151  pass
152  l1prescale=l1precache.find(l1countobj.since())
153  if (lumi is not None and l1prescale is not None):
154  # multiply by livetime in seconds to get
155  # intL in nb^-1
156  # intlumi = nlumi * L1acc / (L1accAP * P )
157  livetime=livefrac*l1dt
158  if self.useprescale:
159  intlumi=(lumi*livetime)/(1.0 * l1prescale)
160  if not (intlumi >= 0):
161  print ("WARNING:",lbinfo.run,"[",lb,"]: bad lumi, prescale or livetime found:(IL,LV):", lumi,livetime)
162  else:
163  intlumi=(lumi*livetime)
164  if not (intlumi >= 0):
165  print ("WARNING:",lbinfo.run,"[",lb,"]: bad lumi or livetime found:(IL,LV)", lumi,livetime)
166 
167  if (self.loglevel>1):
168  print ("%5i %7i %8i %8.2f %8.7f %10.1f" % (lb,l1acc,l1prescale,livetime,evtsbx,intlumi))
169  elif (lumi is not None):
170  intlumi=(lumi*livetime)
171  if (self.loglevel>1):
172  print ("%5i %7i %8i %8s %8.7f %10.if <missing prescale>" %(lb,l1acc,"??",livetime,evtsbx,intlumi))
173  if not (intlumi >= 0):
174  print ("WARNING:",lbinfo.run,"[",lb,"]: bad lumi or livetime found:(IL,LV)", lumi,livetime)
175  else:
176  intlumi=0
177  if (self.loglevel>1):
178  print ("%5i %7i %8i %8s %8s %10s <missing prescale>" %(lb,l1acc,"??",livetime,"??","??"))
179  lumiResults.append( (lbinfo.run, int(lb), lumiResult(intlumi,l1acc,0,0,livetime,1,0), evtsbx, l1tstart ) )
180  # accumulate statistics
181  totalacc[0]+=l1acc
182  totaltime+=livetime
183  totalL+=intlumi
184  totalgoodblock+=1
185  else: #this was a bad run detstatus
186  totalbadblock+=1
187  pass
188  pass
189  l1countitr.close()
190  else:
191  print ("WARNING: Trigger not defined for run",lbinfo.run)
192  pass
193  if (self.loglevel>0):
194  print ("Running total after %24s:" % lbinfo, " %7i events; %8.2f seconds; %10.1f (nb^-1)" % (totalacc[0],totaltime,totalL))
195  pass #end of loop over iovs
196  return lumiResults
197 
python.LumiResultsGetter.coolLumiResultsGetter.__init__
def __init__(self, cooldbconn, **kw)
Definition: LumiResultsGetter.py:16
CaloCellPos2Ntuple.int
int
Definition: CaloCellPos2Ntuple.py:24
python.LumiResultsGetter.coolLumiResultsGetter
Definition: LumiResultsGetter.py:14
python.LumiResultsGetter.coolLumiResultsGetter.lumimethod
lumimethod
Definition: LumiResultsGetter.py:26
python.LumiResultsGetter.coolLumiResultsGetter.lumitag
lumitag
Definition: LumiResultsGetter.py:25
python.LumiResultsGetter.coolLumiResultsGetter.lumidbname
lumidbname
Definition: LumiResultsGetter.py:23
python.LumiResultsGetter.coolLumiResultsGetter.calcFromList
def calcFromList(self, triggername, lblist)
Definition: LumiResultsGetter.py:68
python.LumiResultsGetter.coolLumiResultsGetter.lumifoldername
lumifoldername
Definition: LumiResultsGetter.py:24
python.DetStatusCoolLib.statusCutsToRange
def statusCutsToRange(dbconn, foldername, since, until, tag, statusreq)
Definition: DetStatusCoolLib.py:11
python.LumiResultsGetter.coolLumiResultsGetter.cooldblumi
cooldblumi
Definition: LumiResultsGetter.py:37
python.LumiResultsGetter.coolLumiResultsGetter.getLumiMuCache
def getLumiMuCache(self, since, until)
Definition: LumiResultsGetter.py:43
python.LumiResultsGetter.coolLumiResultsGetter.useprescale
useprescale
Definition: LumiResultsGetter.py:27
python.AtlCoolLib.indirectOpen
def indirectOpen(coolstr, readOnly=True, debug=False)
Definition: AtlCoolLib.py:130
readCCLHist.float
float
Definition: readCCLHist.py:83