ATLAS Offline Software
AtlRunQueryRun.py
Go to the documentation of this file.
1 #!/bin/env python
2 
3 # Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
4 #
5 # ----------------------------------------------------------------
6 # Script : AtlRunQueryRun.py
7 # Project: AtlRunQuery
8 # Purpose: Library with the Run class
9 # Authors: Andreas Hoecker (CERN), Joerg Stelzer (DESY)
10 # Created: Feb 10, 2009
11 # ----------------------------------------------------------------
12 #
13 from functools import total_ordering
14 from CoolRunQuery.utils.AtlRunQueryTimer import timer
15 
16 from CoolRunQuery.utils.AtlRunQueryUtils import addKommaToNumber, filesize, prettyNumber, RunPeriods
17 from CoolRunQuery.utils.AtlRunQueryLookup import DecodeDetectorMask
18 from CoolRunQuery.utils.AtlRunQueryIOV import IOVRange,IOVTime
19 from CoolRunQuery.utils.AtlRunQueryLookup import LArConfig, isDQ, OLCAlgorithms
20 from CoolRunQuery.output.AtlRunQueryRoot import makeLBPlot, makeLBPlotList, makeTimePlotList, makeBSPlots, SaveGraphsToFile
21 from CoolRunQuery.AtlRunQueryQueryConfig import QC
22 from CoolRunQuery.selector.AtlRunQuerySelectorBase import DataKey, Selector
23 
24 import math
25 import time, calendar
26 import sys
27 import re
28 import datetime
29 import subprocess
30 import urllib.request
31 
32 _fW = {'Run' : 12, 'NLB': 5, 'Time': 50, '#Events': 10, 'Stream': 10}
33 
34 class DataEntry:
35  def __init__(self, iov, value, reject=False, valueForStorage=None):
36  self.iov = iov
37  self.lbrange = (self.iov.startTime.lb, self.iov.endTime.lb) # note that the end lb is not part of the iov
38  self.value = value
39  self.rejected = reject
40  self.valueForStorage = valueForStorage
41 
42  def __str__(self):
43  return "[%i-%i) %s %r" % (self.lbrange[0], self.lbrange[1], "r" if self.rejected else "a", self.value)
44 
45  def __repr__(self):
46  return "<DataEntry %s>" % self
47 
48  def __len__(self):
49  length_L = self.lastlb-self.startlb+1
50  if length_L>0x7FFFFFFF:
51  length_L = 0x7FFFFFFF
52  return int(length_L)
53 
54  @property
55  def startlb(self):
56  return self.lbrange[0]
57 
58  @property
59  def endlb(self):
60  return self.lbrange[1]
61 
62  @property
63  def lastlb(self):
64  return ((0x100000000 + self.endlb)-1) & 0xFFFFFFFF
65 
66  def __getitem__(self,k):
67  return self.valueForStorage[k]
68 
69  def contains(self, lb):
70  return self.lbrange[0]<=lb and lb<self.lbrange[1]
71 
72  def intersects(self,lbrange):
73  lbstart, lbend = lbrange
74  return self.contains(lbstart) or self.contains(lbend-1) or (lbstart<=self.lbrange[0] and self.lbrange[1]<lbend)
75 
76  def pickled(self):
77  v = self.value.pickled() if hasattr(self.value,'pickled') else self.value
78  return { 'firstlb' : self.startlb, 'lastlb' : self.lastlb, 'value' : v, 'accepted' : not self.rejected }
79 
80  def json(self):
81  retDict = { 'lbrange' : [self.startlb, self.lastlb] }
82  if self.valueForStorage is None:
83  v = self.value.pickled() if hasattr(self.value,'pickled') else self.value
84  retDict["value"] = v
85  else:
86  retDict.update(self.valueForStorage)
87  return retDict
88 
89 
91  def __init__(self, key, run):
92  super(DataEntryList,self).__init__()
93  self.key = key
94  self.run = run
95 
96  def atLB(self,lb):
97  for e in self:
98  return [x for x in self if x.contains(lb)]
99  return None
100 
101  def stops(self):
102  return set([e.startlb for e in self]).union(set([e.lastlb+1 for e in self]))
103 
104  @property
105  def lastlb(self):
106  return max([e.lastlb for e in self])
107 
108  @property
109  def endlb(self):
110  return max([e.endlb for e in self])
111 
112  def pickled(self):
113  return [e.pickled() for e in self]
114 
115  def json(self):
116  return [e.json() for e in self]
117 
118 
119 class RunData:
120 
121  # this is a temporary thing to get the DQDefects working, I still want to change the way the selectors work
122  DQKeys = []
123  DQLogic = []
124  DefectSelector = None
125 
126  def __init__(self,run):
127  self.__run_o = run
128  self.run = run.runNr
129  self.data = {}
130  self.data_current_lb = {}
131  self.current_lb = 0
132  self.stops = []
133 
134  def __contains__(self,k):
135  if type(k)==DataKey:
136  return k in self.data or k.ResultKey in self.data
137  return k in self.data
138 
139  def __getitem__(self,k):
140  if k not in self:
141  self.data[k] = DataEntryList(key=k, run=self.run)
142  return self.data[k]
143  else:
144  if type(k)==DataKey:
145  return self.data[k] if k in self.data else self.data[k.ResultKey]
146  return self.data[k]
147 
148  def __setitem__(self,k,value):
149  self.data[k]=value
150 
151  def __iter__(self):
152  self.stops = self._calcStops()
153  for lb in self.stops: # the last stop is the LB after the last
154  if lb>self.__run_o.lastlb:
155  break
156  self._setLB(lb)
157  yield self
158 
159  def keys(self):
160  return self.data.keys()
161 
162  @property
163  def runNrS(self):
164  return str(self.run)
165 
166  @property
167  def lb(self):
168  return self.current_lb
169 
170  def lbend(self,lb=None):
171  if lb is None:
172  lb=self.current_lb
173  return self.stops[self.stops.index(lb)+1]-1
174 
175  @property
176  def NrLBs(self):
177  return "%i" % max([el.lastlb for el in self.data.values()])
178 
179  @property
180  def result(self):
181  return self.data_current_lb
182 
183  @property
185  #print ("Checking Reject for LB",self.lb,"-",self.lbend())
186  need_dq_check = False
187  for k,s in self.data_current_lb.items():
188  if k in RunData.DQKeys:
189  need_dq_check = True
190  continue # exclude DQ from this, since it gets its own treatment
191  if s is None:
192  continue
193  for e in s:
194  if e.rejected:
195  return True
196  if need_dq_check:
197  if self.isDQRejected():
198  return True
199  if self.isDQDefectRejected():
200  return True
201  return False
202 
203  def isDQRejected(self):
204  for orGroup in RunData.DQLogic:
205  groupAccept = False
206  for k in orGroup:
207  if len(self.data_current_lb[k])==0:
208  passes = False
209  else:
210  passes = not self.data_current_lb[k][0].rejected
211  if passes:
212  groupAccept = True
213  break
214  if not groupAccept:
215  return True
216  return False
217 
219  if 'DQ' not in self.data_current_lb:
220  return False
221  return not RunData.DefectSelector(self.data_current_lb['DQ'])
222 
223 
224  @property
225  def isRejected(self):
226  for s in self:
227  if not s.isRejectedCurrentLB:
228  return False
229  return True
230 
231 
232  def isReady(self,lb=None):
233  if 'Ready for physics' not in self:
234  raise RuntimeError("No ready data available")
235  readydata = [x for x in self.data['Ready for physics'] if x.value=='1']
236  if lb is None:
237  return readydata
238  if type(lb)==int:
239  for x in readydata:
240  if x.contains(lb):
241  return True
242  return False
243  if type(lb)==tuple and len(lb)==2:
244  for x in readydata:
245  if x.intersects(lb):
246  return True
247  return False
248  raise RuntimeError("Can't interpret lb to check isReady(lb=%r)" % lb)
249 
250 
251  def getLBRanges(self,activeOnly=False):
252  last_lb = self.__run_o.nr_lb
253  a = [(int(data.lb),not data.isRejectedCurrentLB) for data in self if data.lb<=last_lb]
254  #a = [(int(data.lb),not data.isRejectedCurrentLB) for data in self]
255  if not a:
256  return []
257  start,state = a[0]
258  ranges = []
259  for x in a[:-1]:
260  if x[1] == state:
261  continue
262  ranges += [(state, start, x[0])]
263  start,state = x
264  last_start,last_state = a[-1]
265  if last_state==state:
266  ranges += [(state, start, last_lb+1)]
267  else:
268  ranges += [(state, start, last_start)]
269  ranges += [(last_state, last_start, last_lb+1)]
270  if activeOnly:
271  return [x for x in ranges if x[0]]
272  else:
273  return ranges
274 
275  def _setLB(self,lb):
276  self.current_lb = lb
277  self.data_current_lb = dict([(k,entrylist.atLB(lb)) for k,entrylist in self.data.items()])
278 
279  def _calcStops(self):
280  stops = set()
281  for entrylist in self.data.values():
282  stops.update(entrylist.stops())
283  return sorted(list(stops))
284 
285  def addResult(self, iov, k, value, reject, valueForStorage = None):
286  if not iov:
287  iov = IOVRange(runStart=self.run, lbStart=1, runEnd=self.run+1, lbEnd=0)
288  self[k].append(DataEntry(iov=iov, value=value, reject=reject, valueForStorage=valueForStorage))
289 
290  def astxt(self):
291  s = ""
292  if Run.showrunnr:
293  s += "%*s %*s " % (4, self.lb, 4, self.lbend())
294  s += ("r" if self.isRejectedCurrentLB else "a")
295  if Run.showtime:
296  s += "%*s " % (_fW['Time'],'')
297  if Run.showduration:
298  s += " "
299  for k in Run.SortedShowOrder():
300  k = k.ResultKey
301  w = 10
302  if k in _fW:
303  w = _fW[k]
304  v=""
305  if self.data_current_lb[k]:
306  v = [x.value for x in self.data_current_lb[k]][0]
307  if v is None:
308  v=""
309  if k == "#Events" or k[0:4] == "STR:" or k=="TriggerMenu" or k=="TriggerRates" or k=="olc:bcidmask":
310  v = ""
311  s += "%*s " % (w,v)
312  return s
313 
314 
315 @total_ordering
316 class Run:
317  ShowOrder = []
318  _SortedShowOrder = None
319  DisplayOrder = map(re.compile,['#Events','Ready','lhc:|olc:', 'TriggerMenu|SMK|Release|L1 PSK|HLT PSK|BGS|TriggerRates', 'bs:', 'STR:', 'DQ|SHIFTOFL:|LBSUMM:', 'lar:', 'Detector','.*'])
320  PromptCalibRuns = []
321  NemoTasks = {}
322  showrunnr = False
323  showtime = False
324  showduration = False
325  writehtml = False
326  bgcolor = "1"
327  totevents = [0, 0]
328  runnropen = -1
329  showCAFLinks = False
330  Datapath = ''
331  Fieldinfo = {}
332  GlobalTooltips = []
333  BeamspotSource = ''
334  runPeriods = RunPeriods()
335  TmpBoxContent = ''
336 
337  @classmethod
338  def AddToShowOrder(cls,key):
339  #print ("ADDING TO SHOWORDER %r" % key)
340  if key not in cls.ShowOrder:
341  cls.ShowOrder += [ key ]
342 
343  @classmethod
344  def addGlobalToolTip(cls, var, content):
345  cls.GlobalTooltips += ['dw_Tooltip.content_vars["%s"] = {content: \'%s\'};' % (var, content.replace("'","&#39;"))]
346 
347  def __init__(self, runNr=0):
348  self.runNr = runNr
349  self.lhcRun = 0
350  self.sor = 0
351  self.eor = 0
352  self.lastlb = 0
353  self.selDataIncomplete = False
354  self.showDataIncomplete = False
355  self.xvecStb = []
356  self.hasStableBeamsInfo = False
357  # the results of the query index by query key
358  self.result = {}
359  # the run statistics index by query key (filled in selector.runAfterQuery)
360  self.stats = {}
361  # the start times of all lumiblocks [start_LB1, start_LB2, start_LB3, ..., start_LBN]
362  self.lbtimes = []
363  self.tooltips = []
364  self.data = RunData(run=self)
365  # luminosity unil
366  self.lumiunit = 1.0 # default unit
367  self.lumiunittxt = 'nb'
368  self.instlumiunittxt = '30'
369  self.givepeakmuinfo = True
370  if self.runNr > 378000:
371  # last Run-2 run with SMK 2787 and release AthenaP1,21.1.56 is 376153
372  # first Run-3 with SMK 59 and release 22.0.13 is 379453
373  self.lhcRun = 3
374  elif self.runNr > 249000:
375  # last Run-1 run with SMK 1670 and release AtlasP1HLT,19.3.0.4 is 248373
376  # first Run-2 run with SMK 2002 and release AtlasP1HLT,20.1.0.1 is 249785
377  self.lhcRun = 2
378  else:
379  self.lhcRun = 1
380 
381  if self.runNr > 168206 and self.runNr <= 170482:
382  self.lumiunit = 1.0e6 # unit is mbarn for heavy ions
383  self.lumiunittxt = 'mb'
384  self.instlumiunittxt = '24'
385  self.givepeakmuinfo = False
386 
387 
388  @property
389  def runNrS(self):
390  return "%i" % self.runNr
391 
392  @property
393  def data_current_lb(self):
394  return self.data.data_current_lb
395 
396  @property
397  def NrLBs(self):
398  return "%i" % self.lastlb
399 
400  @property
401  def nr_lb(self):
402  return self.lastlb
403 
404  def addToolTip(self, var, content):
405  self.tooltips += ['dw_Tooltip.content_vars["%s\"] = {content: \'%s\'};' % (var, content.replace("'","&#39;"))]
406 
408  if len(self.xvecStb)==0 and 'lhc:stablebeams' in Run.ShowOrder and 'lhc:stablebeams' in self.data:
409  entries = self.data['lhc:stablebeams']
410  for entry in entries:
411  if entry.startlb == 0:
412  continue
413  if 'true' in entry.value.lower():
414  self.xvecStb += range(entry.startlb,entry.endlb)
415  self.hasStableBeamsInfo = len(self.xvecStb)>0
416  return self.hasStableBeamsInfo, self.xvecStb
417 
418  @classmethod
419  def SortedShowOrder(cls):
420  if Run._SortedShowOrder is not None:
421  if len(Run._SortedShowOrder) != len(Run.ShowOrder):
422  raise RuntimeError ("Sorting not up-to-date %i %i" % (len(Run._SortedShowOrder), len(Run.ShowOrder) ))
423  return Run._SortedShowOrder
424  hk = []
425  for order in Run.DisplayOrder:
426  for x in Run.ShowOrder:
427  if not order.match(x.ResultKey):
428  continue
429  if x in hk:
430  continue
431  hk += [x]
432  Run._SortedShowOrder = hk
433  if len(Run._SortedShowOrder) != len(Run.ShowOrder):
434  raise RuntimeError ("Sorting not up-to-date after creation %i %i" % (len(Run._SortedShowOrder), len(Run.ShowOrder) ))
435  return Run._SortedShowOrder
436 
437  @classmethod
438  def headerkeys(cls):
439  hk = []
440  if Run.showrunnr:
441  hk += ['Run','Links','#LB']
442  if Run.showtime:
443  hk += ['Start and endtime (%s)' % QC.localStr()]
444  if Run.showduration:
445  hk += ['Duration']
446  for x in cls.SortedShowOrder():
447  x = x.ResultKey
448  if 'L1 PSK' in x or ('olc:' in x and ('beam1bunches' in x or 'beam2bunches' in x or 'collbunches' in x or 'beam1intensity' in x or 'beam2intensity' in x)):
449  continue
450  hk += [x]
451  return hk
452 
453 
454  @classmethod
455  def header(cls):
456  if Run.writehtml:
457  # flags...
458  ofllumiFlag = False
459  s = '<tr>\n'
460  if Run.showrunnr:
461  s += ' <th>Run</th><th>Links</th><th>#LB</th>\n'
462  if Run.showtime:
463  s += ' <th>Start and endtime (%s)</th>\n' % QC.localStr()
464  if Run.showduration:
465  s += ' <th>Duration</th>\n'
466  for ik, data_key in enumerate(Run.SortedShowOrder()):
467  k = data_key.ResultKey
468  if k[0:4] == 'STR:':
469  s += ' <th><font size="-2">%s_<BR>%s</font></th>' % tuple(k[4:].split('_',1))
470  elif k[0:8] == "Detector":
471  s += ' <th>%s</th>' % k
472  elif "SolCurrent" in k:
473  s += ' <th>Solenoid<br>current&nbsp;(A)</th>'
474  elif "TorCurrent" in k:
475  s += ' <th>Toroid<br>current&nbsp;(A)</th>'
476  elif 'DQ' == k:
477  s += ' '
478  matching_names = dict(Run.Fieldinfo['DQ']['DefMatch'])
479  first = True
480  for channelname in Run.Fieldinfo['DQ']['DefChannels']:
481  tip = "defect_match_%s" % channelname
482  info = "%s # %s" % (channelname if channelname!="" else "*",data_key._second_internal_key if data_key._second_internal_key!="" else "HEAD")
483  s += '<th style="align:center; white-space:nowrap; padding-right: 10px; padding-left: 10px; ">'
484  s += 'Data Quality<br><span class="showTip %s tooltip" style="font-weight:normal; font-size:80%%">(%s)</span>' % (tip, info)
485  if first:
486  s += '<div style="font-size: xx-small; cursor: pointer;" onclick="toggle_dq(this)">[show tolerable]</div>'
487  first = False
488  s += '</th>'
489 
490  allDefects = sorted(matching_names[channelname])
491  n = 4*[len(allDefects)//4]
492  for x in range(len(allDefects) % 4):
493  n[x]+=1
494 
495  # put the list of all defects into 4 columns
496  cx = 0
497  columns = []
498  for x in n:
499  columns.append( allDefects[slice(cx,cx+x)] )
500  cx+=x
501 
502  for x in columns[1:]: # padding at the end of each column except the first to make zip include the last line
503  x += ['']
504 
505  columnsTransposed = zip(*columns) # transpose
506 
507  tts = ''
508  for z in columnsTransposed:
509  tts += '<tr>%s</tr>' % ''.join(["<td>%s</td>"% x for x in z])
510  content = '<table style="width:500px; font-size:80%%;">%s</table>' % tts
511  Run.addGlobalToolTip(tip,content)
512 
513  elif isDQ(k):
514  foldertag,flag = k.split(':')
515 
516  if flag in Run.Fieldinfo:
517  tipname = 'dqvfdesc_%s' % flag
518  commentbox = '%s' % (Run.Fieldinfo[flag])
519  Run.addGlobalToolTip(tipname, commentbox)
520  s += '<th class="showTip %s tooltip" style="cursor:pointer">' % tipname
521  else:
522  s += ' <th>'
523 
524  s += '<font size="-1">%s</font><BR><font style="font-weight:normal;font-size:70%%">' % flag
525  if '#' in foldertag:
526  s += '(%s #<br>%s)' % tuple(foldertag.split('#',1))
527  else:
528  s += '(%s)' % (foldertag)
529  s += '</font></th>'
530 
531  elif k == "L1 PSK":
532  continue
533  elif k == "HLT PSK":
534  s += ' <th>Prescale keys</th>'
535  elif k == "Release":
536  s += ' <th>HLT Release</th>'
537  elif k == "Datasets":
538  s += ' <th>Tier-0 Datasets</th>'
539  elif k == '#Events (incl. calib.)':
540  s += ' <th>#Events<br><font size="-2">(incl.&nbsp;calib.)</font></th>'
541  elif k == '#Events (streamed)' :
542  s += ' <th>#Events<br><font size="-2">(streamed)</font></th>'
543  elif 'lar:' in k:
544  if 'runtype' in k:
545  s += ' <th><font size="-2">Run type</font></th>'
546  elif 'nsamples' in k:
547  s += ' <th><font size="-2">#Samples</font></th>'
548  elif 'firstsample' in k:
549  s += ' <th><font size="-2">1st sample</font></th>'
550  elif 'format' in k:
551  s += ' <th><font size="-2">Format</font></th>'
552  else:
553  print ('ERROR: unknown LAr option "%s"' % k)
554  sys.exit(1)
555  elif 'lhc:' in k:
556  if 'fillnumber' in k:
557  s += ' <th> LHC Fill</th>'
558  elif 'stablebeams' in k:
559  s += ' <th>Stable beams</th>'
560  if 'lhc:beammode' in Run.ShowOrder:
561  s += ' <th>Beam mode</th>'
562  if 'lhc:beamenergy' in Run.ShowOrder:
563  s += ' <th>Beam&nbsp;energy and&nbsp;intensities</th>'
564 
565  elif 'beamenergy' in k:
566  continue # included in 'fillbeams' summary
567  elif 'nbunch1' in k:
568  s += ' <th>#Bunches B1 <br><font size="-2"><b>(NOT YET RELIABLE)</b></font></th>'
569  elif 'nbunch2' in k:
570  s += ' <th>#Bunches B2 <br><font size="-2"><b>(NOT YET RELIABLE)</b></font></th>'
571  elif 'nbunchcoll' in k:
572  s += ' <th>#Bunches<br>colliding <br><font size="-2"><b>(NOT YET RELIABLE)</b></font></th>'
573  elif 'beamtype1' in k:
574  s += ' <th>Beam type&nbsp;B1</th>'
575  elif 'beamtype2' in k:
576  s += ' <th>Beam type&nbsp;B2</th>'
577  elif 'machinemode' in k:
578  s += ' <th>LHC mode</th>'
579  elif 'beammode' in k:
580  continue
581  else:
582  print ('ERROR: unknown LHC option "%s"' % k)
583  sys.exit(1)
584  elif 'ofllumi:' in k:
585  if not ofllumiFlag:
586  s += ' <th>Offline Luminosity<br><font style="font-weight:normal">(%s)</font></font></th>' % k.split(':')[-1]
587  ofllumiFlag = True
588  elif 'bs:' in k:
589  kt = k.replace('bs:','')
590  if 'bs:Pos' in k or 'bs:Sig' in k:
591  s += ' <th><font size="-2">%s<br><font style="font-weight:normal">(mm)</font></font></th>' % kt
592  elif 'bs:Tilt' in k:
593  s += ' <th><font size="-2">%s<br><font style="font-weight:normal">(rad)</font></font></th>' % kt
594  else:
595  s += ' <th><font size="-2">%s</font></th>' % kt
596  elif 'BPM' in k:
597  s += ' <th>Beam&nbsp;Position Monitors&nbsp;(BPM)</th>'
598  elif 'olc:' in k:
599  if 'olc:lumi' in k:
600  tp1, tp2, chan = k.split(':')
601  try:
602  chan = float(chan)
603  except ValueError:
604  chan = -1
605  if chan in OLCAlgorithms:
606  chanstr = OLCAlgorithms[chan]
607  else:
608  chanstr = 'UNKNOWN'
609  s += ' <th>Online&nbsp;del.&nbsp;Luminosity&nbsp;<font size="-2"><br><font style="font-weight:normal">[%s]</font></font></th>' % chanstr
610  elif 'beam1bunches' in k:
611  continue # not used anymore
612  elif 'beam2bunches' in k:
613  continue # not used anymore
614  elif 'collbunches' in k:
615  continue # not used anymore
616  elif 'bcidmask' in k:
617  s += ' <th>Bunch&nbsp;structure</th>'
618  elif 'beam1intensity' in k:
619  continue # included in 'fillbeams' summary
620  elif 'beam2intensity' in k:
621  continue # included in 'fillbeams' summary
622  else:
623  s += ' <th>%s</th>' % k
624 
625  elif 'BGS Key' in k:
626  s += ' <th>Bunch group key</th>'
627 
628  else:
629  s += ' <th>%s</th>' % k
630  s += '\n'
631  s += '</tr>'
632 
633  # generate a second header line
634  secondheader = ''
635  patterns = [ ('lar:', 'LAr configuration'),
636  ('lhc:|olc:', 'LHC and online luminosity information' if any(['olc:' in x for x in Run.headerkeys()]) else 'LHC information' ),
637  ('bs:', 'Beam spot parameters (%s)' % Run.BeamspotSource),
638  ('STR:', 'Data stream statistics'),
639  ('TriggerMenu|SMK|Release|L1 PSK|HLT PSK|BGS|TriggerRates', 'Trigger information'),
640  ('SHIFTOFL:', 'Data quality (SHIFTOFL)'),
641  ('LBSUMM:', 'Data quality (LBSUMM)')
642  ]
643 
644  order = []
645  for (p,hdesc) in patterns:
646  matchedpositions = [idx for (idx,head) in enumerate(Run.headerkeys()) if re.match(p,head)]
647  #print ("pattern",p,matchedpositions)
648  if matchedpositions:
649  order += [(min(matchedpositions),max(matchedpositions),hdesc)]
650  order.sort()
651 
652  mergeempty = True
653  if len(order)>0:
654  current=0
655  for th in order:
656  if mergeempty:
657  if th[0]>current:
658  secondheader += '<th colspan="%s"></th>' % (th[0]-current)
659  else:
660  for x in range(th[0]-current):
661  secondheader += '<th></th>'
662  secondheader += '<th colspan="%s">%s</th>' % (th[1]-th[0]+1,th[2])
663  current=th[1]+1
664  if len(Run.headerkeys())>current:
665  if mergeempty:
666  secondheader += '<th colspan="%s"></th>' % (len(Run.headerkeys())-current)
667  else:
668  for x in range(len(Run.headerkeys())-current):
669  secondheader += '<th></th>'
670  secondheader = "<tr>%s</tr>" % secondheader
671 
672 
673  s = '<thead>' + secondheader + s + '</thead>\n'
674 
675  # Global (run independent) tooltips
676 
677  # OLC
678  if any([k for k in Run.ShowOrder if "olc:lumi" in k.ResultKey]):
679  boxcontent = '<font color="#AA0000">Click&nbsp;to&nbsp;enlarge&nbsp;figure and&nbsp;to&nbsp;obtain&nbsp;online&nbsp;integrated&nbsp;luminosity&nbsp;versus&nbsp;LB</font>'
680  Run.addGlobalToolTip("OLCLumi", boxcontent)
681 
682  # OFLLumi
683  if any([k for k in Run.ShowOrder if "ofllumi" in k.ResultKey]):
684  boxcontent = '<font color="#AA0000">Click to obtain offline integrated luminosity versus LB</font>'
685  Run.addGlobalToolTip("OFLLumi", boxcontent)
686 
687  # OFLBS - beamspot
688  if any([k for k in Run.ShowOrder if "bs:" in k.ResultKey]):
689  boxcontent = '<font color="#AA0000">Click to obtain %s beamspot versus LB</font>' % (Run.BeamspotSource.split()[0])
690  Run.addGlobalToolTip("OFLBS", boxcontent)
691 
692  # BPM info
693  if any([k for k in Run.ShowOrder if "BPM" == k.ResultKey]):
694  boxcontent = '<font color="#AA0000">Click to enlarge figure</font>'
695  Run.addGlobalToolTip("BPM", boxcontent)
696 
697  # LHC Summary
698  if any([k for k in Run.ShowOrder if "lhc:fillnumber" in k.ResultKey]):
699  boxcontent = '<font color="#AA0000">Click to enlarge figure</font>'
700  Run.addGlobalToolTip("LHCSummary", boxcontent)
701 
702  else:
703  s = ''
704  for lll in [1,2]:
705  if Run.showrunnr:
706  if lll==0:
707  s += '%-*s %*s ' % (_fW['Run'],'Run',_fW['NLB'],'#LB')
708  if lll==1:
709  s += '%-*s %*s ' % (_fW['Run'],' ',_fW['NLB'],' ')
710  s+=" " # accept/reject flag
711  if Run.showtime:
712  hstr = 'Start and endtime (%s)' % QC.localStr()
713  if lll==0:
714  s += '%*s ' %(_fW['Time'],hstr)
715  if lll==1:
716  s += '%*s ' %(_fW['Time'],' ')
717  if Run.showduration:
718  if lll==0:
719  s += '%*s ' % (10,'Duration')
720  if lll==1:
721  s += '%*s ' % (10,' ')
722  for k in Run.SortedShowOrder():
723  if k.Type == DataKey.STREAM:
724  w = max(len(k.Header)-k.Header.find('_'),_fW['Stream'])
725  if lll==0:
726  s += '%*s ' % (w,k.Header[4:k.Header.find('_')])
727  if lll==1:
728  s += '%*s ' % (w,k.Header[k.Header.find('_')+1:])
729  else:
730  w = 10
731  if k in _fW:
732  w = _fW[k.ResultKey]
733  if lll==0:
734  s += '%*s ' % (w,k.Header)
735  if lll==1:
736  s += '%*s ' % (w,' ')
737  if lll==0:
738  s+='\n'
739  return s
740 
741  def addResult(self, resDictKey, value, iov=None, reject=False, valueForStorage=None):
742  if resDictKey=='DQ' and value=='n.a.':
743  return
744  if resDictKey not in self.result:
745  self.result[resDictKey] = value
746  if iov:
747  if iov.startTime.lb>self.lastlb:
748  return # sometimes there are IOVs completely outside the run e.g. run 165821 DQ SHIFTOFL
749  iov.endTime = min(iov.endTime, IOVTime(self.runNr,self.lastlb+1) )
750  self.data.addResult(iov, resDictKey, value, reject, valueForStorage=valueForStorage)
751 
752  def runlinks(self):
753  s = ''
754  # DS
755  if time.gmtime(self.sor/1.E9).tm_year >= 2010:
756  s += ' <a href="http://atlas.web.cern.ch/Atlas/GROUPS/DATAPREPARATION/DataSummary/%i/run.py?run=%i" target="_blank" title="Data summary information for run %i"><font size="-3">DS</font></a>,&nbsp;\n' % (time.gmtime(self.sor/1.E9).tm_year, self.runNr, self.runNr)
757  # RS
758  s += ' <a href="http://atlas-service-db-runlist.web.cern.ch/atlas-service-db-runlist/php/runDetails.php?run=%i" target="_blank" title="Run summary information for run %i"><font size="-3">RS</font></a>,&nbsp;\n' % (self.runNr, self.runNr)
759  # BS
760  s += ' <a href="https://atlas-beamspot.cern.ch/webapp/jobs/?r=%i" target="_blank" title="Beam spot fit information for run %i"><font size="-3">BS</font></a>,&nbsp;\n' % (self.runNr, self.runNr)
761  # AMI
762  s += ' <a href="https://ami.in2p3.fr/AMI/servlet/net.hep.atlas.Database.Bookkeeping.AMI.Servlet.Command?Converter=/AMIXmlToAMIProdHtml.xsl&Command=FormBrowseDatasetPerRun+-runNumber=%i" target="_blank" title="AMI reference for run %i"><font size="-3">AMI</font></a>,&nbsp;\n' % (self.runNr, self.runNr)
763  # DQ
764  s += ' <a href="https://atlasdqm.web.cern.ch/atlasdqm/DQBrowser/makeMatrix.php?selection=All&run=%i&runup=&dbinstance=COMP200_SHIFTOFL&tag=HEAD" target="_blank" title="Browse detailed data quality entries for run %i (uses SHIFTOFL folder in COMP200 conditions database)"><font size="-3">DQ</font></a>,<br>\n' % (self.runNr, self.runNr)
765  # ELOG
766  s += ' <a href="https://atlasop.cern.ch/elog/ATLAS/ATLAS/?mode=full&reverse=0&reverse=1&npp=20&ma=1&ya=2008&last=3064&subtext=%i&sall=0" target="_blank" title="Search for ELOG entries on run %i"><font size="-3">ELOG</font></a>,&nbsp;\n' % (self.runNr, self.runNr)
767  # DCS reference, format: http://atlas-dcs.cern.ch/navigation.php?datestring=2009-07-26-10-12
768  tbeg = time.strftime("%Y-%m-%d-%H-%M-%S", time.gmtime(self.sor/1.E9))
769  t = time.gmtime(self.eor/1.E9)
770  tend = "%4i-%02i-%02i-%02i-%02i" % (t[0], t[1], t[2], t[3], t[4])
771  s += ' <a href="http://atlas-dcs.cern.ch/navigation.php?date2=%s" target="_blank" title="DCS status at begin of run %i"><font size="-3">DCS:SoR</font></a>/' % (tbeg, self.runNr)
772  s += '<a href="http://atlas-dcs.cern.ch/navigation.php?date2=%s" target="_blank" title="DCS status at end of run %i"><font size="-3">EoR</font></a>,&nbsp;\n ' % (tend, self.runNr)
773  #s += ' <a href="https://atlas-dcs.cern.ch/navigation.php?date2=2008-09-29-19-01-42">DCS:SoR</font></a>/' % (tbeg, self.runNr)
774  #s += '<a href="https://atlas-dcs.cern.ch/navigation.php?date2=2008-09-30-08-17"><font size="-3">EoR</font></a>,&nbsp;\n ' % (tend, self.runNr)
775 
776  # OKS
777  if self.data['oks']:
778  if self.lhcRun<3:
779  s += ' <a href="http://cern.ch/atlas-project-tdaq-cc/cgi/getdata.sh?tdaq-05-05-00&oracle://atlas_oks/r&atlas_oks_archive&%i&%i&ATLAS" target="_blank" title="Download online configuration for run %i"><font size="-3">OKS</font></a>\n' % ( self.data['oks'][0].value + (self.runNr,) )
780  else:
781  (hash, release) = self.data["oks"][0].value
782  s+= f' <a href="https://gitlab.cern.ch/atlas-tdaq-oks/p1/{release}/-/tree/{hash[5:]}" target="_blank" title="Browse online configuration for run {self.runNr}"><font size="-3">OKS</font></a>\n'
783  # lumi summary
784  # typical address: https://atlas.web.cern.ch/Atlas/GROUPS/DATAPREPARATION/RunSummary/run142308_summary.html
785  # OLD: fname = 'https://atlas.web.cern.ch/Atlas/GROUPS/DATAPREPARATION/RunSummary/run%i_summary.html' % (self.runNr)
786  fname = 'http://atlas.web.cern.ch/Atlas/GROUPS/DATAPREPARATION/DataSummary/runsum.py?run=%i\n' % (self.runNr)
787  fwget = urllib.request.urlopen(fname)
788 
789  wincontent = ''
790  for line in fwget:
791  if '</head>' in str(line) and '<base href' not in wincontent:
792  wincontent += '<base href="http://atlas.web.cern.ch/Atlas/GROUPS/DATAPREPARATION/DataSummary/2010/"></base>'
793  wincontent += str(line)
794  wincontent = wincontent.replace('href="css/atlas-datasummary.css"', 'href="http://atlas.web.cern.ch/Atlas/GROUPS/DATAPREPARATION/DataSummary/css/atlas-datasummary.css"')
795 
796  # remove temporarily second plot with integration
797  wincontent = wincontent.replace( '<td>\n<a href="rundata/run%i/run%i_ilumr.png"><img src="rundata/run%i/run%i_ilumr.png" alt="InstLumi" style="width: 200px; "></a></td>' % (self.runNr,self.runNr,self.runNr,self.runNr),'')
798  wincontent = wincontent.replace('"','&quot;')
799  wincontent = wincontent.replace('./RunSummary/figs','https://atlas.web.cern.ch/Atlas/GROUPS/DATAPREPARATION/RunSummary/figs')
800  wincontent = wincontent.replace('<a href','<a target=&quot;_blank&quot; href')
801  wincontent = wincontent.replace('width: 200px','width: 350px')
802  wincontent = wincontent.replace('width: 250px','width: 350px')
803 
804 
805  openwincmd = 'javascript:openLumiWindow('
806  openwincmd += "'Print','<!DOCTYPE html PUBLIC &quot;-//W3C//DTD HTML 4.01 Transitional//EN&quot;><html xmlns:&quot;my&quot;><head><title>Luminosity information for run %i</title></head><body style=&quot;background-color:#ffffff&quot;>" % self.runNr
807  openwincmd += wincontent
808  openwincmd += '</body></html>'
809  openwincmd += "')"
810 
811  return s
812 
813 
814  def timestr(self,format='html',closed=True):
815  """ sor and eor is always in UTC, so sor=0 means the run started 1.1.1970 at 00:00:00"""
816  if QC.localtime:
817  begin = time.localtime(self.sor/1.E9)
818  end = time.localtime(self.eor/1.E9)
819  else:
820  begin = time.gmtime(self.sor/1.E9)
821  end = time.gmtime(self.eor/1.E9)
822 
823  # begin string
824  beginstr = time.strftime("%a %b %d %Y %X",begin)
825 
826  # end format
827  endformat = "%X"
828  if end[0]>begin[0]:
829  endformat = "%a %b %d, %Y %X"
830  elif end[1]>begin[1] or end[2]>begin[2]:
831  endformat = "%a %b %d, %X"
832 
833  # end string
834  if closed:
835  endstr = time.strftime(endformat,end)
836  else:
837  endstr = '<font color=#BB0000>ongoing</font>' if format=='html' else 'ongoing'
838 
839  # output
840  if format=='html':
841  return '%s&nbsp;&minus;&nbsp;%s' % (beginstr,endstr)
842  elif format=='seconds': #mainly for dictionary
843  return '%12.3f, %12.3f' % (self.sor/1.E9, self.eor/1.E9)
844  elif format=='secondsNum': #mainly for dictionary
845  return self.sor/1.E9, self.eor/1.E9
846  else:
847  return '%s - %s' % (beginstr,endstr)
848 
849  def durationstr(self):
850  dt = time.gmtime((self.eor-self.sor)/1.E9)[2:6]
851  if dt[0]>1:
852  return "%id %ih %im %is" % ((dt[0]-1,) + dt[1:])
853  else:
854  return "%ih %im %is" % dt[1:]
855 
856  @classmethod
857  def prettyChain(cls,tr,ps):
858  i = len(ps)-1
859  while i>0:
860  if ps[i]==ps[i-1]:
861  ps[i]=' '
862  elif ps[i]<0:
863  ps[i]='x'
864  else:
865  ps[i]=str(ps[i])
866  i-=1
867  if ps[0] is None:
868  ps[0]='n.a.'
869  elif ps[0]<0:
870  ps[0]='x'
871  else:
872  ps[0]=str(ps[0])
873 
874  pss = '-'.join(ps)
875  s = "%s (%s)" % (tr.name,pss)
876  return s
877 
878  def splitTriggerChains(self, chainlist):
879  res = { 'L1': [], 'L2': [], 'EF': [] }
880  for tr,pslist in chainlist.items():
881  if not tr.forshow:
882  continue
883  k = tr.name[0:2]
884  res[k] += [Run.prettyChain(tr,pslist)]
885  res['L1'].sort()
886  res['L2'].sort()
887  res['EF'].sort()
888  l1chains = '<br> '.join(res['L1'])
889  l2chains = '<br> '.join(res['L2'])
890  efchains = '<br> '.join(res['EF'])
891  ret = ()
892  if l1chains:
893  ret += (l1chains.replace('.0',''), )
894  if l2chains:
895  ret += (l2chains.replace('.0',''), )
896  if efchains:
897  ret += (efchains.replace('.0',''), )
898  return ret
899 
900  def __str__(self):
901  if Run.writehtml:
902  s = ashtml(self)
903  return s
904  else:
905  s = self.astxt()
906  for lbr in self.data:
907  s+= "\n" + lbr.astxt()
908  return s
909 
910  def __lt__(self,other):
911  if isinstance(other,Run):
912  return self.runNr < other.runNr
913  return self.runNr < other
914 
915  def __eq__(self,other):
916  if isinstance(other,Run):
917  return self.runNr == other.runNr
918  return self.runNr == other
919 
920 
921  def astxt(self):
922  s = ""
923  if Run.showrunnr:
924  s += "run %*s %*s " % (_fW['Run']-4,self.runNrS, _fW['NLB'], self.NrLBs)
925  s += " "
926 
927  if Run.showtime:
928  s += "%*s " % (_fW['Time'],self.timestr('txt'))
929 
930  if Run.showduration:
931  dt = time.gmtime((self.eor-self.sor)/1.E9)[2:6]
932  if dt[0]>1:
933  s += "%id %ih %im %is " % ((dt[0]-1,) + dt[1:])
934  else:
935  s += "%2ih %2im %2is " % dt[1:]
936 
937  for k in Run.SortedShowOrder():
938  w = 10
939  if k in _fW:
940  w = _fW[k]
941  v = self.result[k.ResultKey]
942  ostr=v
943  if k == "#Events":
944  ostr = addKommaToNumber(v)
945  elif k.Type == DataKey.STREAM:
946  w=max(len(k.Header)-k.Header.find('_'),_fW['Stream'])
947  if isinstance(ostr,tuple):
948  ostr = ostr[0]
949  elif k=="TriggerMenu":
950  pv = [Run.prettyChain(tr,pslist) for (tr,pslist) in v.items() if tr.forshow]
951  ostr = ", ".join(pv)
952  elif k=="TriggerRates":
953  ostr = "NOT YET"
954  elif k=="olc:bcidmask":
955  ostr = "NOT YET"
956 
957  s += "%*s " % (w,ostr)
958 
959  return s
960 
961 
962 
963 def ashtml(run):
964  import CoolRunQuery.html.AtlRunQueryHtmlUtils as HU
965 
966  with timer("print runnur, runtime, etc"):
967  s = "<!-- Run %s -->\n" % run.runNrS
968 
969  # disctionary with results
970  if Run.bgcolor == "1":
971  Run.bgcolor = "2"
972  else:
973  Run.bgcolor = "1"
974  color = Run.bgcolor
975 
976  runrowclass = "out"
977  if run.showDataIncomplete:
978  runrowclass="showmiss"
979  if run.selDataIncomplete:
980  runrowclass="selmiss"
981  runrowclass += color
982 
983  s += '<tr class="out%s">\n' % (color)
984 
985  if Run.showrunnr: # show columns Run, Links, LB
986  # run number
987  if run.runNr == Run.runnropen: # is the run still ongoing?
988  s += ' <td style="text-align:center" class="%s"><font color="#BB0000">%s<br><font size="-2">(ongoing)</font></font>' % (runrowclass, run.runNrS)
989  else:
990  s += '<td style="text-align:center" class="%s">%s' % (runrowclass, run.runNrS)
991  p = Run.runPeriods.findPeriod( run.runNr )
992  if p:
993  # split in the middle
994  idx=-1
995  for i in range(p.count(',')//2+1):
996  idx = p.find(',',idx+1)
997  s += '<br><font color="#488AC7"><font size=-2><nobr>Period: %s<br>%s</nobr></font></font>' % (p[:idx],p[idx+1:])
998 
999  # open for prompt calibration?
1000  if run.runNr in Run.PromptCalibRuns:
1001  s += '<br><font color="#008800"><font size="-2">(in&nbsp;calib&nbsp;loop)</font></font>'
1002  s += '</td>'
1003 
1004  # links to other information
1005  s += '\n <td>\n%s</td>' % run.runlinks()
1006 
1007  # luminosity block and average lb duration
1008  lbcontent = '%s' % run.NrLBs
1009  try:
1010  vf = float(run.NrLBs)
1011  if vf > 0:
1012  lbcontent = '%s<br><font size="-2">(%i&nbsp;s)</font>' % (run.NrLBs, (run.eor-run.sor)/(1.0E9*vf) )
1013  except ValueError:
1014  pass
1015 
1016  window = HU.OpenWindow( HU.CreateLBTable(run), extracss=['html/atlas-runquery-lb.css'] )
1017 
1018  # put into html page
1019  tip = 'showTip LBStart_%i' % run.runNr
1020  s += '\n <!-- LB Content -->\n'
1021  s += ' <td style="text-align: right"><div class="%s tooltip" style="display:inline;cursor:pointer">%s%s</a></div></td>\n' % (tip, window, lbcontent)
1022 
1023 
1024  if Run.showtime:
1025  s += ' <td>%s</td>' % run.timestr('html',run.runNr != Run.runnropen) # is the run still ongoing?
1026 
1027 
1028  if Run.showduration:
1029  if run.runNr == Run.runnropen:
1030  s += ' <td><font color="#BB0000">%s<br><font size="-2">(ongoing)</font></font></td>' % run.durationstr()
1031  else:
1032  s += " <td>%s</td>" % run.durationstr()
1033 
1034  # find maximum output rate in case of streams
1035  sumstrnev = 0
1036  for k in Run.SortedShowOrder():
1037  if k.Type == DataKey.STREAM and k.ResultKey in run.stats and 'calibration' not in k.ResultKey:
1038  sumstrnev += run.result[k.ResultKey][0]
1039  if sumstrnev == 0:
1040  sumstrnev = -1
1041 
1042  # flags...
1043  ofllumiFlag = False
1044 
1045 
1046  # the loop
1047  with timer("print keys"):
1048  for data_key in Run.SortedShowOrder():
1049  k = data_key.ResultKey
1050  v = run.result[k]
1051 
1052  with timer("keybuild %s" % k, disabled=True):
1053  if any(['olc:beam2intensity' in k,
1054  'olc:beam1intensity' in k,
1055  'lhc:beamenergy' in k,
1056  'beam1bunches' in k,
1057  'beam2bunches' in k,
1058  'collbunches' in k,
1059  'L1 PSK' == k,
1060  ]):
1061  continue
1062 
1063  s += '\n '
1064 
1065  # -----------------------------------------------------------------------------------------------------------------------
1066 
1067  if k == "#Events":
1068  # compute approximative output rate in Hz
1069  durInSec = (run.eor-run.sor)/1.0E9
1070  rate = 'n.a. Hz'
1071  try:
1072  if durInSec > 0:
1073  rate = '%.1f Hz' % (float(v)/durInSec)
1074  except ValueError: # if n.a.
1075  pass
1076  s += ' <td style="text-align: right">%s<BR><font size="-2">(%s)</font></td>' % (addKommaToNumber(v),rate)
1077  continue
1078 
1079  # -----------------------------------------------------------------------------------------------------------------------
1080 
1081  if k == "#L1A" or k == '#L2A' or k == '#EFA' or k == '#Events (streamed)' or k == '#Events (incl. calib.)':
1082  s += ' <td style="text-align: right">%s</td>' % addKommaToNumber(v)
1083  continue
1084 
1085  # -----------------------------------------------------------------------------------------------------------------------
1086 
1087  if k == 'DQ': # DEFECT
1088  intolerable = Run.Fieldinfo['DQ']['IntolerableDefects']
1089 
1090  for channelname in Run.Fieldinfo['DQ']['DefChannels']:
1091  if channelname == '':
1092  matching_dqentries = run.stats[k]["defects"]
1093  elif channelname == 'DET':
1094  matching_dqentries = [dqentry for dqentry in run.stats[k]["defects"] if '_' not in dqentry[0]]
1095  else:
1096  from re import compile
1097  pattern = compile(channelname)
1098  matching_dqentries = [dqentry for dqentry in run.stats[k]["defects"] if pattern.match(dqentry[0])]
1099 
1100 
1101  # reduce to LB ranges inside READY
1102  matching_dqentries_ready = []
1103  for (defect, listLBranges) in matching_dqentries: # dqentry is of format ('SCT_GLOBAL_STANDBY', [(1L, 49L), (119L, 123L)])
1104  readyLBRanges = [lbrange for lbrange in listLBranges if run.data.isReady(lbrange)]
1105  if len(readyLBRanges)>0:
1106  matching_dqentries_ready += [ (defect, readyLBRanges) ]
1107 
1108 
1109  if len(matching_dqentries_ready)==0:
1110  dq_info = "<table class='dqdefects' style='border-color: limegreen; height=100%'><tr><td>&nbsp;</td></tr></table>\n"
1111  else:
1112  dq_info = "<table class='dqdefects'>\n"
1113  for defect,listLBranges in matching_dqentries_ready:
1114  tip = 'showTip dqdefect_%i_%s tooltip' % (run.runNr, defect)
1115  if defect in intolerable:
1116  dq_info += "<tr class='%s'><td class='intolerable'>%s</td><td class='lb'>" % (tip, defect)
1117  else:
1118  dq_info += "<tr class='%s tolerable' style='visibility:collapse;'><td>%s</td><td class='lb'>" % (tip, defect)
1119  dq_info += ", ".join([("%g&minus;%g" % (x[0],x[1]-1) if x[1]-x[0]!=1 else "%g" % x[0]) for x in listLBranges])
1120  dq_info += "</td></tr>\n"
1121  dq_info += '<tr height="100%%"><td height="100%%"></td></tr>\n'
1122  dq_info += "</table>\n"
1123  s += '<td class="def">%s</td>' % dq_info
1124 
1125  continue
1126 
1127  # -----------------------------------------------------------------------------------------------------------------------
1128 
1129  if isDQ(k): # old, traffic-light DQ
1130  extraDQInfo = ''
1131  tip = ''
1132  dqmax = run.stats[k]["max"]
1133  n = run.stats[k]["counts"]
1134 
1135  foundComment = False
1136  for (dq,comment), start, end in run.stats[k]["blocks"]:
1137  dqcss = dq
1138  if dq == 'n.a.':
1139  dqcss = 'NA'
1140  elif comment:
1141  foundComment = True
1142 
1143  if n[dq]>0 and dq != dqmax:
1144  if start == end-1: # only one LB
1145  extraDQInfo += '<tr><td class="td%s" style="min-width: 45px; text-align: left; border-width: 0px; padding:1px;">&nbsp;LB&nbsp;%g:</td><td class="td%s" style="text-align: left; border-width: 0px; padding: 1px; ">%s&nbsp;</td></tr>' % (dqcss,start,dqcss,dq)
1146  else: # range of LBs
1147  extraDQInfo += '<tr><td class="td%s" style="min-width: 45px; text-align: left; border-width: 0px; padding:1px;">&nbsp;LB&nbsp;%g&minus;%g:</td><td class="td%s" style="text-align: left; border-width: 0px; padding: 1px; ">%s&nbsp;</td></tr>' % (dqcss,start,end-1,dqcss,dq)
1148 
1149  if foundComment:
1150  tip = 'showTip dqcomm_%s_%i' % (k, run.runNr)
1151  if extraDQInfo:
1152  extraDQInfo = '<br><img vspace=2 height="1" width="1" src="wdot.jpg"><br><table style="width: 100%; border: 1px solid; border-width: 1px; border-spacing: 0px; border-color: #eeeeee; border-collapse: separate; padding: 0px; font-size: 65%"><tr>' + extraDQInfo + '</table>'
1153 
1154  if tip:
1155  s += '<td class="%s td tooltip td%s">%s%s</td>' % (tip,dqmax,dqmax,extraDQInfo)
1156  else:
1157  s += '<td class="td td%s">%s%s</td>' % (dqmax,dqmax,extraDQInfo)
1158 
1159  continue
1160 
1161  # -----------------------------------------------------------------------------------------------------------------------
1162 
1163  if "detector systems" in k.lower():
1164  if v!='n.a.':
1165  mask = '0x'+v if Selector.condDB()=='CONDBR2' else v # run2 the format is a hex string, in run 1 it is an int (represented as string)
1166  v = DecodeDetectorMask( mask=mask, lhcRun=run.lhcRun, smart=True)
1167  s += ' <td style="min-width:%ipx"><font size="-2">%s<hr color="#aaaaaa" size=1>[<a href="http://sroe.home.cern.ch/sroe/cgi-bin/avgmodule.py?run=%i" target=_blank>SCT HV setting</a>]</font></td>' % (1.1*len(v),v,run.runNr)
1168  continue
1169 
1170  # -----------------------------------------------------------------------------------------------------------------------
1171 
1172  if 'olc:lumi' in k:
1173 
1174  # find range with stable beams (requires LHC information to be available)
1175  hasStableBeamsInfo, xvecStb = run.getStableBeamsVector()
1176 
1177  # is pileup information available?
1178  printMu = 'olc:bcidmask' in Run.SortedShowOrder() and run.runNr>=151260 and run.givepeakmuinfo
1179 
1180  # insert events per LB
1181  xvec = []
1182  yvec = []
1183  yvecInt = []
1184  for entry in run.data[k]:
1185  assert entry.startlb != 0, 'entry should not start at LB=0'
1186  val = entry.value if (entry.value!='n.a.' and entry.value>0) else 0
1187  lastlb = min(entry.lastlb,run.nr_lb)
1188  xvec += range(entry.startlb,lastlb+1)
1189  nlb = lastlb - entry.startlb + 1
1190  yvec += nlb*[val]
1191  yvecInt += nlb*[val]
1192 
1193  # correct for time span
1194  intlumi, intlumiStb = (0, 0)
1195 
1196  # for lifetime
1197  lifetime = 0
1198  lb1 = 0
1199  lb2 = 0
1200  t1 = 0
1201  t2 = 0
1202  y1 = 0
1203  y2 = 0
1204  if len(xvecStb) > 15:
1205  lb1 = xvecStb[3]
1206  lb2 = xvecStb[-1-5]
1207 
1208  peaklumi = -1
1209  for idx,(lbtime,lbendtime) in enumerate(run.lbtimes):
1210  lb=idx+1
1211  dt = (float(lbendtime)-float(lbtime))/1.E9
1212  yvecInt[idx] *= dt/1000.0*run.lumiunit # unit of yvec was: ub-1 s-1 -> nb-1
1213  yvec[idx] *= 1.0*run.lumiunit # unit of yvec was: ub-1 s-1, transform to: 10^30 cm-2s-1
1214  intlumi += yvecInt[idx]
1215 
1216  if yvec[idx] > peaklumi:
1217  peaklumi = yvec[idx]
1218  if lb in xvecStb:
1219  intlumiStb += yvecInt[idx]
1220  if lb == lb1:
1221  t1 = lbtime/1.E9
1222  y1 = yvec[idx]
1223  elif lb == lb2:
1224  t2 = lbtime/1.E9
1225  y2 = yvec[idx]
1226 
1227  if y1 > 0 and y2 > 0:
1228  lifetime = (t2 - t1)/(3600*math.log(y1/y2)) # unit: hours
1229 
1230  # line to be printed in column
1231  if hasStableBeamsInfo:
1232  fullprint_ = 'All&nbsp;LBs:&nbsp;%0.4g<br>Stable&nbsp;B:&nbsp;%0.4g' % (intlumi,intlumiStb)
1233  histoText = 'Integrated luminosity: %.4g %s-1 (all LBs) and %.4g %s-1 (stable beams)' % (intlumi,run.lumiunittxt,intlumiStb,run.lumiunittxt)
1234  else:
1235  fullprint_ = 'All&nbsp;LBs:&nbsp;%0.4g' % (intlumi)
1236  histoText = 'Integrated luminosity: %.4g %s-1 (all LBs)' % (intlumi,run.lumiunittxt)
1237 
1238  # find out which channel was used
1239  tp1, tp2, chan = k.split(':')
1240  try:
1241  chan = int(chan)
1242  if chan in OLCAlgorithms:
1243  chanstr = OLCAlgorithms[chan]
1244  else:
1245  chanstr = 'UNKNOWN'
1246  except ValueError:
1247  chanstr = chan
1248 
1249  path = makeLBPlot( xvec, xvecStb, yvec, 'Luminosity block number', 'Online luminosity (10^{%s}cm^{-2}s^{-1})' % run.instlumiunittxt, '',
1250  'olclumi_vs_lb_run_%i' % (run.runNr),
1251  'Online lumi [%s] per LB for run %i' % (chanstr, run.runNr),
1252  QC.datapath, histoText )
1253 
1254  # create window and tooltip
1255  wincontent = '<table class=&quot;outer&quot; style=&quot;padding: 5px&quot;><tr><td>'
1256  wincontent += '<strong><b>Online luminosity [algorithm: %s] per LB for run %i:</b></strong><br><font size=&quot;-1&quot; color=&quot;#888888&quot;>(Begin/end of run: %s)</font>' % (chanstr, run.runNr, run.timestr('html', run.runNr != Run.runnropen))
1257  wincontent += '<hr color=&quot;black&quot; size=1>'
1258  wincontent += '<table style=&quot;padding: 0px&quot;><tr><td>'
1259  wincontent += '<img src=&quot;%s&quot; align=&quot;left&quot;>' % path
1260  wincontent += '</td></tr></table>'
1261  wincontent += '<hr color=&quot;black&quot; size=1>'
1262  wincontent += '<table class=&quot;LB&quot;>'
1263  wincontent += '<tr><th>LB</th><th>Start time<br> (%s)</th><th>Duration<br>(sec)</th><th>Inst. luminosity<br>(1e%s&nbsp;cm<sup>&minus;2</sup>s<sup>&minus;1</sup>)</th>' % (QC.tzdesc(), run.instlumiunittxt)
1264  wincontent += '<th>Int. luminosity<br>(%s<sup>&minus;1</sup>)</th><th>Cumul. luminosity<br>(%s<sup>&minus;1</sup>)</th>' % (run.lumiunittxt, run.lumiunittxt)
1265  if printMu:
1266  wincontent += '<th>&nbsp;&nbsp;&lt;&mu;&gt;&nbsp;&nbsp;</th>'
1267  if hasStableBeamsInfo:
1268  wincontent += '<th>Stable beams</th>'
1269  wincontent += '</tr><tr style=&quot;background:%s&quot;>' % '#eeeeee'
1270  intlumi = 0
1271  mumax = -1
1272  minBiasXsec = 80.0 if Selector.isRun2() else 71.5 # minbias cross-section for 8TeV (71.5) and 13TeV (80.0)
1273 
1274  is5TeVRun = (run.sor/1.E9) > time.mktime((2017,11,11,0,0,0,0,0,0)) and (run.sor/1.E9) < time.mktime((2017,11,21,8,0,0,0,0,0))
1275  if is5TeVRun:
1276  minBiasXsec = 66.25
1277 
1278  is5TeVHIRun = (run.sor/1.E9) > time.mktime((2018,11,7,0,0,0,0,0,0)) and (run.sor/1.E9) < time.mktime((2018,12,31,0,0,0,0,0,0))
1279  if is5TeVHIRun:
1280  minBiasXsec = 7660
1281 
1282  for idx,(lbtime,lbendtime) in enumerate(run.lbtimes):
1283  lb=idx+1
1284  isStableBeams = (lb in xvecStb)
1285  intlumi += yvecInt[idx]
1286  stbBeams = 'T' if isStableBeams else '&minus;'
1287  timetuple = time.localtime(lbtime/1.E9) if QC.localtime else time.gmtime(lbtime/1.E9)
1288  wincontent += '<td>%s</td><td>%s</td><td>%.2f</td><td>%.4g</td><td>%.4g</td><td>%.4g</td>' % (lb, time.strftime("%X",timetuple), (float(lbendtime)-float(lbtime))/1.E9, yvec[idx], yvecInt[idx], intlumi)
1289  # pileup <mu> information?
1290  if printMu:
1291  nb = 0
1292  for n,v,lbstart,lbend in run.stats['olc:bcidmask']['blocks']:
1293  if lb >= lbstart and lb <= lbend:
1294  if v:
1295  nb = len(v[2])
1296  break
1297  # compute expected number of interactions
1298  lumi_mb = yvec[idx]*1000.0
1299  mu = 0
1300  if nb:
1301  mu = lumi_mb * minBiasXsec / 11245.511 / nb
1302  wincontent += '<td>%.3g</td>' % mu
1303  if isStableBeams and mu > mumax:
1304  mumax = mu
1305  if hasStableBeamsInfo:
1306  wincontent += '<td>%s</td>' % stbBeams
1307  if idx%2!=0:
1308  col = '#eeeeee'
1309  else:
1310  col = '#ffffff'
1311  wincontent += '</tr><tr style=&quot;background:%s&quot;>' % col
1312 
1313  printMuInfoToFile = True
1314  if printMuInfoToFile:
1315  mutextfilename = QC.datapath + '/mu_vs_run_output.txt'
1316  muout = open( mutextfilename, 'a' )
1317  muout.write( '%10i %f\n' % (run.runNr, mumax) )
1318  muout.close()
1319 
1320  if mumax < 0:
1321  s_mumax = "n.a."
1322  elif mumax < 0.1:
1323  s_mumax = "%0.3e" % mumax
1324  else:
1325  s_mumax = "%0.3f" % mumax
1326 
1327  if run.runNr == Run.runnropen: # run still ongoing
1328  wincontent += '<tr><td style=&quot;text-align:left&quot;colspan=&quot;3&quot;><i>&nbsp;&nbsp;Run still ongoing ...</i></td></tr>'
1329  wincontent += '</tr></table>'
1330 
1331  wincontent += """<hr color=&quot;red&quot; size=1><font color=&quot;#777777&quot;><font size=&quot;-1&quot;><i><font size=&quot;-2&quot;>Created by AtlRunQuery on: %s</font></i></font></td></tr></table><script type=&quot;text/javascript&quot;></script></body></html>""" % str(datetime.datetime.now())
1332  wincontent += '</td></tr></table>'
1333 
1334  openwincmd = '<a href="javascript:openLargeWindow('
1335  openwincmd += "'Print','<!DOCTYPE html PUBLIC &quot;-//W3C//DTD HTML 4.01 Transitional//EN&quot;><html xmlns:&quot;my&quot;><head><title>Run query result for online luminosity</title><LINK href=&quot;html/atlas-runquery-lb.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot;></head><body><table style=&quot;font-family: sans-serif; font-size: 85%%&quot;>"
1336  openwincmd += wincontent
1337  openwincmd += "')\">"
1338 
1339  # line to be printed in column
1340  fullprint = '<table class="bcidtable">'
1341  fullprint += '<tr><td colspan="2"><img src="%s" align="left" width="90px"></td></tr>' % path
1342  if hasStableBeamsInfo:
1343  fullprint += '<tr><td style="text-align:left">Entire&nbsp;run:</td><td style="text-align:left">&nbsp;%0.4g&nbsp;%s<sup>&minus;1</sup></td></tr><tr><td style="text-align:left">Stable&nbsp;beams:</td><td style="text-align:left">&nbsp;%0.4g&nbsp;%s<sup>&minus;1</sup></td></tr><tr><td style="text-align:left">Peak&nbsp;lumi:</td><td style="text-align:left">&nbsp;%.2g&nbsp;e%s&nbsp;cm<sup>&minus;2</sup>s<sup>&minus;1</sup></td></tr><tr><td style="text-align:left">Peak&nbsp;&lt;&mu;&gt;:</td><td style="text-align:left">&nbsp;%s</td></tr>' % (intlumi, run.lumiunittxt, intlumiStb, run.lumiunittxt, peaklumi, run.instlumiunittxt, s_mumax)
1344  if lifetime > 0:
1345  fullprint += '<tr><td style="text-align:left">Approx.&nbsp;lifetime:</td><td style="text-align:left">&nbsp;%0.2g&nbsp;h</td></tr>' % (lifetime)
1346  else:
1347  fullprint += '<td style="text-align:left">All&nbsp;LBs:</td><td style="text-align:left">&nbsp;%0.4g</td></tr>' % (intlumi)
1348  fullprint += '</table>'
1349 
1350  # put into html page
1351  s += '<td class="showTip OLCLumi stream" style="text-decoration:none; text-align: right">%s%s</a></td>' % (openwincmd, fullprint)
1352 
1353  continue
1354 
1355  # -----------------------------------------------------------------------------------------------------------------------
1356 
1357  if 'olc:bcidmask' in k:
1358 
1359  firstGoodRun = 151260
1360  if run.runNr < firstGoodRun: # OLC information not properly filled
1361  s += '<td style="text-align:center;color:#AA0000;font-size:60%%;">BCID information only available for run numbers larger than %i</font></td>' % firstGoodRun
1362  continue
1363 
1364  # line to be printed in column
1365  fullprint = '<font size=-2><i>Run without stable beams (or, in few cases, missing bunch information in COOL). Click here to obtain bunch crossing information</i>.</font>'
1366 
1367  wincontent = '<table class=&quot;outer&quot; style=&quot;padding: 5px&quot;><tr><td>'
1368  wincontent += '<strong><b>Identifiers (BCID) for paired and unpaired bunches for run %i:</b></strong><br><font size=&quot;-1&quot; color=&quot;#888888&quot;>(Begin/end of run: %s)</font>' % (run.runNr, run.timestr('html', run.runNr != Run.runnropen))
1369  wincontent += '<hr color=&quot;black&quot; size=1>'
1370  wincontent += '<table class=&quot;bcidtable&quot; align=&quot;center&quot;><tr class=&quot;tr0&quot;><td style=&quot;text-align:left;font-weight:bold&quot; colspan=&quot;3&quot;>LB&nbsp;range</td><td style=&quot;text-align:right;font-weight:bold&quot;>&nbsp;&nbsp;&nbsp;&nbsp;Stable<br>beams</td><td style=&quot;text-align:right;font-weight:bold&quot;>%s</td><td style=&quot;text-align:right;font-weight:bold&quot;>%s</td><td style=&quot;text-align:right;font-weight:bold&quot;>%s</td></tr>' % ('&nbsp;&nbsp;Crossing&nbsp;(Paired)', '<nobr>&nbsp;&nbsp;Unpaired&nbsp;Beam-1&nbsp;</nobr>', '<nobr>&nbsp;&nbsp;Unpaired&nbsp;Beam-2</nobr>')
1371  ic = 0
1372 
1373  # retrieve stable beam information
1374  hasStableBeamsInfo, xvecStb = run.getStableBeamsVector()
1375 
1376  first = True
1377  for n,v,lbstart,lbend in run.stats[k]['blocks']:
1378  ic += 1
1379  cls = 'tr1' if (ic%2==1) else 'tr2'
1380 
1381  # is this block during stable beams ?
1382  isInStableBeamPeriod = False
1383  stableBeamWord = '&minus;'
1384  if hasStableBeamsInfo:
1385  if lbstart <= xvecStb[-1] and lbend >= xvecStb[0]:
1386  isInStableBeamPeriod = True
1387  stableBeamWord = '<b>T</b>'
1388 
1389  wincontent += '<tr class=&quot;%s&quot;><td class=&quot;td1&quot; style=&quot;text-align:right&quot;><b>%s</b></td><td style=&quot;text-align:right&quot;><b>&minus;</b></td><td style=&quot;text-align:right&quot;><b>%s:</b>&nbsp;&nbsp;&nbsp;</td><td>%s&nbsp;&nbsp;&nbsp;&nbsp;</td>' % (cls,str(lbstart),str(lbend-1),stableBeamWord)
1390  if v:
1391  beam1, beam2, beam12 = v
1392  unpaired1 = [b for b in beam1 if b not in beam12]
1393  unpaired2 = [b for b in beam2 if b not in beam12]
1394 
1395  noBunches = not unpaired1 and not unpaired2 and not beam12 # happens at least in run 152508
1396  if not unpaired1:
1397  unpaired1 = ['&minus;']
1398  if not unpaired2:
1399  unpaired2 = ['&minus;']
1400  if not beam12:
1401  beam12 = ['&minus;']
1402 
1403  # analyse bunch train structure
1404  if isInStableBeamPeriod and first and not noBunches:
1405  first = False # don't do that again
1406 
1407  maxBunchDistanceInTrain = 6
1408  if int(run.runNr) > 168665:
1409  maxBunchDistanceInTrain = 25 # large (20) bunch distance for Heavy Ion collisions
1410  trains = []
1411  bp = -1
1412  for b in beam12:
1413  if bp > 0 and b - bp <= maxBunchDistanceInTrain:
1414  if trains[-1][-1] != bp:
1415  trains.append([bp])
1416  trains[-1].append(b)
1417  elif len(beam12) > 1 and bp <= 0 and beam12[0] - b <= maxBunchDistanceInTrain:
1418  trains.append([b])
1419  bp = b
1420 
1421  fullprint = '<table class = "triggerlinktable">'
1422  fullprint += '<tr><td style="text-align:left"><nobr>No. of coll. bunches:&nbsp;&nbsp;</nobr></td><td> <b>%i</b></td></tr>' % len(beam12)
1423  fullprint += '<tr><td style="text-align:left"><nobr>No. of bunch trains:</nobr></td><td><b> %i</b></td></tr>' % len(trains)
1424  if trains:
1425  Run.TmpBoxContent = '<strong><b><nobr>Bunch train configuration for run <font color="#AA0000">%i</font></nobr></b></strong>' % run.runNr
1426  Run.TmpBoxContent += '<hr size=1>'
1427 
1428  # it may be that the BCID=1 is a single pilot bunch only without a train
1429  # in that case, don't use it to compute bunch distance in train, but print comment
1430  icoor = 0
1431  if len(trains) > 1:
1432  icoor = 1
1433  if len(trains[icoor]) > 1:
1434  bunchDist = trains[icoor][1] - trains[icoor][0]
1435  fullprint += '<tr><td style="text-align:left"><nobr>Bunch dist. in trains:</nobr></td><td><nobr><b> %i</b> (%i ns)</nobr></td></tr>' % (bunchDist, bunchDist*25)
1436  # print the comment in case of single pilot bunch
1437  if len(trains) > 0:
1438  if len(trains[0]) == 1:
1439  fullprint += '<tr><td style="text-align:left;color:#4477EE" colspan=2><i>The first "bunch train" is trivial and consists of only the colliding pilot bunch</td></tr>'
1440  fullprint += '</table><hr size=1>'
1441  Run.TmpBoxContent += '<table><tr><td>Train</td><td><nobr>No. of bunches</nobr></td><td style="text-align:right">&nbsp;&nbsp;&nbsp;BCID range</td></tr>'
1442  for it, train in enumerate(trains):
1443  Run.TmpBoxContent += '<tr><td>&nbsp;&nbsp;%i:&nbsp;&nbsp;</td><td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;%i</td><td style="text-align:right"><nobr>&nbsp;&nbsp;%i &minus; %i</nobr></td></tr>' % (it+1, len(train), train[0], train[-1])
1444  Run.TmpBoxContent += '</table><hr size=1>'
1445  else:
1446  Run.TmpBoxContent = '<nobr>No bunch trains in this run</nobr> <hr size=1>'
1447  fullprint += '</table><hr size=1>'
1448  Run.TmpBoxContent += '<p><font color="#AA0000"><b><nobr>Click to obtain full list of BCIDs</nobr></b></font>'
1449  fullprint += '<span style="font-size: xx-small; color: #555555">[ <i>Mouse over for train configuration. Click for full list of BCIDs</i> ]</span>'
1450 
1451  wincontent += '<td class=&quot;td1&quot; style=&quot;text-align:right&quot;>%s</td><td style=&quot;text-align:right; border-left:1px #C0C0D0 solid;border-right:1px #C0C0D0 solid&quot;>%s</td><td style=&quot;text-align:right&quot;>%s</td>' % (', '.join(map(str,beam12)), ', '.join(map(str,unpaired1)), ', '.join(map(str,unpaired2)) )
1452  else:
1453  wincontent += '<td class=&quot;td1&quot; style=&quot;text-align:right&quot;>%s</td><td style=&quot;text-align:right&quot;>%s</td><td style=&quot;text-align:right&quot;>%s</td>' % ('&minus;','&minus;','&minus;')
1454 
1455  wincontent += '</tr>'
1456 
1457 
1458  wincontent += '</table></td>'
1459  wincontent += '</td></tr></table>'
1460 
1461 
1462  openwincmd = HU.OpenWindow(wincontent, title="Run query result for online luminosity", extracss=None, size="large")
1463  #openwincmd = '<a href="javascript:openLargeWindow('
1464  #openwincmd += "'Print','<!DOCTYPE html PUBLIC &quot;-//W3C//DTD HTML 4.01 Transitional//EN&quot;><html xmlns:&quot;my&quot;><head><title>Run query result for online luminosity</title><LINK href=&quot;html/atlas-runquery-results.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot;></head><body><table style=&quot;font-family: sans-serif; font-size: 85%%&quot;>"
1465  #openwincmd += wincontent
1466  #openwincmd += "')\">"
1467 
1468  s += '<td class="showTip OLCBCID_%i stream" style="text-decoration:none; text-align: left">%s%s</a></td>' % (run.runNr, openwincmd, fullprint)
1469 
1470  continue
1471 
1472  # -----------------------------------------------------------------------------------------------------------------------
1473 
1474  if k.startswith('bs:Pos') or k.startswith('bs:Sig') or k.startswith('bs:Tilt'):
1475 
1476  # reference for average
1477  refkey = 'bs:Sig-X' # must exist !
1478  statkey = 'bs:Status' # must exist !
1479 
1480  onloffltype = 'Online' if (run.stats['Beamspot']=='online') else 'Offline'
1481 
1482  # given is beamspot position or width or tilt
1483  xvec = []
1484  yvec = []
1485  yvecSt = []
1486  bsidx = []
1487  isOK = False
1488  vave = 0
1489  eave = 0
1490  iave = float(0)
1491  idx = 0
1492 
1493  for entry in run.data[k]:
1494  if entry.startlb==0 and entry.lastlb==0:
1495  continue
1496 
1497  val,valerr = entry.value
1498  ref = run.data[refkey].atLB(entry.startlb)[0].value[0]
1499  stat = run.data[statkey].atLB(entry.startlb)[0].value
1500 
1501  lastlb = min(entry.lastlb,run.lastlb)
1502  lbs = range(entry.startlb,lastlb+1)
1503  nlb = len(lbs)
1504 
1505  xvec += [nlb]
1506  yvec += [(val,valerr)]# * nlb
1507  yvecSt += [stat]# * nlb
1508  bsidx += [idx] * nlb
1509  idx += 1
1510 
1511  # compute average if BS has been determined
1512  if ref < 10:
1513  vave += nlb * val
1514  eave += nlb * val**2
1515  iave += nlb
1516  isOK = True
1517 
1518  if not isOK:
1519  s += '<td>n.a.</td>'
1520  continue
1521 
1522  if iave>0:
1523  vave /= float(iave)
1524  rad = eave/iave - vave*vave
1525  if rad>=0:
1526  eave = math.sqrt(rad)
1527  else:
1528  eave = 0
1529  else:
1530  vave = -1
1531 
1532  ymin = vave - 3*eave
1533  ymax = vave + 3*eave
1534 
1535  if ymin >= ymax:
1536  ymin = ymin*0.9
1537  ymax = ymin*1.1
1538  if ymin >= ymax:
1539  ymin = -0.1
1540  ymax = 0.1
1541 
1542  if ymin==ymax:
1543  delta = 0.1*abs(ymax)
1544  else:
1545  delta = 0.1*(ymax-ymin)
1546  ymin -= delta
1547  ymax += delta
1548 
1549 
1550  bstype = 'pos'
1551  if 'Sig' in k:
1552  bstype = 'width'
1553  elif 'Tilt' in k:
1554  bstype = 'tilt'
1555  bstype += k[k.find('-'):]
1556 
1557  histoText = 'Average beam spot %s: (%.4g +- %.1g) mm' % (bstype, vave, eave)
1558 
1559  path = makeBSPlots( xvec=xvec, yvec=yvec,
1560  xtitle = 'Luminosity block number', ytitle = '%s beamspot %s (mm)' % (onloffltype, bstype),
1561  histname = '%s_vs_lb_run_%i' % (k.replace(':','_').replace('-','_'), run.runNr),
1562  histtitle = '%s beamspot %s per LB for run %i' % (onloffltype, bstype, run.runNr),
1563  datapath = QC.datapath, ymin = ymin, ymax = ymax, printText = histoText )
1564 
1565 
1566  # create window and tooltip
1567  wincontent = '<table class=&quot;outer&quot; style=&quot;padding: 5px&quot;><tr><td>'
1568  wincontent += '<strong><b>%s beamspot %s per LB for run %i:</b></strong><br><font size=&quot;-1&quot;><font color=&quot;#888888&quot;>(Begin/end of run: %s)</font></font><hr color=&quot;black&quot; size=1>' % (onloffltype, bstype, run.runNr, run.timestr('html', run.runNr != Run.runnropen))
1569  wincontent += '<table style=&quot;padding: 0px&quot;><tr><td>'
1570  wincontent += '<img src=&quot;%s&quot; align=&quot;left&quot;>' % (path)
1571  wincontent += '</td></tr></table>'
1572  wincontent += '<hr color=&quot;black&quot; size=1>'
1573 
1574  wincontent += '<table style=&quot;width: auto; border: 0px solid; border-width: margin: 0 0 0 0; border-spacing: 0px; border-collapse: separate; padding: 0px; font-size: 90%; vertical-align:top; &quot;>'
1575  wincontent += '<tr><th style=&quot;text-align:right&quot;>LB</th><th style=&quot;text-align:right&quot;>&nbsp;&nbsp;&nbsp;Start time<br> (%s)</th><th style=&quot;text-align:right&quot;>&nbsp;&nbsp;&nbsp;Duration<br>(sec)</th><th style=&quot;text-align:right&quot;>&nbsp;&nbsp;&nbsp;Beamspot %s<br>(mm)</th><th style=&quot;text-align:right&quot;>&nbsp;&nbsp;&nbsp;Fit&nbsp;status</th>' % (QC.tzdesc(),bstype)
1576  wincontent += '</tr><tr style=&quot;background:%s&quot;>' % '#eeeeee'
1577  for idx,(lbtime,lbendtime) in enumerate(run.lbtimes):
1578  lb=idx+1
1579  timetuple = time.localtime(lbtime/1.E9) if QC.localtime else time.gmtime(lbtime/1.E9)
1580  wincontent += '<td style=&quot;text-align:right&quot;>&nbsp;&nbsp;%s</td>' % lb
1581  wincontent += '<td style=&quot;text-align:right&quot;>&nbsp;%s</td>' % time.strftime("%X",timetuple)
1582  wincontent += '<td style=&quot;text-align:right&quot;>%.2f</td>' % ((float(lbendtime)-float(lbtime))/1.E9)
1583  wincontent += '<td style=&quot;text-align:right&quot;>%.4g &plusmn; %.2g</td>' % yvec[bsidx[idx]]
1584  wincontent += '<td style=&quot;text-align:right&quot;>%i</td>' % yvecSt[bsidx[idx]]
1585 
1586  if idx%2!=0:
1587  col = '#eeeeee'
1588  else:
1589  col = '#ffffff'
1590  wincontent += '</tr><tr style=&quot;background:%s&quot;>' % col
1591  if run.runNr == Run.runnropen: # run still ongoing
1592  wincontent += '<tr><td style=&quot;text-align:left&quot;colspan=&quot;3&quot;><i>&nbsp;&nbsp;Run still ongoing ...</i></td></tr>'
1593  wincontent += '</tr></table>'
1594 
1595  wincontent += """<hr color=&quot;red&quot; size=1><font color=&quot;#777777&quot;><font size=&quot;-1&quot;><i><font size=&quot;-2&quot;>Created by AtlRunQuery on: %s</font></i></font></td></tr></table><script type=&quot;text/javascript&quot;></script></body></html>""" % str(datetime.datetime.now())
1596  wincontent += '</td></tr></table>'
1597 
1598  openwincmd = '<a href="javascript:openWindow('
1599  openwincmd += "'Print','<!DOCTYPE html PUBLIC &quot;-//W3C//DTD HTML 4.01 Transitional//EN&quot;>"
1600  openwincmd += "<html><head><title>Run query result for the %s beamspot</title><LINK href=&quot;html/atlas-runquery-lb.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot;></head>" % (onloffltype.lower())
1601  openwincmd += "<body><table style=&quot;font-family: sans-serif; font-size: 85%&quot;>"
1602  openwincmd += wincontent
1603  openwincmd += "</table></body></html>"
1604  openwincmd += "')\">"
1605 
1606  # plot
1607  fullprint = '<table class="triggerlinktable">'
1608  fullprint += '<tr><td colspan="2"><img src="%s" align="left" width="90px"></td></tr>' % path
1609  fullprint += '<tr><td colspan="2"></td></tr>'
1610  if isOK:
1611  fullprint += '<tr><td style="text-align:left">Average&nbsp;%s:</td></tr><tr><td style="text-align:left"><nobr>&nbsp;%0.3g&nbsp;&plusmn;&nbsp;%.2g&nbsp;(RMS)</nobr></td></tr>' % (bstype, vave, eave)
1612  fullprint += '</table>'
1613 
1614  # put into html page
1615  s += '<td class="showTip OFLBS stream" style="text-decoration:none; text-align: right">%s%s</a></td>' % (openwincmd, fullprint)
1616  continue
1617 
1618  # -----------------------------------------------------------------------------------------------------------------------
1619 
1620  if "STR:" == k[0:4]:
1621  streamName = k[4:]
1622  if 'n.a.' in v:
1623  s += '<td class="tdna">n.a.</td>'
1624  continue
1625 
1626  # compute approximative output rate in Hz
1627  durInSec = (run.eor-run.sor)/1.0E9
1628  rate = 'n.a.&nbsp;Hz'
1629  try:
1630  if durInSec > 0:
1631  rate = '%.3f&nbsp;Hz' % (v[0]/durInSec)
1632  except ValueError:
1633  pass
1634  strevents = v[0]
1635  strsize = v[1]
1636  # add relative fraction (only if not calibrtion string)
1637  fracstr = ''
1638  if 'calibration' not in k:
1639  fracstr = '%.1f%%,' % (float(strevents)/sumstrnev*100)
1640 
1641 
1642  ev = {}
1643  xvec = []
1644  xvecStb = []
1645  yvecN = []
1646  yvecR = []
1647  nevtot = 0
1648 
1649  # statistics
1650  maxrate = -1
1651  averate = 0
1652  nc = 0
1653 
1654  # insert events per LB
1655  lbrecinfo = run.stats[k]['LBRecInfo']
1656 
1657  isPhysicsStream = lbrecinfo is not None and len(lbrecinfo)>0
1658  if isPhysicsStream: # only for physics stream we have LB wise information
1659  ev = dict(lbrecinfo)
1660  for lb in ev:
1661  ev[lb]=0
1662  for lb,nev in lbrecinfo:
1663  ev[lb] += nev
1664  for idx,(lbtime,lbendtime) in enumerate(run.lbtimes):
1665  lb=idx+1
1666  nev = 0
1667  if lb in ev:
1668  nev = ev[lb]
1669  xvec.append(lb)
1670  yvecN.append(nev)
1671  yvecR.append(0)
1672  nevtot += nev
1673  try:
1674  if float(lbendtime)-float(lbtime) > 0:
1675  yvecR[-1] = nev/((float(lbendtime)-float(lbtime))/1.E9)
1676  except ValueError:
1677  pass
1678 
1679 
1680  # find range with stable beams (requires LHC information to be available)
1681  hasStableBeamsInfo, xvecStb = run.getStableBeamsVector()
1682 
1683  # prepare pop-up window
1684  wincontent = '<table class=&quot;outer&quot; style=&quot;padding: 5px&quot;>'
1685  wincontent += '<tr><td><b>Number of events and rates per LB for stream %s run %i:</b><br><font size=&quot;-1&quot;><font color=&quot;#888888&quot;>(Begin/end of run: %s)</font></font><hr color=&quot;black&quot; size=1>' % (streamName, run.runNr, run.timestr('html', run.runNr != Run.runnropen))
1686 
1687  # create plot
1688  pathN = makeLBPlot( xvec, xvecStb, yvecN, 'Luminosity block number', 'Number of events / LB', '',
1689  'nev_vs_lb_str_%s_run_%i' % (streamName, run.runNr),
1690  'N events per LB in stream "%s", run %i' % (streamName, run.runNr),
1691  QC.datapath, 'Total number of events: %i' % nevtot )
1692  pathR = makeLBPlot( xvec, xvecStb, yvecR, 'Luminosity block numer', 'Event rate [Hz] / LB', '',
1693  'rate_vs_lb_str_%s_run_%i' % (streamName, run.runNr),
1694  'Event rate per LB in stream "%s", run %i' % (streamName, run.runNr),
1695  QC.datapath )
1696  wincontent += '<table style="padding: 0px">\n<tr><td>'
1697  wincontent += '<img src="%s" width="350">' % pathN.split('/')[-1]
1698  wincontent += '</td><td>'
1699  wincontent += '<img src="%s" width="350">' % pathR.split('/')[-1]
1700  wincontent += '</td></tr></table>\n'
1701  wincontent += '<hr color="black" size=1>\n'
1702  wincontent += '<table class="lb">\n'
1703  wincontent += '<tr><th>LB</th><th>Start time (%s)</th><th>Duration (sec)</th><th>Nevents</th><th>Cumul. Nevents</th><th>Rate [Hz]</th>' % QC.tzdesc()
1704  if hasStableBeamsInfo:
1705  wincontent += '<th>Stable beams</th>'
1706  wincontent += '</tr>\n<tr style="background:%s">' % '#eeeeee'
1707  sumnev = 0
1708  for idx,(lbtime,lbendtime) in enumerate(run.lbtimes):
1709  lb=idx+1
1710  nev = 0
1711  if lb in ev:
1712  nev = ev[lb]
1713  sumnev += nev
1714  stbBeams = '&minus;'
1715  if yvecR[idx] > 0:
1716  averate += yvecR[idx]
1717  if yvecR[idx] > maxrate:
1718  maxrate = yvecR[idx]
1719  nc += 1
1720  if lb in xvecStb:
1721  stbBeams = 'T'
1722 
1723  timetuple = time.localtime(lbtime/1.E9) if QC.localtime else time.gmtime(lbtime/1.E9)
1724  wincontent += '<td>%s</td><td>%s</td><td>%.2f</td><td>%i</td><td>%i</td><td>%.3g</td>' % (lb, time.strftime("%X",timetuple), (float(lbendtime)-float(lbtime))/1.E9, int(yvecN[idx]), sumnev, yvecR[idx])
1725  if hasStableBeamsInfo:
1726  wincontent += '<td>%s</td>' % stbBeams
1727  if idx%2!=0:
1728  col = '#eeeeee'
1729  else:
1730  col = '#ffffff'
1731  wincontent += '</tr>\n<tr style="background:%s">' % col
1732 
1733  # compute max and averages
1734  if nc>0:
1735  averate /= float(nc)
1736 
1737  if run.runNr == Run.runnropen: # run still ongoing
1738  wincontent += '<tr><td style="text-align:left"colspan="3"><i>&nbsp;&nbsp;Run still ongoing ...</i></td></tr>\n'
1739  wincontent += '</tr></table>\n'
1740  wincontent += '<hr color="red" size=1><font color="#777777"><font size="-1"><i><font size="-2">Created by AtlRunQuery on: %s</font></i></font></td></tr></table><script type="text/javascript"></script></body></html>' % str(datetime.datetime.now())
1741  wincontent += '</td></tr></table>'
1742  else:
1743  wincontent = ""
1744 
1745  # the output
1746  tooltipkey = "STROV_%i_%s" % (run.runNr, streamName)
1747 
1748  physStrOnlyInfo = ""
1749  if isPhysicsStream:
1750  maxrate = 'max:&nbsp;%.2f&nbsp;Hz' % (maxrate)
1751  averate = 'ave:&nbsp;%.2f&nbsp;Hz' % (averate)
1752  physStrOnlyInfo = "%s,<br>%s,<br>%s,&nbsp;" % (maxrate, averate, fracstr)
1753  debugStrLink = ""
1754  if 'debug_' in k:
1755  debugStrLink = '&nbsp;<a href="https://trigmon.web.cern.ch/trigmon/ResultsAnalysis/RESULTS/%i/00%i_%s" target=_blank><font color="#993333">[MON]</font></a>' % (time.gmtime(run.sor/1.E9)[0], run.runNr, k[4:].strip())
1756  evtsize = ',<br>%s/evt' % filesize(float(strsize)/float(strevents)) if (strevents>0) else ""
1757  tdcontent = '%s <BR><font size="-2">(%s%s/run%s%s)' % (addKommaToNumber(strevents), physStrOnlyInfo, filesize(strsize), evtsize, debugStrLink)
1758 
1759  # wrap content in div with tooltip
1760  tdcontent = '<div class="showTip %s stream" style="display:inline;cursor:pointer">%s</div>' % (tooltipkey, tdcontent)
1761 
1762  if isPhysicsStream:
1763  # create popup page and wrap content into href
1764  filename = HU.CreatePopupHtmlPage( 'streamov_%i_%s' % (run.runNr, streamName), HU.WrapIntoHTML(wincontent, title="%s Stream Content" % streamName) )
1765  tdcontent = '<a class="externalWindow" style="text-decoration:none" href="%s">%s</a>' % (filename, tdcontent)
1766 
1767  s += '<td style="text-decoration:none">%s</td>' % (tdcontent)
1768 
1769  continue
1770 
1771  # -----------------------------------------------------------------------------------------------------------------------
1772 
1773  if k=="TriggerMenu":
1774  chains = run.splitTriggerChains(v)
1775  if len(chains)==0:
1776  s += '<td></td>'
1777  elif len(chains)==1:
1778  s += '<td style="min-width:300px"><font size="-2">%s</font></td>' % ( chains )
1779  elif len(chains)==2:
1780  s += '<td style="min-width:300px"><font size="-2">%s<hr color="gray" size=1>%s</font></td>' % ( chains )
1781  else:
1782  s += '<td style="min-width:300px"><font size="-2">%s<hr color="gray" size=1>%s<hr color="gray" size=1>%s</font></td>' % ( chains )
1783  continue
1784 
1785  # -----------------------------------------------------------------------------------------------------------------------
1786 
1787  if k=="TriggerRates":
1788  if type(v)==str:
1789  s += '<td>%s</td>'%v
1790  else:
1791  tablecontent = ""
1792  triggergroups,imgpaths,openwincmds = HU.createRatePopupWindow(v,run)
1793  for idx,(trgroup,imgpath,openwincmd) in enumerate(zip(triggergroups,imgpaths,openwincmds)):
1794  tooltipkey = "TrRate_Set%i_%i" % (idx,run.runNr)
1795  contentpage = "%s/popupContent_trRates_%i_%i.html" % (QC.datapath, run.runNr, idx)
1796 
1797  if idx!=0:
1798  tablecontent += ' <tr><td colspan="2"><hr color="gray"></td></tr>'
1799  imgcontent = '<img src="%s" align="center" width="90px"><br>' % imgpath
1800  imagerow = '<div class="showTip %s ratespopup" id="%s" style="display:inline;cursor:pointer;font-size:80%%;">%s</div>' % (tooltipkey, contentpage, imgcontent)
1801  tablecontent += ' <tr><td colspan="2" >%s</td></tr>' % imagerow
1802  for tr,avr in trgroup:
1803  tablecontent += ' <tr><td>%s</td><td>: %3.1f Hz</td></tr>' % (tr,avr)
1804  s+="<td><table class='ratestable'>\n%s\n </table></td>" % tablecontent
1805  continue
1806 
1807  # -----------------------------------------------------------------------------------------------------------------------
1808 
1809  if "Datasets" == k:
1810  # separate datasets into stream types
1811  streamtypes = ['physics_','express_','calibration_','debug_', 'debugrec_']
1812  steptypes = ['.daq.','.recon.','.merge.','other','Reproc' ]
1813  datatypes = ['.RAW','.DRAW','.ESD.','.DESD','.AOD.','.TAG.','.TAG_COMM.','.HIST.','.NTUP','other']
1814  vetotypes = ['_TMP']
1815  shownlist = []
1816 
1817  s += '<td>'
1818  s += '<table class="datasettable">'
1819  hrline = ''
1820  allcafdsnames = ''
1821  first = True
1822  for stype in streamtypes:
1823  for step in steptypes:
1824  for dtype in datatypes:
1825  selectedds = {}
1826  for ds in v:
1827  if (stype in ds[0] and step in ds[0] and dtype in ds[0]) or (stype in ds[0] and stype == 'debug_' and step == 'other' and (dtype in ds[0] or dtype == 'other')) and not ds[0] in shownlist:
1828  vetoed = False
1829  for veto in vetotypes:
1830  if veto in ds[0]:
1831  vetoed = True
1832  break
1833  if not vetoed:
1834  # number of files, size, events
1835  st = ['&nbsp;%s&nbsp;files' % (prettyNumber(ds[4]))]
1836  st += ['&nbsp;%s' % (filesize(ds[5]))]
1837  if ds[6] == 0:
1838  st += ['&nbsp;unkn.&nbsp;evts&nbsp;']
1839  else:
1840  st += ['&nbsp;%s&nbsp;evts&nbsp;' % (prettyNumber(ds[6]))]
1841  selectedds[ds[0]] = st
1842  # replication status
1843  if 'replicate:done' in ds[2]:
1844  selectedds[ds[0]] += [True]
1845  else:
1846  selectedds[ds[0]] += [False]
1847  if ds[3] == 'DONE':
1848  selectedds[ds[0]] += [True]
1849  else:
1850  selectedds[ds[0]] += [False]
1851  selectedds[ds[0]] += [ds[7]] # add dataset creation time
1852  shownlist.append(ds[0])
1853 
1854  if not selectedds:
1855  continue
1856  dsnames = selectedds.keys()
1857  dsnames.sort()
1858  if not first:
1859  s += hrline
1860  first = False
1861  s += '<tr><td colspan="1"><font color="#666666"><i>[&nbsp;Stream&nbsp;type&nbsp;+&nbsp;processing&nbsp;step&nbsp;+&nbsp;data&nbsp;type:&nbsp;<b>%s</b>&nbsp;+&nbsp;<b>%s</b>&nbsp;+&nbsp;<b>%s</b>&nbsp;]</i> </font></td></tr>' % (stype, step, dtype)
1862  for dsname in dsnames:
1863  # build AMI link to dataset
1864  dsnspl = dsname.split('.')
1865  lk = "https://ami.in2p3.fr/AMI/servlet/net.hep.atlas.Database.Bookkeeping.AMI.Servlet.Command?Converter=/AMIXmlToAMIProdHtml.xsl&Command=FormBrowseDatasetPerParameter+-runNumber%3D"
1866  project = dsnspl[0]
1867  runNum = dsnspl[1]
1868  stream = dsnspl[2]
1869  format = dsnspl[4]
1870  s += '<tr><td>'
1871  s += '<a href="https://ami.in2p3.fr/AMI/servlet/net.hep.atlas.Database.Bookkeeping.AMI.Servlet.Command?Converter=/AMIXmlToAMIProdHtml.xsl&Command=FormBrowseDatasetPerParameter+-runNumber%3D'
1872  s += runNum + "+-dataType=" + format + "+-projectName=" + project + "+-streamName=" + stream
1873  s += '" target="_blank" title="AMI dataset information">'
1874  s += dsname + '</td>'
1875  res = selectedds[dsname]
1876  s += '<td style="text-align:right"><font color="#005500">&nbsp;[</font></td>'
1877  for st in res[0:3]:
1878  s += '<td style="text-align:right"><font color="#005500">%s</font></td>' % st
1879  s += '<td style="text-align:right"><font color="#005500">]</font></td>'
1880  if res[3]:
1881  if Run.showCAFLinks:
1882  s += '<td><a href="javascript:openPageWindow('
1883  s += "'data/%s.html','%s')" % (dsname,dsname)
1884  s += '"title="Check which files of this dataset are available on ATLCAL disk pool">'
1885  s += '<font color="#BB0517">&nbsp;[&nbsp;on&nbsp;CAF&nbsp;]</font></a></td>'
1886 
1887  # get age of file in hours
1888  deltat = (datetime.datetime.utcnow() - res[5])
1889  deltat = deltat.days*24.*3600. + deltat.seconds
1890  allcafdsnames += dsname + '@' + '%g' % deltat + ','
1891  else:
1892  s +='<td><font color="#BB0517">&nbsp;[&nbsp;on&nbsp;CAF&nbsp;]</font></td>'
1893  else:
1894  s += '<td></td>'
1895  if res[4]:
1896  lk = '<a href="https://ami.in2p3.fr/AMI/servlet/net.hep.atlas.Database.Bookkeeping.AMI.Servlet.Command?Command=FormGetDQ2InfoPerDataset+-logicalDatasetName%3D%22' + dsname + '%22&Converter=%2FAMIXmlToProdFrameHtml.xsl" target="_blank" title="DQ2 information (via AMI) for dataset: ' + dsname + '">'
1897  s += '<td>%s<font color="#153EBB">&nbsp;[&nbsp;in&nbsp;DDM&nbsp;]</font></a></td>' % lk
1898  else:
1899  s += '<td></td>'
1900 
1901  s += '</tr>'
1902  if dtype != datatypes[-1]:
1903  hrline = '<tr><td colspan="8"><hr style="width:100%; background-color: #BBBBBB; height:1px; margin-left:0; border:0"/></td>'
1904  else:
1905  hrline = ''
1906 
1907  if step != steptypes[-1]:
1908  hrline = '<tr><td colspan="8"><hr style="width:100%; background-color: #666666; height:2px; margin-left:0; border:0"/></td>'
1909  if stype != streamtypes[-1]:
1910  hrline = '<tr><td colspan="8"><hr style="width:100%; background-color: #6D7B8D; height:3px; margin-left:0; border:0"/></td>'
1911  # sanity check
1912  s_ = ''
1913  for ds in v:
1914  if 'TMP.' not in ds[0] and ds[0] not in shownlist:
1915  s_ += '<tr><td colspan=8>' + ds[0] + '</td></tr>'
1916  if s_:
1917  s += '<tr><td colspan="8"><hr style="width:100%; background-color: #EE0000; height:3px; margin-left:0; border:0"/></td>'
1918  s += '<tr><td colspan=8><font color="#EE0000"><i>Remaining, unassigned datasets:</i></font></td></tr>'
1919  s += s_
1920 
1921  # close table
1922  s += '</table>\n'
1923  s += '</td>'
1924 
1925  # call subprocesses
1926  if allcafdsnames:
1927  subprocess.Popen('python subproc.py caf %s' % (allcafdsnames[:-1]), shell=True)
1928 
1929  continue
1930 
1931  # -----------------------------------------------------------------------------------------------------------------------
1932 
1933  if 'HLT PSK' == k:
1934  # add another column with links to trigger menu for all SMK and PSKs combinations
1935  linklist = run.stats['PSK']['blocks']
1936  linkRun12 = (
1937  '<a href="https://atlas-trigconf.cern.ch/run/smkey/{smk}/l1key/{l1psk}/hltkey/{hltpsk}/" target="_blank" '
1938  'title="L1: \'{l1name}\', HLT \'{hltname}\'. '
1939  'You can obtain the full trigger menu corresponding to SMK={smk} and prescale keys L1={l1psk}, HLT={hltpsk} in an independent window"'
1940  '>{l1psk}&nbsp;|&nbsp;{hltpsk}</a>'
1941  )
1942  linkRun3L1 = (
1943  '<a href="https://atlas-triggertool.web.cern.ch/db/{db}/smk/{smk}/l1psk/{l1psk}/" target="_blank" '
1944  'title="L1: \'{l1name}\'. You can obtain the full trigger menu corresponding to SMK={smk} and L1 prescale key {l1psk} in an independent window"'
1945  '>{l1psk}</a>'
1946  )
1947  linkRun3HLT = (
1948  '<a href="https://atlas-triggertool.web.cern.ch/db/{db}/smk/{smk}/hltpsk/{hltpsk}/" target="_blank" '
1949  'title="HLT: \'{hltname}\'. You can obtain the full trigger menu corresponding to SMK={smk} and HLT prescale key {l1psk} in an independent window"'
1950  '>{hltpsk}</a>'
1951  )
1952  if linklist:
1953  if len(linklist)<=15:
1954  ncol = 1
1955  elif len(linklist)<=30:
1956  ncol = 2
1957  else:
1958  ncol = 3
1959  if len(linklist)<=15:
1960  nrow = len(linklist)
1961  elif len(linklist)<=45:
1962  nrow = 15
1963  else:
1964  nrow = (len(linklist)+2)//3
1965 
1966  s += '<td align="center"><table class="triggerlinktable" align="center">'
1967  s += '<tr>'
1968  for x in range(ncol):
1969  s += '<td style="text-align:center;font-weight:bold" colspan="3">LB&nbsp;range</td><td style="text-align:center;font-weight:bold">L1&nbsp;&nbsp;&nbsp;HLT</td>'
1970  s += '</tr>'
1971 
1972  for row in range(nrow):
1973  s += '<tr>'
1974  for col in range(ncol):
1975  entry = row + col*nrow
1976  if entry>=len(linklist):
1977  continue
1978  link = dict(zip( ("startlb", "endlb", "l1psk", "hltpsk", "l1name", "hltname"),linklist[entry]))
1979  link.update({
1980  "smk" : run.result["SMK"],
1981  "db" : "dev1_i8" if int(run.result["SMK"]) < 3000 else "run3"
1982  })
1983  s += f'<td style="padding-left: 0.8em">{link["startlb"]}</td><td>&minus;</td><td>{link["endlb"]}:&nbsp;</td>'
1984  if run.lhcRun < 3:
1985  cellContent = linkRun12.format(**link)
1986  else:
1987  cellContent = linkRun3L1.format(**link) + "&nbsp;|&nbsp;" + linkRun3HLT.format(**link)
1988  s += f'<td style="border-right: 1px solid gray; padding-right: 0.8em">{cellContent}</td>'
1989  s += '</tr>'
1990  s += '</table>'
1991  s += '<hr style="width:100%; background-color: #AAAABB; height:1px; margin-left:0; border:0"/>'
1992  s += '<a href="https://atlas-trigconf.cern.ch/psevo/%i/" target="_blank" title="Obtain prescale evolution for all L1/L2/EF chains of this run in independent window"><font size="-2"><i>Prescale&nbsp;evolution...</i></font></a>' % run.runNr
1993  s+='</td>'
1994  else:
1995  s += '<td style="text-align:center">n.a.</td>'
1996  continue
1997 
1998  # -----------------------------------------------------------------------------------------------------------------------
1999 
2000  if 'BGS Key' == k:
2001  if v!='n.a.':
2002  smk = int(run.result["SMK"])
2003  bgskOffset = 10000 if (smk<3000 and run.lhcRun==3) else 0
2004 
2005  if len(run.stats['BGS Key' ]['blocks'])>0:
2006  s += '<td align="center"><table class="triggerlinktable" align="center"><tr><td style="text-align:left;font-weight:bold" colspan="3">LB&nbsp;range</td><td style="text-align:right;font-weight:bold">BGS</td></tr>'
2007  for bgskey, lbbeg, lbend in run.stats['BGS Key' ]['blocks']:
2008  s += '<tr><td style="text-align:right">%i</td><td style="text-align:right">&minus;</td><td style="text-align:right">%i:&nbsp;</td>' % (lbbeg, lbend-1)
2009  cellContent = (
2010  f'&nbsp;<a href="https://atlas-trigconf.cern.ch/bunchgroups?key={bgskey+bgskOffset}" target="_blank" '
2011  f'title="Obtain bunch group description for BGS Key={bgskey} in independent window"'
2012  f'>{bgskey}</a>'
2013  )
2014  s += f'<td>{cellContent}</td></tr>'
2015  s += '</table>'
2016  s+='</td>'
2017  else:
2018  s += '<td style="text-align:center">n.a.</td>'
2019  else:
2020  s += '<td class="tdna">n.a.</td>'
2021  continue
2022 
2023  # -----------------------------------------------------------------------------------------------------------------------
2024 
2025  if "SMK" == k:
2026  if v=='n.a.':
2027  s += '<td class="tdna">n.a.</td>'
2028  else:
2029  namecomment = '<div style="font-size:80%%;color:#488AC7"><b>%s</b> (v.%i)</div><div style="width:200px;font-size:60%%;color:#777777;text-align:left">%s</div>' % run.stats['SMK']['info']
2030  s += '<td style="text-align: center;">%s<br>%s</td>' % (v,namecomment)
2031  continue
2032 
2033  # -----------------------------------------------------------------------------------------------------------------------
2034 
2035  if 'lar:runtype' in k or 'lar:format' in k:
2036  info = LArConfig(k.replace('lar:',''))
2037  try:
2038  s += '<td style="text-align: center">%s<br><font size="-2">(%s)</font></td>' % (v,info[int(v)])
2039  except ValueError:
2040  if v=='n.a.':
2041  s += '<td class="tdna">n.a.</td>'
2042  else:
2043  s += '<td style="text-align: right">%s</td>' % v
2044  continue
2045 
2046  # -----------------------------------------------------------------------------------------------------------------------
2047 
2048  if 'BPM' == k:
2049 
2050  # compute average and RMS BPMs
2051  fullprint = '<table class="triggerlinktable" align="center">'
2052  keys = v.keys()
2053  keys.sort()
2054 
2055  # time results
2056  xvec = []
2057  yvec = []
2058  toffset = int(run.sor/1.E9)
2059  deltat = int(run.eor/1.E9) - int(run.sor/1.E9)
2060 
2061  # LB axis
2062  xveclb = []
2063  for idx,(lbtime,lbendtime) in enumerate(run.lbtimes):
2064  lb=idx+1
2065  xveclb.append( [lbtime/1.E9-toffset, (float(lbendtime)-float(lbtime))/1.E9] )
2066 
2067  ymin = +1e30
2068  ymax = -1e30
2069  legend = []
2070  for ik,key in enumerate(keys):
2071  y = 0
2072  y2 = 0
2073  xvec.append([])
2074  yvec.append([])
2075  for (val,dte) in v[key]:
2076  y += val
2077  y2 += val*val
2078 
2079  ts = time.strptime( dte[:dte.rfind(':')] + '/UTC','%d-%m-%Y %H:%M:%S/%Z' )
2080  tsec = int(calendar.timegm(ts))
2081  xvec[-1].append(tsec - toffset) # time defined with respect to offset
2082  yvec[-1].append(val)
2083 
2084  ic = len(v[key])
2085  if ic > 0:
2086  y /= float(ic)
2087  arg = y2/float(ic) - y*y
2088  if arg > 0:
2089  y2 = math.sqrt(arg)
2090  else:
2091  y2 = 0
2092  ymin = min(ymin,y - 1.5*y2)
2093  ymax = max(ymax,y + 1.5*y2)
2094 
2095  # fill table
2096  vname = 'unknown'
2097  if 'B1' in key and 'hori' in key:
2098  vname = 'B1&nbsp;horiz.&nbsp;IP'
2099  lname = 'B1 horizont IP pos.'
2100  elif 'B1' in key and 'vert' in key:
2101  vname = 'B1&nbsp;vert.&nbsp;IP'
2102  lname = 'B1 vertical IP pos.'
2103  elif 'B2' in key and 'hori' in key:
2104  vname = 'B2&nbsp;horiz.&nbsp;IP'
2105  lname = 'B2 horizontal IP pos.'
2106  elif 'B2' in key and 'vert' in key:
2107  vname = 'B2&nbsp;vert.&nbsp;IP'
2108  lname = 'B2 vertical IP pos.'
2109  legend.append( lname )
2110  fullprint += '<tr><td style="text-align:left">%s:&nbsp;</td><td>(</td><td style="text-align:right">&nbsp;%s</td><td style="text-align:left">&nbsp;&#177;&nbsp;</td><td style="text-align:left">%.4g</td><td>)&nbsp;um</td><td>&nbsp;&nbsp;&nbsp;</td>' % (vname, ('%.4g' % y).replace('-','&minus;'), y2)
2111 
2112  if ik == 0:
2113  fullprint += '<td rowspan="4">REPLACEME</td>'
2114  fullprint += '</tr>'
2115 
2116  # write to file (as text and TGraphs)
2117  bpmrootfilename = QC.datapath + '/bpm_output_run%i.root' % run.runNr
2118  SaveGraphsToFile( bpmrootfilename, keys, xvec, yvec, "TimeOffset", toffset )
2119 
2120  bpmtextfilename = QC.datapath + '/bpm_output_run%i.txt' % run.runNr
2121  bpmout = open( bpmtextfilename, 'w' )
2122 
2123  bpmout.write( '# BPM Output for run %i\n' % run.runNr )
2124  bpmout.write( '# Start - end of run: %s [UTC]\n' % run.timestr('txt') )
2125  bpmout.write( '# Time offset applied below in seconds: %i\n' % int(toffset) )
2126  bpmout.write( '#\n' )
2127  bpmout.write( '# ---------------------------------------------------------------------------------\n' )
2128  for ik,key in enumerate(keys):
2129  bpmout.write( '# Output for variable: "%s"\n' % key )
2130  bpmout.write( '# Format: index / timestamp (seconds) wrt. begin of run / BPM position in microns\n' )
2131  bpmout.write( '#\n' )
2132  for i in range(len(xvec[ik])):
2133  bpmout.write( "%4i %9.2f %14.6f\n" % (i, xvec[ik][i], yvec[ik][i]) )
2134  bpmout.write( '#\n' )
2135  bpmout.write( '# ---------------------------------------------------------------------------------\n' )
2136  bpmout.close()
2137 
2138  fullprint += '<tr><td colspan=8><hr style="width:100%; background-color:#999999; height:1px; margin-left:0; border:0"/></td></tr>'
2139  fullprint += '<tr><td colspan=8 style="text-align:left"><a href="%s" target="_blank" title="Tabulated BPM information versus time for run %i"><i>Click here for tabulated BPM values versus time...</i></a></td></tr>' % (bpmtextfilename, run.runNr)
2140  fullprint += '<tr><td colspan=8 style="text-align:left"><a href="%s" target="_blank" title="BPM information versus time for run %i as four TGraph objects in ROOT file"><i>Right-click to download ROOT file with TGraphs...</i></a></td></tr>' % (bpmrootfilename, run.runNr)
2141  fullprint += '</table>'
2142 
2143  # make plot
2144  path = makeTimePlotList( xvec, xveclb, yvec, toffset, deltat, ymin, ymax,
2145  'Time of day (UTC)', 'Beam position (microns)', legend,
2146  'bp_vs_time_run_%i' % (run.runNr),
2147  'Beam position versus time of day for run %i' % (run.runNr),
2148  QC.datapath, '' )
2149 
2150  replacetxt = '<img src="%s" align="left" width="70px">' % path
2151  fullprint = fullprint.replace('REPLACEME',replacetxt)
2152 
2153  # create window and tooltip
2154  wincontent = '<table class=&quot;outer&quot; style=&quot;padding: 5px&quot;><tr><td>'
2155  wincontent += '<strong><b>LHC beam positions at IP verssu time for run %i:</b></strong><br><font size=&quot;-1&quot;><font color=&quot;#888888&quot;>(Begin/end of run: %s)</font></font><hr color=&quot;black&quot; size=1>' % (run.runNr, run.timestr('html', run.runNr != Run.runnropen))
2156  wincontent += '<table style=&quot;padding: 0px&quot;><tr><td>'
2157  wincontent += '<img src=&quot;%s&quot; align=&quot;left&quot;></td>' % path
2158  wincontent += '</td></tr></table>'
2159  wincontent += """<hr color=&quot;red&quot; size=1><font color=&quot;#777777&quot;><font size=&quot;-1&quot;><i><font size=&quot;-2&quot;>Created by AtlRunQuery on: %s</font></i></font></td></tr></table><script type=&quot;text/javascript&quot;></script></body></html>""" % str(datetime.datetime.now())
2160  wincontent += '</td></tr></table>'
2161 
2162 
2163  openwincmd = HU.OpenWindow(wincontent,title="Summary of LHC information")
2164 
2165  # put into html page
2166  s += '<td style="text-decoration:none">%s<div class="showTip BPM stream" style="display:inline;cursor:pointer">%s</div></a></td>' % (tooltipkey, fullprint)
2167  continue
2168 
2169  # -----------------------------------------------------------------------------------------------------------------------
2170 
2171  if 'ofllumi:' in k:
2172 
2173  if ofllumiFlag:
2174  continue
2175  ofllumiFlag = True
2176 
2177  # find range with stable beams (requires LHC information to be available)
2178  hasStableBeamsInfo, xvecStb = run.getStableBeamsVector()
2179 
2180  # find all channels that should be printed
2181  kref = []
2182  chans = []
2183  tags = []
2184  for kp in Run.ShowOrder:
2185  if 'ofllumi:' in kp.ResultKey:
2186  name, chanstr, tagstr = kp.ResultKey.split(':')
2187  kref.append(kp)
2188  chans.append(chanstr)
2189  tags.append(tagstr)
2190 
2191  # get the channel names
2192  chanstr = []
2193  for ch in chans:
2194  ich = int(ch)
2195  if ich in OLCAlgorithms:
2196  chanstr.append(OLCAlgorithms[ich])
2197  else:
2198  chanstr.append('Unknown')
2199 
2200  # insert events per LB
2201  xvec = []
2202  yvec = []
2203  peaklumi = []
2204  intlumi = []
2205  intlumiStb = []
2206  for ikp,kp in enumerate(kref):
2207  yvec.append([])
2208  peaklumi.append(-1)
2209  intlumi.append(0)
2210  intlumiStb.append(0)
2211  for entry in run.data[kp]:
2212  if entry.startlb == 0:
2213  continue
2214  val = entry.value if entry.value!='n.a.' and entry.value>0 else 0
2215  lastlb = min(entry.lastlb,run.lastlb)
2216  lbs = range(entry.startlb,lastlb+1)
2217  if ikp == 0:
2218  xvec += lbs
2219  yvec[-1] += len(lbs)*[float(val)]
2220 
2221 
2222  for idx,(lbtime,lbendtime) in enumerate(run.lbtimes):
2223  lb=idx+1
2224  dt = (float(lbendtime)-float(lbtime))/1.E9
2225  for ich in range(len(chans)):
2226  tmp = yvec[ich]
2227  intlumi[ich] += tmp[idx]*dt/1000.0 # unit of yvec was: ub-1 s-1 -> nb-1
2228  if lb in xvecStb:
2229  intlumiStb[ich] += yvec[ich][idx]*dt/1000.0
2230 
2231  yvec[ich][idx] *= 1.0 # unit of yvec was: ub-1 s-1, transform to: 10^30 cm-2s-1
2232  if yvec[ich][idx] > peaklumi[ich]:
2233  peaklumi[ich] = yvec[ich][idx]
2234 
2235  # line to be printed in column
2236  fullprint_ = ''
2237  if hasStableBeamsInfo:
2238  for ich,ch in enumerate(chans):
2239  fullprint_ += 'Integrated&nbsp;(channel:&nbsp;%s):&nbsp;%0.4g<br>Stable&nbsp;B:&nbsp;%0.4g<br>' % (ch,intlumi[ich],intlumiStb[ich])
2240  histoText = 'Integr. lumi (channel: %i): %.4g nb-1 (all LBs) and %.4g nb-1 (stable beams)' % (0, intlumi[0],intlumiStb[0])
2241  else:
2242  for ich,ch in enumerate(chans):
2243  fullprint_ += 'Integrated&nbsp;(channel:&nbsp;%s):&nbsp;%0.4g<br>' % (ch,intlumi[ich])
2244  histoText = 'Integr. lumi (channel: %i): %.4g nb-1 (all LBs)' % (0, intlumi[0])
2245 
2246  # make plot
2247  path = makeLBPlotList( xvec, xvecStb, yvec,
2248  'Luminosity block number', 'Offline luminosity (10^{30}cm^{-2}s^{-1})', chanstr,
2249  'ofllumi%s_vs_lb_run_%i' % (chans[0],run.runNr),
2250  'Offline lumi per LB for run %i' % (run.runNr),
2251  QC.datapath, histoText )
2252 
2253  # create window and tooltip
2254  wincontent = '<table class=&quot;outer&quot; style=&quot;padding: 5px&quot;><tr><td>'
2255  wincontent += '<strong><b>Offline luminosity per LB for run %i:</b></strong><br><font size=&quot;-1&quot; color=&quot;#888888&quot;>(Begin/end of run: %s)</font>' % (run.runNr, run.timestr('html', run.runNr != Run.runnropen))
2256  wincontent += '<hr color=&quot;black&quot; size=1>'
2257  wincontent += '<table style=&quot;padding: 0px&quot;><tr><td>'
2258  wincontent += '<img src=&quot;%s&quot; align=&quot;left&quot;>' % path
2259  wincontent += '</td></tr></table>'
2260  wincontent += '<hr color=&quot;black&quot; size=1>'
2261  wincontent += '<table class=&quot;LB&quot;>'
2262  wincontent += '<tr><th>LB</th><th>Start time<br> (%s)</th><th>Duration<br>(sec)</th>' % QC.tzdesc()
2263  for ch in chanstr:
2264  wincontent += '<th>Inst. luminosity<br>(1e%s&nbsp;cm<sup>&minus;2</sup>s<sup>&minus;1</sup>)<br>[ %s ]</th>' % (run.instlumiunittxt,ch)
2265  wincontent += '<th>Stable beams</th>'
2266  wincontent += '</tr><tr style=&quot;background:%s&quot;>' % '#eeeeee'
2267  for idx,(lbtime,lbendtime) in enumerate(run.lbtimes):
2268  lb=idx+1
2269  stbBeams = '&minus;'
2270  if lb in xvecStb:
2271  stbBeams = 'T'
2272  timetuple = time.localtime(lbtime/1.E9) if QC.localtime else time.gmtime(lbtime/1.E9)
2273  wincontent += '<td>%i</td><td>%s</td><td>%.2f</td>' % (lb, time.strftime("%X",timetuple), (float(lbendtime)-float(lbtime))/1.E9)
2274  for ich in range(len(chans)):
2275  wincontent += '<td>%.4g</td>' % (yvec[ich][idx])
2276  wincontent += '<td>%s</td>' % stbBeams
2277  if idx%2!=0:
2278  col = '#eeeeee'
2279  else:
2280  col = '#ffffff'
2281  wincontent += '</tr><tr style=&quot;background:%s&quot;>' % col
2282  if run.runNr == Run.runnropen: # run still ongoing
2283  wincontent += '<tr><td style=&quot;text-align:left&quot;colspan=&quot;3&quot;><i>&nbsp;&nbsp;Run still ongoing ...</i></td></tr>'
2284  wincontent += '</tr></table>'
2285  wincontent += """<hr color=&quot;red&quot; size=1><font color=&quot;#777777&quot;><font size=&quot;-1&quot;><i><font size=&quot;-2&quot;>Created by AtlRunQuery on: %s</font></i></font></td></tr></table><script type=&quot;text/javascript&quot;></script></body></html>""" % str(datetime.datetime.now())
2286  wincontent += '</td></tr></table>'
2287 
2288  openwincmd = HU.OpenWindow(wincontent,title="Run query result for online luminosity")
2289 
2290  # line to be printed in column
2291  fullprint = '<table class="bcidtable">'
2292  fullprint += '<tr><td colspan="2"><img src="%s" align="left" width="90px"></td></tr>' % path
2293  if hasStableBeamsInfo:
2294  for ich in range(len(chans)):
2295  fullprint += '<tr><td style="text-align:left">Entire&nbsp;run:</td><td style="text-align:left">&nbsp;%0.4g&nbsp;%s<sup>&minus;1</sup></td></tr><tr><td style="text-align:left">Stable&nbsp;beams:</td><td style="text-align:left">&nbsp;%0.4g&nbsp;%s<sup>&minus;1</sup></td></tr><tr><td style="text-align:left">Peak&nbsp;lumi:</td><td style="text-align:left">&nbsp;%0.3g&nbsp;e%s&nbsp;cm<sup>&minus;2</sup>s<sup>&minus;1</sup></td></tr>' % (intlumi[ich], run.lumiunittxt, intlumiStb[ich], run.lumiunittxt, peaklumi[ich], run.instlumiunittxt)
2296  else:
2297  for ich in range(len(chans)):
2298  fullprint += '<td style="text-align:left">All&nbsp;LBs:</td><td style="text-align:left">&nbsp;%0.4g</td></tr>' % (intlumi[ich])
2299  fullprint += '</table>'
2300 
2301  # put into html page
2302  s += '<td class="showTip OFLLumi stream" style="text-decoration:none; text-align: right">%s%s</a></td>' % (openwincmd, fullprint)
2303  continue
2304 
2305  # -----------------------------------------------------------------------------------------------------------------------
2306 
2307  if any( [ ('lhc:' in k and 'beamenergy' not in k),
2308  ('TorCurrent' in k),
2309  ('SolCurrent' in k),
2310  ('bs:' in k),
2311  ('Ready for physics' in k),
2312  ] ):
2313  res = []
2314  keys = []
2315 
2316  # search unique ranges
2317  for entry in run.data[k]:
2318  if entry.startlb == 0:
2319  continue
2320  val = entry.value
2321 
2322  try:
2323  val = float(val)
2324  if 'bs:' not in k and 'ofllumi:' not in k and 'beam1intensity' not in k and 'beam2intensity' not in k:
2325  val = round(val) # no floating points, unless it is 'bs'
2326  except ValueError:
2327  pass
2328 
2329  # special treatment for E-beam = 7864
2330  if 'beamenergy' in k and val>=7864:
2331  val = 'ASYNC'
2332 
2333  if not keys or res[-1] != val:
2334  if keys:
2335  keys[-1][1] = entry.startlb
2336  res.append ( val )
2337  keys.append( [entry.startlb, entry.endlb] )
2338  elif res[-1] == val:
2339  keys[-1][1] = entry.endlb
2340 
2341 
2342  if len(keys) > 1:
2343  s += '<td><table class="triggerlinktable" align="center">'
2344  for i, c in enumerate(keys):
2345  if int(c[0]) != int(c[1])-1:
2346  s += '<tr><td>LB&nbsp;</td><td style="text-align:right">%i</td><td style="text-align:right">&minus;</td><td style="text-align:right">%i:&nbsp;</td>' % (int(c[0]),int(c[1])-1)
2347  else:
2348  s += '<tr><td>LB&nbsp;</td><td style="text-align:right">%i</td><td style="text-align:right"></td><td style="text-align:right">:&nbsp;</td>' % (int(c[0]))
2349  try:
2350  val = float(res[i])
2351  if 'bs:' in k or 'beam1intensity' in k or 'beam2intensity' in k:
2352  vt = '%.4g' % abs(val)
2353  if val < 0:
2354  vt = '&minus;' + vt
2355  if 'e-' in vt:
2356  vt = vt.replace('e-','e&minus;')
2357  s += '<td style="text-align:right">%s</td></tr>' % vt
2358  elif 'ofllumi:' in k:
2359  s += '<td style="text-align:right">%g</td></tr>' % val
2360  else:
2361  s += '<td style="text-align:right">%i</td></tr>' % round(val)
2362  except ValueError:
2363  s += '<td style="text-align:left">%s</td></tr>' % res[i].strip()
2364  s += '</table></td>'
2365 
2366  else:
2367  try:
2368  if 'bs:' in k:
2369  vt = '%.4g' % abs(float(v))
2370  if float(v) < 0:
2371  v = '&minus;' + vt
2372  else:
2373  v = vt
2374  if 'e-' in v:
2375  v = v.replace('e-','e&minus;')
2376  else:
2377  v = round(float(v))
2378  if 'beamenergy' in k and v >= 7864:
2379  v = 'ASYNC'
2380  else:
2381  v = '%i' % v
2382  except ValueError:
2383  pass
2384  s += '<td style="text-align:center;font-size: 85%%">%s</td>' % v
2385 
2386 
2387  if ('lhc:stablebeams' in k and 'lhc:beamenergy' in Run.ShowOrder and 'lhc:beammode' not in Run.ShowOrder) or 'lhc:beammode' in k:
2388  imgpath, xvec, yvec, ymax = HU.makeSummaryPlotForLHC(run)
2389  wincontent = HU.makeSummaryPageForLHC(run, yvec, imgpath)
2390  openwincmd = HU.OpenWindow(wincontent, 'Summary of LHC information')
2391  fullprint = '<table class="bcidtable">'
2392  fullprint += '<tr><td><img src="%s" align="left" width="90px"></td></tr>' % imgpath
2393  fullprint += '<tr><td style="text-align:left">Maximum&nbsp;intensities:<br>Beam&nbsp;1:&nbsp;%0.3g&nbsp;e11&nbsp;protons<br>Beam&nbsp;2:&nbsp;%0.3g&nbsp;e11&nbsp;protons</td></tr>' % (ymax[0], ymax[1])
2394  fullprint += '<tr><td style="text-align:left">Maximum&nbsp;beam&nbsp;energy:<br>%i&nbsp;GeV</td></tr>' % int(ymax[2])
2395  fullprint += '</table>'
2396  fullprint += '<span style="font-size: xx-small; color: #555555">[ <i>Numbers given for stable beam period (if applies)</i> ]</span>'
2397  # put into html page
2398  s += '<td class="showTip LHCSummary stream" style="text-decoration:none; text-align: left">%s %s </a></td>' % (openwincmd, fullprint)
2399 
2400  continue
2401 
2402  # -----------------------------------------------------------------------------------------------------------------------
2403 
2404  # all others
2405  if v=='n.a.':
2406  s += '<td class="tdna">n.a.</td>'
2407  else:
2408  s += '<td style="text-align: right">%s</td>' % v
2409 
2410 
2411  s += "</tr>\n\n"
2412 
2413 
2416 
2417  # here we start filling the tooltips. there are quite a lot and we should be a bit smarter about them.
2418  # For instance, there is no need to define the whole table for each single box
2419 
2420  with timer("Tooltips"):
2421  createToolTips(run)
2422 
2423  return s
2424 
2425 
2426 
2428  import CoolRunQuery.html.AtlRunQueryHtmlUtils as HU
2429 
2430  HU.CreateLBTooltip(run)
2431 
2432  # DQ DEFECTS
2433  if 'DQ' in Run.ShowOrder:
2434  HU.CreateDQTooltip(run)
2435 
2436  # stream overlaps
2437  for k in [k for k in Run.ShowOrder if k.Type==DataKey.STREAM and k.ResultKey in run.stats]:
2438  HU.CreateStreamOverlapTooltip(run, k)
2439 
2440  # DQ (old)
2441  for data_key in Run.ShowOrder:
2442  k = data_key.ResultKey
2443  if not isDQ(k):
2444  continue
2445  if k not in run.stats:
2446  continue
2447  commentbox = ''
2448  for (dq,comment), start, end in run.stats[k]["blocks"]:
2449  if dq != 'n.a.':
2450  if not comment:
2451  comment = 'no comment'
2452  col = "#000000"
2453  if dq == 'R':
2454  col = "#AA0000"
2455  elif dq == 'G':
2456  col = "#006600"
2457  elif dq == 'Y':
2458  col = "#716309"
2459  if start == end-1:
2460  commentbox += '<tr style="color:%s"><td style="vertical-align:top;">LB&nbsp;</td><td style="text-align:right;vertical-align:top;">%s</td><td style="text-align:right;vertical-align:top;"></td><td style="text-align:right;vertical-align:top;">&nbsp;(%s)&nbsp;:&nbsp;</td><td style="text-align:left;vertical-align:top;"><i><strong><b>"%s"</b></strong></i></td></tr>' % (col,start,dq,comment)
2461  else:
2462  commentbox += '<tr style="color:%s"><td style="vertical-align:top;">LB&nbsp;</td><td style="text-align:right;vertical-align:top;">%s</td><td style="text-align:right;vertical-align:top;">&minus;</td><td style="text-align:right;vertical-align:top;">%s&nbsp;(%s)&nbsp;:&nbsp;</td><td style="text-align:left;vertical-align:top;"><i><strong><b>"%s"</b></strong></i></td></tr>' % (col,start,end-1,dq,comment)
2463  else:
2464  if start == end-1:
2465  commentbox += '<tr style="color:#222222"><td style="vertical-align:top;">LB&nbsp;</td><td style="text-align:right;vertical-align:top;">%s</td><td style="text-align:right;vertical-align:top;"></td><td style="text-align:right;vertical-align:top;">&nbsp;(n.a.)&nbsp;</td><td style="text-align:left;vertical-align:top;"></td></tr>' % (start)
2466  else:
2467  commentbox += '<tr style="color:#222222"><td style="vertical-align:top;">LB&nbsp;</td><td style="text-align:right;vertical-align:top;">%s</td><td style="text-align:right;vertical-align:top;">&minus;</td><td style="text-align:right;vertical-align:top;">%s&nbsp;(n.a.)&nbsp;</td><td style="text-align:left;vertical-align:top;"></td></tr>' % (start,end-1)
2468  if commentbox:
2469  sp = k.split(':')
2470  commentbox = '<strong><b>Comments&nbsp;for&nbsp;%s&nbsp;DQ&nbsp;channel&nbsp;"%s"&nbsp;in&nbsp;run&nbsp;%s:</b></strong>' % (sp[0],sp[1],run.runNr) + '<table>' + commentbox
2471  commentbox += '</table>'
2472  run.addToolTip( "dqcomm_%s_%i" % (k, run.runNr), commentbox)
2473 
2474 
2475  # trigger keys
2476  lbtrigtypes = { 'L1 PSK': ['L1&nbsp;PSK', 'L1K'], 'HLT PSK' : ['HLT&nbsp;PSK','HLTK'] }
2477  for lbtrigtype, c in lbtrigtypes.items():
2478  if lbtrigtype in Run.ShowOrder and 'blocks' in run.stats[lbtrigtype] and len(run.stats[lbtrigtype]['blocks'])>1:
2479  boxcontent = '<strong><b>%s&nbsp;evolved&nbsp;during&nbsp;run:</b></strong><br>' % c[0]
2480  boxcontent += '<table style="width: auto; border: 0px solid; border-width: margin: 0 0 0 0; 0px; border-spacing: 0px; border-collapse: separate; padding: 0px; font-size: 100%">'
2481  for item, start, stop in run.stats[lbtrigtype]['blocks']:
2482  boxcontent += '<tr><td>LB&nbsp;</td><td style="text-align:right">%s</td><td style="text-align:right">&minus;</td><td style="text-align:right">%s</td><td style="text-align:right">:&nbsp;%s</td></tr>' % (start,stop-1,item)
2483  boxcontent += '</table>'
2484  run.addToolTip("%s_%i" % (c[1], run.runNr), boxcontent)
2485 
2486 
2487  # OLC BCID
2488  if any([k for k in Run.ShowOrder if "olc:bcidmask" in k.ResultKey]):
2489  boxcontent = Run.TmpBoxContent
2490  if boxcontent:
2491  Run.addGlobalToolTip("OLCBCID_%i" % run.runNr, boxcontent)
2492 
python.AtlRunQueryRun.Run.AddToShowOrder
def AddToShowOrder(cls, key)
Definition: AtlRunQueryRun.py:338
python.AtlRunQueryRun.RunData.stops
stops
Definition: AtlRunQueryRun.py:132
python.AtlRunQueryRun.Run.runlinks
def runlinks(self)
Definition: AtlRunQueryRun.py:752
DerivationFramework::TriggerMatchingUtils::sorted
std::vector< typename R::value_type > sorted(const R &r, PROJ proj={})
Helper function to create a sorted vector from an unsorted range.
replace
std::string replace(std::string s, const std::string &s2, const std::string &s3)
Definition: hcg.cxx:307
python.AtlRunQueryRun.Run.headerkeys
def headerkeys(cls)
Definition: AtlRunQueryRun.py:438
python.AtlRunQueryRun.DataEntry.__repr__
def __repr__(self)
Definition: AtlRunQueryRun.py:45
python.AtlRunQueryRun.DataEntry.lbrange
lbrange
Definition: AtlRunQueryRun.py:37
python.AtlRunQueryRun.RunData.__setitem__
def __setitem__(self, k, value)
Definition: AtlRunQueryRun.py:148
python.AtlRunQueryRun.RunData.run
run
Definition: AtlRunQueryRun.py:128
python.utils.AtlRunQueryUtils.prettyNumber
def prettyNumber(n, width=-1, delim=',', decimal='.')
Definition: AtlRunQueryUtils.py:72
python.AtlRunQueryRun.Run.nr_lb
def nr_lb(self)
Definition: AtlRunQueryRun.py:401
python.utils.AtlRunQueryUtils.filesize
def filesize(no)
Definition: AtlRunQueryUtils.py:197
python.AtlRunQueryRun.Run.header
def header(cls)
Definition: AtlRunQueryRun.py:455
python.AtlRunQueryRun.Run.tooltips
tooltips
Definition: AtlRunQueryRun.py:363
python.AtlRunQueryRun.RunData.data
data
Definition: AtlRunQueryRun.py:129
python.AtlRunQueryRun.RunData.runNrS
def runNrS(self)
Definition: AtlRunQueryRun.py:163
python.utils.AtlRunQueryUtils.addKommaToNumber
def addKommaToNumber(no)
Definition: AtlRunQueryUtils.py:189
index
Definition: index.py:1
max
constexpr double max()
Definition: ap_fixedTest.cxx:33
python.AtlRunQueryRun.Run.GlobalTooltips
list GlobalTooltips
Definition: AtlRunQueryRun.py:332
min
constexpr double min()
Definition: ap_fixedTest.cxx:26
python.output.AtlRunQueryRoot.makeLBPlotList
def makeLBPlotList(xvec, xvecStb, yvec, xtitle, ytitle, ylegend, histname, histtitle, datapath, printText='', ymin=None, ymax=None)
Definition: AtlRunQueryRoot.py:498
python.AtlRunQueryRun.Run.addResult
def addResult(self, resDictKey, value, iov=None, reject=False, valueForStorage=None)
Definition: AtlRunQueryRun.py:741
MuonGM::round
float round(const float toRound, const unsigned int decimals)
Definition: Mdt.cxx:27
python.AtlRunQueryRun.RunData.lbend
def lbend(self, lb=None)
Definition: AtlRunQueryRun.py:170
python.AtlRunQueryRun.Run
Definition: AtlRunQueryRun.py:316
python.AtlRunQueryRun.Run.showDataIncomplete
showDataIncomplete
Definition: AtlRunQueryRun.py:354
python.AtlRunQueryRun.RunData
Definition: AtlRunQueryRun.py:119
python.AtlRunQueryRun.DataEntryList.atLB
def atLB(self, lb)
Definition: AtlRunQueryRun.py:96
python.AtlRunQueryRun.Run.result
result
Definition: AtlRunQueryRun.py:358
python.AtlRunQueryRun.DataEntryList.lastlb
def lastlb(self)
Definition: AtlRunQueryRun.py:105
python.AtlRunQueryRun.RunData.result
def result(self)
Definition: AtlRunQueryRun.py:180
python.AtlRunQueryRun.DataEntry.__init__
def __init__(self, iov, value, reject=False, valueForStorage=None)
Definition: AtlRunQueryRun.py:35
python.AtlRunQueryRun.Run.prettyChain
def prettyChain(cls, tr, ps)
Definition: AtlRunQueryRun.py:857
python.AtlRunQueryRun.RunData.lb
def lb(self)
Definition: AtlRunQueryRun.py:167
dumpHVPathFromNtuple.append
bool append
Definition: dumpHVPathFromNtuple.py:91
python.AtlRunQueryRun.DataEntry.contains
def contains(self, lb)
Definition: AtlRunQueryRun.py:69
python.AtlRunQueryRun.Run.xvecStb
xvecStb
Definition: AtlRunQueryRun.py:355
python.AtlRunQueryRun.DataEntryList.endlb
def endlb(self)
Definition: AtlRunQueryRun.py:109
python.output.AtlRunQueryRoot.SaveGraphsToFile
def SaveGraphsToFile(filename, varnames, xvecs, yvecs, addparamName=None, addparamVal=None)
Definition: AtlRunQueryRoot.py:88
python.AtlRunQueryRun.RunData.__init__
def __init__(self, run)
Definition: AtlRunQueryRun.py:126
python.CaloAddPedShiftConfig.type
type
Definition: CaloAddPedShiftConfig.py:42
python.AtlRunQueryRun.DataEntry.__str__
def __str__(self)
Definition: AtlRunQueryRun.py:42
python.AtlRunQueryRun.DataEntryList.__init__
def __init__(self, key, run)
Definition: AtlRunQueryRun.py:91
python.utils.AtlRunQueryTimer.timer
def timer(name, disabled=False)
Definition: AtlRunQueryTimer.py:85
python.AtlRunQueryRun.RunData.isDQDefectRejected
def isDQDefectRejected(self)
Definition: AtlRunQueryRun.py:218
python.Bindings.values
values
Definition: Control/AthenaPython/python/Bindings.py:808
python.AtlRunQueryRun.Run.durationstr
def durationstr(self)
Definition: AtlRunQueryRun.py:849
python.AtlRunQueryRun.Run.astxt
def astxt(self)
Definition: AtlRunQueryRun.py:921
python.utils.AtlRunQueryLookup.isDQ
def isDQ(name)
Definition: AtlRunQueryLookup.py:135
python.AtlRunQueryRun.RunData.isDQRejected
def isDQRejected(self)
Definition: AtlRunQueryRun.py:203
python.AtlRunQueryRun.Run.lastlb
lastlb
Definition: AtlRunQueryRun.py:352
python.AtlRunQueryRun.Run.__str__
def __str__(self)
Definition: AtlRunQueryRun.py:900
python.AtlRunQueryRun.Run.givepeakmuinfo
givepeakmuinfo
Definition: AtlRunQueryRun.py:369
python.AtlRunQueryRun.Run.selDataIncomplete
selDataIncomplete
Definition: AtlRunQueryRun.py:353
python.AtlRunQueryRun.Run.eor
eor
Definition: AtlRunQueryRun.py:351
python.AtlRunQueryRun.RunData.isRejected
def isRejected(self)
Definition: AtlRunQueryRun.py:225
python.AtlRunQueryRun.RunData.getLBRanges
def getLBRanges(self, activeOnly=False)
Definition: AtlRunQueryRun.py:251
python.AtlRunQueryRun.DataEntry.valueForStorage
valueForStorage
Definition: AtlRunQueryRun.py:40
python.AtlRunQueryRun.DataEntry
Definition: AtlRunQueryRun.py:34
python.AtlRunQueryRun.Run.lumiunit
lumiunit
Definition: AtlRunQueryRun.py:366
perfmonmt-refit.slice
slice
Definition: perfmonmt-refit.py:52
python.AtlRunQueryRun.Run.__lt__
def __lt__(self, other)
Definition: AtlRunQueryRun.py:910
python.AtlRunQueryRun.Run.SortedShowOrder
def SortedShowOrder(cls)
Definition: AtlRunQueryRun.py:419
python.AtlRunQueryRun.RunData.addResult
def addResult(self, iov, k, value, reject, valueForStorage=None)
Definition: AtlRunQueryRun.py:285
python.AtlRunQueryRun.Run.timestr
def timestr(self, format='html', closed=True)
Definition: AtlRunQueryRun.py:814
python.AtlRunQueryRun.Run.addToolTip
def addToolTip(self, var, content)
Definition: AtlRunQueryRun.py:404
python.utils.AtlRunQueryLookup.DecodeDetectorMask
def DecodeDetectorMask(mask, lhcRun=3, smart=False)
Definition: AtlRunQueryLookup.py:419
python.AtlRunQueryRun.DataEntry.startlb
def startlb(self)
Definition: AtlRunQueryRun.py:55
python.AtlRunQueryRun.DataEntry.value
value
Definition: AtlRunQueryRun.py:38
plotBeamSpotVxVal.range
range
Definition: plotBeamSpotVxVal.py:194
python.AtlRunQueryRun.DataEntry.__len__
def __len__(self)
Definition: AtlRunQueryRun.py:48
python.AtlRunQueryRun.Run.instlumiunittxt
instlumiunittxt
Definition: AtlRunQueryRun.py:368
python.AtlRunQueryRun.Run.NrLBs
def NrLBs(self)
Definition: AtlRunQueryRun.py:397
histSizes.list
def list(name, path='/')
Definition: histSizes.py:38
python.output.AtlRunQueryRoot.makeBSPlots
def makeBSPlots(xvec, yvec, xtitle, ytitle, histname, histtitle, datapath, ymin, ymax, printText='')
Definition: AtlRunQueryRoot.py:608
python.AtlRunQueryRun.DataEntry.pickled
def pickled(self)
Definition: AtlRunQueryRun.py:76
python.AtlRunQueryRun.RunData._setLB
def _setLB(self, lb)
Definition: AtlRunQueryRun.py:275
python.AtlRunQueryRun.Run.runNrS
def runNrS(self)
Definition: AtlRunQueryRun.py:389
python.AtlRunQueryRun.RunData._calcStops
def _calcStops(self)
Definition: AtlRunQueryRun.py:279
python.AtlRunQueryRun.RunData.isReady
def isReady(self, lb=None)
Definition: AtlRunQueryRun.py:232
python.AtlRunQueryRun.DataEntry.json
def json(self)
Definition: AtlRunQueryRun.py:80
CxxUtils::set
constexpr std::enable_if_t< is_bitmask_v< E >, E & > set(E &lhs, E rhs)
Convenience function to set bits in a class enum bitmask.
Definition: bitmask.h:232
python.AtlRunQueryRun.DataEntryList.key
key
Definition: AtlRunQueryRun.py:93
TCS::join
std::string join(const std::vector< std::string > &v, const char c=',')
Definition: Trigger/TrigT1/L1Topo/L1TopoCommon/Root/StringUtils.cxx:10
python.AtlRunQueryRun.DataEntry.rejected
rejected
Definition: AtlRunQueryRun.py:39
python.AtlRunQueryRun.Run.stats
stats
Definition: AtlRunQueryRun.py:360
python.AtlRunQueryRun.Run.data_current_lb
def data_current_lb(self)
Definition: AtlRunQueryRun.py:393
python.AtlRunQueryRun.DataEntryList
Definition: AtlRunQueryRun.py:90
python.AtlRunQueryRun.Run.data
data
Definition: AtlRunQueryRun.py:364
python.AtlRunQueryRun.Run.hasStableBeamsInfo
hasStableBeamsInfo
Definition: AtlRunQueryRun.py:356
python.output.AtlRunQueryRoot.makeTimePlotList
def makeTimePlotList(xvec, xveclb, yvec, toffset, dt, ymin, ymax, xtit, ytit, ylegend, name, title, datapath, printText='')
Definition: AtlRunQueryRoot.py:367
TrigJetMonitorAlgorithm.items
items
Definition: TrigJetMonitorAlgorithm.py:71
python.AtlRunQueryRun.DataEntryList.stops
def stops(self)
Definition: AtlRunQueryRun.py:101
python.AtlRunQueryRun.Run.getStableBeamsVector
def getStableBeamsVector(self)
Definition: AtlRunQueryRun.py:407
Trk::open
@ open
Definition: BinningType.h:40
python.AtlRunQueryRun.DataEntry.__getitem__
def __getitem__(self, k)
Definition: AtlRunQueryRun.py:66
python.AtlRunQueryRun.ashtml
def ashtml(run)
Definition: AtlRunQueryRun.py:963
python.AtlRunQueryRun.RunData.data_current_lb
data_current_lb
Definition: AtlRunQueryRun.py:130
python.utils.AtlRunQueryLookup.LArConfig
def LArConfig(type)
Definition: AtlRunQueryLookup.py:444
python.AtlRunQueryRun.Run.runNr
runNr
Definition: AtlRunQueryRun.py:348
python.AtlRunQueryRun.Run.lhcRun
lhcRun
Definition: AtlRunQueryRun.py:349
python.CaloAddPedShiftConfig.int
int
Definition: CaloAddPedShiftConfig.py:45
python.AtlRunQueryRun.Run.sor
sor
Definition: AtlRunQueryRun.py:350
python.AtlRunQueryRun.RunData.astxt
def astxt(self)
Definition: AtlRunQueryRun.py:290
python.AtlRunQueryRun.DataEntryList.run
run
Definition: AtlRunQueryRun.py:94
python.AtlRunQueryRun.Run.ShowOrder
list ShowOrder
Definition: AtlRunQueryRun.py:317
python.AtlRunQueryRun.RunData.isRejectedCurrentLB
def isRejectedCurrentLB(self)
Definition: AtlRunQueryRun.py:184
python.AtlRunQueryRun.Run.lumiunittxt
lumiunittxt
Definition: AtlRunQueryRun.py:367
python.AtlRunQueryRun.DataEntry.iov
iov
Definition: AtlRunQueryRun.py:36
python.AtlRunQueryRun.DataEntry.intersects
def intersects(self, lbrange)
Definition: AtlRunQueryRun.py:72
python.AtlRunQueryRun.RunData.__contains__
def __contains__(self, k)
Definition: AtlRunQueryRun.py:134
python.AtlRunQueryRun.Run.addGlobalToolTip
def addGlobalToolTip(cls, var, content)
Definition: AtlRunQueryRun.py:344
str
Definition: BTagTrackIpAccessor.cxx:11
python.AtlRunQueryRun.RunData.NrLBs
def NrLBs(self)
Definition: AtlRunQueryRun.py:176
python.AtlRunQueryRun.RunData.__iter__
def __iter__(self)
Definition: AtlRunQueryRun.py:151
python.AtlRunQueryRun.RunData.__run_o
__run_o
Definition: AtlRunQueryRun.py:127
python.AtlRunQueryRun.RunData.keys
def keys(self)
Definition: AtlRunQueryRun.py:159
python.AtlRunQueryRun.Run.__init__
def __init__(self, runNr=0)
Definition: AtlRunQueryRun.py:347
python.output.AtlRunQueryRoot.makeLBPlot
def makeLBPlot(xvec, xvecStb, yvecScalar, xtitle, ytitle, ylegendScalar, histname, histtitle, datapath, printText='', ymin=None, ymax=None)
Definition: AtlRunQueryRoot.py:667
python.AtlRunQueryRun.DataEntry.lastlb
def lastlb(self)
Definition: AtlRunQueryRun.py:63
python.AtlRunQueryRun.RunData.__getitem__
def __getitem__(self, k)
Definition: AtlRunQueryRun.py:139
python.AtlRunQueryRun.createToolTips
def createToolTips(run)
Definition: AtlRunQueryRun.py:2427
python.AtlRunQueryRun.RunData.current_lb
current_lb
Definition: AtlRunQueryRun.py:131
python.AtlRunQueryRun.DataEntryList.json
def json(self)
Definition: AtlRunQueryRun.py:115
Trk::split
@ split
Definition: LayerMaterialProperties.h:38
python.AtlRunQueryRun.Run.splitTriggerChains
def splitTriggerChains(self, chainlist)
Definition: AtlRunQueryRun.py:878
python.AtlRunQueryRun.DataEntry.endlb
def endlb(self)
Definition: AtlRunQueryRun.py:59
python.AtlRunQueryRun.Run.__eq__
def __eq__(self, other)
Definition: AtlRunQueryRun.py:915
python.AtlRunQueryRun.Run.lbtimes
lbtimes
Definition: AtlRunQueryRun.py:362
python.AtlRunQueryRun.DataEntryList.pickled
def pickled(self)
Definition: AtlRunQueryRun.py:112
python.LArMinBiasAlgConfig.float
float
Definition: LArMinBiasAlgConfig.py:65