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