CMS 3D CMS Logo

create_public_lumi_plots.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 
3 ######################################################################
4 ## File: create_public_lumi_plots.py
5 ######################################################################
6 
7 from __future__ import print_function
8 from builtins import range
9 import sys
10 import os
11 import commands
12 import time
13 import datetime
14 import calendar
15 import copy
16 import math
17 import optparse
18 import ConfigParser
19 import cjson
20 
21 import numpy as np
22 
23 import six
24 import matplotlib
25 matplotlib.use('Agg')
26 from matplotlib import pyplot as plt
27 # FIX FIX FIX
28 # This fixes a well-know bug with stepfilled logarithmic histograms in
29 # Matplotlib.
30 from RecoLuminosity.LumiDB.mpl_axes_hist_fix import hist
31 if matplotlib.__version__ != '1.0.1':
32  print("ERROR The %s script contains a hard-coded bug-fix " \
33  "for Matplotlib 1.0.1. The Matplotlib version loaded " \
34  "is %s" % (__file__, matplotlib.__version__), file=sys.stderr)
35  sys.exit(1)
36 matplotlib.axes.Axes.hist = hist
37 # FIX FIX FIX end
38 
39 from RecoLuminosity.LumiDB.public_plots_tools import ColorScheme
40 from RecoLuminosity.LumiDB.public_plots_tools import LatexifyUnits
41 from RecoLuminosity.LumiDB.public_plots_tools import AddLogo
42 from RecoLuminosity.LumiDB.public_plots_tools import InitMatplotlib
43 from RecoLuminosity.LumiDB.public_plots_tools import SavePlot
44 from RecoLuminosity.LumiDB.public_plots_tools import FONT_PROPS_SUPTITLE
45 from RecoLuminosity.LumiDB.public_plots_tools import FONT_PROPS_TITLE
46 from RecoLuminosity.LumiDB.public_plots_tools import FONT_PROPS_AX_TITLE
47 from RecoLuminosity.LumiDB.public_plots_tools import FONT_PROPS_TICK_LABEL
48 
49 try:
50  import debug_hook
51  import pdb
52 except ImportError:
53  pass
54 
55 ######################################################################
56 
57 # Some global constants. Not nice, but okay.
58 DATE_FMT_STR_LUMICALC = "%m/%d/%y %H:%M:%S"
59 DATE_FMT_STR_LUMICALC_DAY = "%m/%d/%y"
60 DATE_FMT_STR_OUT = "%Y-%m-%d %H:%M"
61 DATE_FMT_STR_AXES = "%-d %b"
62 DATE_FMT_STR_CFG = "%Y-%m-%d"
63 NUM_SEC_IN_LS = 2**18 / 11246.
64 
65 KNOWN_ACCEL_MODES = ["PROTPHYS", "IONPHYS", "PAPHYS",
66  "2013_amode_bug_workaround"]
67 LEAD_SCALE_FACTOR = 82. / 208.
68 
69 ######################################################################
70 
72  """Holds info from one line of lumiCalc lumibyls output."""
73 
74  def __init__(self, line, json_file_name=None):
75 
76  # Decode the comma-separated line from lumiCalc.
77  line_split = line.split(",")
78  tmp = line_split[0].split(":")
79  self.run_number = int(tmp[0])
80  self.fill_number = int(tmp[1])
81  tmp = line_split[1].split(":")
82  self.ls = int(tmp[0])
83  tmp = line_split[2]
84  self.timestamp = datetime.datetime.strptime(tmp, DATE_FMT_STR_LUMICALC)
85  # NOTE: Convert from ub^{-1} to b^{-1}.
86  scale_factor = 1.e6
87  self.lum_del = scale_factor * float(line_split[5])
88  self.lum_rec = scale_factor * float(line_split[6])
89 
90  # Adding lum_cert for the data certification information
91  if json_file_name:
92  addcertls = bool(checkCertification(self.run_number, self.ls))
93  if addcertls:
94  self.lum_cert = scale_factor * float(line_split[6])
95  else:
96  self.lum_cert = 0.
97  else:
98  self.lum_cert = 0.
99 
100  # End of __init__().
101 
102  # End of class LumiDataPoint.
103 
104 ######################################################################
105 
107  """A supposedly coherent block of LumiDataPoints.
108 
109  NOTE: No checks on duplicates, sorting, etc.
110 
111  """
112 
113  scale_factors = {
114  "fb^{-1}" : 1.e-15,
115  "pb^{-1}" : 1.e-12,
116  "nb^{-1}" : 1.e-9,
117  "ub^{-1}" : 1.e-6,
118  "mb^{-1}" : 1.e-3,
119  "b^{-1}" : 1.,
120  "Hz/fb" : 1.e-15,
121  "Hz/pb" : 1.e-12,
122  "Hz/nb" : 1.e-9,
123  "Hz/ub" : 1.e-6,
124  "Hz/mb" : 1.e-3,
125  "Hz/b" : 1.
126  }
127 
128  def __init__(self, data_point=None):
129  if not data_point:
130  self.data_points = []
131  else:
132  self.data_points = [data_point]
133  # End of __init__().
134 
135  def __iadd__(self, other):
136  self.data_points.extend(other.data_points)
137  # End of __iadd__().
138  return self
139 
140  def __lt__(self, other):
141  # End of __lt__().
142  return self.time_mid() < other.time_mid()
143 
144  def add(self, new_point):
145  self.data_points.append(new_point)
146  # End of add().
147 
148  def copy(self):
149  # End of copy().
150  return copy.deepcopy(self)
151 
152  def is_empty(self):
153  # End of is_empty().
154  return not len(self.data_points)
155 
156  def lum_del_tot(self, units="b^{-1}"):
157  res = sum([i.lum_del for i in self.data_points])
158  res *= LumiDataBlock.scale_factors[units]
159  # End of lum_del_tot().
160  return res
161 
162  def lum_rec_tot(self, units="b^{-1}"):
163  res = sum([i.lum_rec for i in self.data_points])
164  res *= LumiDataBlock.scale_factors[units]
165  # End of lum_rec_tot().
166  return res
167 
168  def lum_cert_tot(self, units="b^{-1}"):
169  res = sum([i.lum_cert for i in self.data_points])
170  res *= LumiDataBlock.scale_factors[units]
171  # End of lum_cert_tot().
172  return res
173 
174  def max_inst_lum(self, units="Hz/b"):
175  res = 0.
176  if len(self.data_points):
177  res = max([i.lum_del for i in self.data_points])
178  res /= NUM_SEC_IN_LS
179  res *= LumiDataBlock.scale_factors[units]
180  # End of max_inst_lum().
181  return res
182 
183  def straighten(self):
184  self.data_points.sort()
185  # End of straighten().
186 
187  def time_begin(self):
188  res = min([i.timestamp for i in self.data_points])
189  # End of time_begin().
190  return res
191 
192  def time_end(self):
193  res = max([i.timestamp for i in self.data_points])
194  # End of time_end().
195  return res
196 
197  def time_mid(self):
198  delta = self.time_end() - self.time_begin()
199  delta_sec = delta.days * 24 * 60 * 60 + delta.seconds
200  res = self.time_begin() + datetime.timedelta(seconds=.5*delta_sec)
201  # End of time_mid().
202  return res
203 
204  # End of class LumiDataBlock.
205 
206 ######################################################################
207 
209  """A collection of LumiDataBlocks."""
210 
211  def __init__(self, data_block=None):
212  if not data_block:
213  self.data_blocks = []
214  else:
215  self.data_blocks = [data_block]
216  # End of __init__().
217 
218  def __len__(self):
219  # End of __len__().
220  return len(self.data_blocks)
221 
222  def add(self, new_block):
223  self.data_blocks.append(new_block)
224  # End of add().
225 
226  def sort(self):
227  self.data_blocks.sort()
228  # End of sort().
229 
230  def time_begin(self):
231  res = datetime.datetime.max
232  if len(self.data_blocks):
233  res = min([i.time_begin() for i in self.data_blocks])
234  # End of time_begin().
235  return res
236 
237  def time_end(self):
238  res = datetime.datetime.min
239  if len(self.data_blocks):
240  res = max([i.time_end() for i in self.data_blocks])
241  # End of time_end().
242  return res
243 
244  def times(self):
245  res = [i.time_mid() for i in self.data_blocks]
246  # End of times().
247  return res
248 
249  def lum_del(self, units="b^{-1}"):
250  res = [i.lum_del_tot(units) for i in self.data_blocks]
251  # End of lum_del().
252  return res
253 
254  def lum_rec(self, units="b^{-1}"):
255  res = [i.lum_rec_tot(units) for i in self.data_blocks]
256  # End of lum_rec().
257  return res
258 
259  def lum_cert(self, units="b^{-1}"):
260  res = [i.lum_cert_tot(units) for i in self.data_blocks]
261  # End of lum_cert().
262  return res
263 
264  def lum_del_tot(self, units="b^{-1}"):
265  # End of lum_del().
266  return sum(self.lum_del(units))
267 
268  def lum_rec_tot(self, units="b^{-1}"):
269  # End of lum_rec().
270  return sum(self.lum_rec(units))
271 
272  def lum_cert_tot(self, units="b^{-1}"):
273  # End of lum_cert().
274  return sum(self.lum_cert(units))
275 
276  def lum_inst_max(self, units="Hz/b"):
277  res = [i.max_inst_lum(units) for i in self.data_blocks]
278  # End of lum_inst_max().
279  return res
280 
281  # End of class LumiDataBlockCollection.
282 
283 ######################################################################
284 
285 def CacheFilePath(cache_file_dir, day=None):
286  cache_file_path = os.path.abspath(cache_file_dir)
287  if day:
288  cache_file_name = "lumicalc_cache_%s.csv" % day.isoformat()
289  cache_file_path = os.path.join(cache_file_path, cache_file_name)
290  return cache_file_path
291 
292 ######################################################################
293 
294 def AtMidnight(datetime_in):
295  res = datetime.datetime.combine(datetime_in.date(), datetime.time())
296  # End of AtMidnight().
297  return res
298 
299 ######################################################################
300 
301 def AtMidWeek(datetime_in):
302  # NOTE: The middle of the week is on Thursday according to our
303  # definition
304  tmp = datetime_in.date()
305  date_tmp = tmp - \
306  datetime.timedelta(days=tmp.weekday()) + \
307  datetime.timedelta(days=3)
308  res = datetime.datetime.combine(date_tmp, datetime.time())
309  # End of AtMidWeek().
310  return res
311 
312 ######################################################################
313 
314 def GetUnits(year, accel_mode, mode):
315 
316  units_spec = {
317  "PROTPHYS" : {
318  2010 : {
319  "cum_day" : "pb^{-1}",
320  "cum_week" : "pb^{-1}",
321  "cum_year" : "pb^{-1}",
322  "max_inst" : "Hz/ub",
323  },
324  2011 : {
325  "cum_day" : "pb^{-1}",
326  "cum_week" : "pb^{-1}",
327  "cum_year" : "fb^{-1}",
328  "max_inst" : "Hz/nb",
329  },
330  2012 : {
331  "cum_day" : "pb^{-1}",
332  "cum_week" : "fb^{-1}",
333  "cum_year" : "fb^{-1}",
334  "max_inst" : "Hz/nb",
335  },
336  2013 : {
337  "cum_day" : "pb^{-1}",
338  "cum_week" : "pb^{-1}",
339  "cum_year" : "pb^{-1}",
340  "max_inst" : "Hz/ub",
341  }
342  },
343  "IONPHYS" : {
344  2011 : {
345  "cum_day" : "ub^{-1}",
346  "cum_week" : "ub^{-1}",
347  "cum_year" : "ub^{-1}",
348  "max_inst" : "Hz/mb",
349  }
350  },
351  "PAPHYS" : {
352  2013 : {
353  "cum_day" : "nb^{-1}",
354  "cum_week" : "nb^{-1}",
355  "cum_year" : "nb^{-1}",
356  "max_inst" : "Hz/mb",
357  }
358  }
359  }
360 
361  units = None
362 
363  try:
364  units = units_spec[accel_mode][year][mode]
365  except KeyError:
366  if mode == "cum_day":
367  units = "pb^{-1}"
368  elif mode == "cum_week":
369  units = "pb^{-1}"
370  elif mode == "cum_year":
371  units = "fb^{-1}"
372  elif mode == "max_inst":
373  units = "Hz/ub"
374 
375  # DEBUG DEBUG DEBUG
376  assert not units is None
377  # DEBUG DEBUG DEBUG end
378 
379  # End of GetUnits().
380  return units
381 
382 ######################################################################
383 
385  # DEBUG DEBUG DEBUG
386  assert amodetag in ["IONPHYS", "PAPHYS"]
387  # DEBUG DEBUG DEBUG end
388 
389  res = LEAD_SCALE_FACTOR
390  if amodetag == "PAPHYS":
391  res = math.sqrt(res)
392 
393  # End of GetEnergyPerNucleonScaleFactor().
394  return res
395 
396 ######################################################################
397 
398 def NumDaysInYear(year):
399  """Returns the number of days in the given year."""
400 
401  date_lo = datetime.date(year, 1, 1)
402  date_hi = datetime.date(year + 1, 1, 1)
403  num_days = (date_hi - date_lo).days
404 
405  # End of NumDaysInYear().
406  return num_days
407 
408 ######################################################################
409 
410 def GetXLocator(ax):
411  """Pick a DateLocator based on the range of the x-axis."""
412  (x_lo, x_hi) = ax.get_xlim()
413  num_days = x_hi - x_lo
414  min_num_ticks = min(num_days, 5)
415  locator = matplotlib.dates.AutoDateLocator(minticks=min_num_ticks,
416  maxticks=None)
417  # End of GetLocator().
418  return locator
419 
420 ######################################################################
421 
422 def TweakPlot(fig, ax, time_range,
423  add_extra_head_room=False):
424 
425  # Fiddle with axes ranges etc.
426  (time_begin, time_end) = time_range
427  ax.relim()
428  ax.autoscale_view(False, True, True)
429  for label in ax.get_xticklabels():
430  label.set_ha("right")
431  label.set_rotation(30.)
432 
433  # Bit of magic here: increase vertical scale by one tick to make
434  # room for the legend.
435  if add_extra_head_room:
436  y_ticks = ax.get_yticks()
437  (y_min, y_max) = ax.get_ylim()
438  is_log = (ax.get_yscale() == "log")
439  y_max_new = y_max
440  if is_log:
441  tmp = y_ticks[-1] / y_ticks[-2]
442  y_max_new = y_max * math.pow(tmp, add_extra_head_room)
443  else:
444  tmp = y_ticks[-1] - y_ticks[-2]
445  y_max_new = y_max + add_extra_head_room * tmp
446  ax.set_ylim(y_min, y_max_new)
447 
448  # Add a second vertical axis on the right-hand side.
449  ax_sec = ax.twinx()
450  ax_sec.set_ylim(ax.get_ylim())
451  ax_sec.set_yscale(ax.get_yscale())
452 
453  for ax_tmp in fig.axes:
454  for sub_ax in [ax_tmp.xaxis, ax_tmp.yaxis]:
455  for label in sub_ax.get_ticklabels():
456  label.set_font_properties(FONT_PROPS_TICK_LABEL)
457 
458  ax.set_xlim(time_begin, time_end)
459 
460  locator = GetXLocator(ax)
461  ax.xaxis.set_major_locator(locator)
462  formatter = matplotlib.dates.DateFormatter(DATE_FMT_STR_AXES)
463  ax.xaxis.set_major_formatter(formatter)
464 
465  fig.subplots_adjust(top=.85, bottom=.14, left=.13, right=.91)
466  # End of TweakPlot().
467 
468 ######################################################################
469 
470 def checkCertification(run_number, ls):
471  """Check if this run and LS are certified as good and return a boolean parameter."""
472  try:
473  ls_ranges = certification_data[run_number]
474  for ranges in ls_ranges:
475  if (ls >= ranges[0]) and (ls <= ranges[1]):
476  return True
477  except KeyError:
478  return False
479 
480  return False
481 
482 ######################################################################
483 
484 def loadCertificationJSON(json_file_name):
485 
486  full_file = open(json_file_name, "r")
487  full_file_content = ["".join(l) for l in full_file.readlines()]
488  full_object = cjson.decode(full_file_content[0])
489 
490  # Now turn this into a dictionary for easier handling.
491  tmp = full_object.keys()
492  tmp = [int(i) for i in tmp]
493  run_list = sorted(tmp)
494  certification_data = {}
495  for run in run_list:
496  ls_ranges = full_object.get(str(run), None)
497  certification_data[run] = ls_ranges
498 
499  return certification_data
500 
501 ######################################################################
502 
503 if __name__ == "__main__":
504 
505  desc_str = "This script creates the official CMS luminosity plots " \
506  "based on the output from the lumiCalc family of scripts."
507  arg_parser = optparse.OptionParser(description=desc_str)
508  arg_parser.add_option("--ignore-cache", action="store_true",
509  help="Ignore all cached lumiCalc results " \
510  "and re-query lumiCalc. " \
511  "(Rebuilds the cache as well.)")
512  (options, args) = arg_parser.parse_args()
513  if len(args) != 1:
514  print("ERROR Need exactly one argument: a config file name", file=sys.stderr)
515  sys.exit(1)
516  config_file_name = args[0]
517  ignore_cache = options.ignore_cache
518 
519  cfg_defaults = {
520  "lumicalc_flags" : "",
521  "date_end" : None,
522  "color_schemes" : "Joe, Greg",
523  "beam_energy" : None,
524  "beam_fluctuation" : None,
525  "verbose" : False,
526  "oracle_connection" : None,
527  "json_file" : None
528  }
529  cfg_parser = ConfigParser.SafeConfigParser(cfg_defaults)
530  if not os.path.exists(config_file_name):
531  print("ERROR Config file '%s' does not exist" % config_file_name, file=sys.stderr)
532  sys.exit(1)
533  cfg_parser.read(config_file_name)
534 
535  # Which color scheme to use for drawing the plots.
536  color_scheme_names_tmp = cfg_parser.get("general", "color_schemes")
537  color_scheme_names = [i.strip() for i in color_scheme_names_tmp.split(",")]
538  # Where to store cache files containing the lumiCalc output.
539  cache_file_dir = cfg_parser.get("general", "cache_dir")
540  # Flag to turn on verbose output.
541  verbose = cfg_parser.getboolean("general", "verbose")
542 
543  # Some details on how to invoke lumiCalc.
544  lumicalc_script = cfg_parser.get("general", "lumicalc_script")
545  lumicalc_flags_from_cfg = cfg_parser.get("general", "lumicalc_flags")
546  accel_mode = cfg_parser.get("general", "accel_mode")
547  # Check if we know about this accelerator mode.
548  if not accel_mode in KNOWN_ACCEL_MODES:
549  print("ERROR Unknown accelerator mode '%s'" % \
550  accel_mode, file=sys.stderr)
551 
552  # WORKAROUND WORKAROUND WORKAROUND
553  amodetag_bug_workaround = False
554  if accel_mode == "2013_amode_bug_workaround":
555  amodetag_bug_workaround = True
556  accel_mode = "PAPHYS"
557  # WORKAROUND WORKAROUND WORKAROUND end
558 
559  beam_energy_tmp = cfg_parser.get("general", "beam_energy")
560  # If no beam energy specified, use the default(s) for this
561  # accelerator mode.
562  beam_energy = None
563  beam_energy_from_cfg = None
564  if not beam_energy_tmp:
565  print("No beam energy specified --> using defaults for '%s'" % \
566  accel_mode)
567  beam_energy_from_cfg = False
568  else:
569  beam_energy_from_cfg = True
570  beam_energy = float(beam_energy_tmp)
571 
572  beam_fluctuation_tmp = cfg_parser.get("general", "beam_fluctuation")
573  # If no beam energy fluctuation specified, use the default for
574  # this accelerator mode.
575  beam_fluctuation = None
576  beam_fluctuation_from_cfg = None
577  if not beam_fluctuation_tmp:
578  print("No beam energy fluctuation specified --> using the defaults to '%s'" % \
579  accel_mode)
580  beam_fluctuation_from_cfg = False
581  else:
582  beam_fluctuation_from_cfg = True
583  beam_fluctuation = float(beam_fluctuation_tmp)
584 
585  # Overall begin and end dates of all data to include.
586  tmp = cfg_parser.get("general", "date_begin")
587  date_begin = datetime.datetime.strptime(tmp, DATE_FMT_STR_CFG).date()
588  tmp = cfg_parser.get("general", "date_end")
589  date_end = None
590  if tmp:
591  date_end = datetime.datetime.strptime(tmp, DATE_FMT_STR_CFG).date()
592  # If no end date is given, use today.
593  today = datetime.datetime.utcnow().date()
594  if not date_end:
595  print("No end date given --> using today")
596  date_end = today
597  # If end date lies in the future, truncate at today.
598  if date_end > today:
599  print("End date lies in the future --> using today instead")
600  date_end = today
601  # If end date is before start date, give up.
602  if date_end < date_begin:
603  print("ERROR End date before begin date (%s < %s)" % \
604  (date_end.isoformat(), date_begin.isoformat()), file=sys.stderr)
605  sys.exit(1)
606 
607  # If an Oracle connection string is specified, use direct Oracle
608  # access. Otherwise access passes through the Frontier
609  # cache. (Fine, but much slower to receive the data.)
610  oracle_connection_string = cfg_parser.get("general", "oracle_connection")
611  use_oracle = (len(oracle_connection_string) != 0)
612 
613  # If a JSON file is specified, use the JSON file to add in the
614  # plot data certified as good for physics.
615  json_file_name = cfg_parser.get("general", "json_file")
616  if len(json_file_name) < 1:
617  json_file_name = None
618  if json_file_name:
619  if not os.path.exists(json_file_name):
620  print("ERROR Requested JSON file '%s' is not available" % json_file_name, file=sys.stderr)
621  sys.exit(1)
622  print("Using JSON file '%s' for certified data" % json_file_name)
623  else:
624  if verbose:
625  print("No JSON file specified, filling only standard lumi plot.")
626 
627  ##########
628 
629  certification_data = None
630  if json_file_name:
631  certification_data = loadCertificationJSON(json_file_name)
632 
633  ##########
634 
635  # Map accelerator modes (as fed to lumiCalc) to particle type
636  # strings to be used in plot titles etc.
637  particle_type_strings = {
638  "PROTPHYS" : "pp",
639  "IONPHYS" : "PbPb",
640  "PAPHYS" : "pPb"
641  }
642  particle_type_str = particle_type_strings[accel_mode]
643 
644  beam_energy_defaults = {
645  "PROTPHYS" : {2010 : 3500.,
646  2011 : 3500.,
647  2012 : 4000.,
648  2013 : 1380.1},
649  "IONPHYS" : {2010 : 3500.,
650  2011 : 3500.},
651  "PAPHYS" : {2013 : 4000.}
652  }
653  beam_fluctuation_defaults = {
654  "PROTPHYS" : {2010 : .15,
655  2011 : .15,
656  2012 : .15,
657  2013 : .15},
658  "IONPHYS" : {2010 : .15,
659  2011 : .15},
660  "PAPHYS" : {2013 : .15}
661  }
662 
663  ##########
664 
665  # Environment parameter for access to the Oracle DB.
666  if use_oracle:
667  os.putenv("TNS_ADMIN", "/afs/cern.ch/cms/lumi/DB")
668 
669  ##########
670 
671  # Tell the user what's going to happen.
672  print("Using configuration from file '%s'" % config_file_name)
673  if ignore_cache:
674  print("Ignoring all cached lumiCalc results (and rebuilding the cache)")
675  else:
676  print("Using cached lumiCalc results from %s" % \
677  CacheFilePath(cache_file_dir))
678  print("Using color schemes '%s'" % ", ".join(color_scheme_names))
679  print("Using lumiCalc script '%s'" % lumicalc_script)
680  print("Using additional lumiCalc flags from configuration: '%s'" % \
681  lumicalc_flags_from_cfg)
682  print("Selecting data for accelerator mode '%s'" % accel_mode)
683  if beam_energy_from_cfg:
684  print("Selecting data for beam energy %.0f GeV" % beam_energy)
685  else:
686  print("Selecting data for default beam energy for '%s' from:" % accel_mode)
687  for (key, val) in six.iteritems(beam_energy_defaults[accel_mode]):
688  print(" %d : %.1f GeV" % (key, val))
689  if beam_fluctuation_from_cfg:
690  print("Using beam energy fluctuation of +/- %.0f%%" % \
691  (100. * beam_fluctuation))
692  else:
693  print("Using default beam energy fluctuation for '%s' from:" % accel_mode)
694  for (key, val) in six.iteritems(beam_fluctuation_defaults[accel_mode]):
695  print(" %d : +/- %.0f%%" % (key, 100. * val))
696  if use_oracle:
697  print("Using direct access to the Oracle luminosity database")
698  else:
699  print("Using access to the luminosity database through the Frontier cache")
700 
701  ##########
702 
703  # See if the cache file dir exists, otherwise try to create it.
704  path_name = CacheFilePath(cache_file_dir)
705  if not os.path.exists(path_name):
706  if verbose:
707  print("Cache file path does not exist: creating it")
708  try:
709  os.makedirs(path_name)
710  except Exception as err:
711  print("ERROR Could not create cache dir: %s" % path_name, file=sys.stderr)
712  sys.exit(1)
713 
714  ##########
715 
717 
718  ##########
719 
720  week_begin = date_begin.isocalendar()[1]
721  week_end = date_end.isocalendar()[1]
722  year_begin = date_begin.isocalendar()[0]
723  year_end = date_end.isocalendar()[0]
724  # DEBUG DEBUG DEBUG
725  assert year_end >= year_begin
726  # DEBUG DEBUG DEBUG end
727  print("Building a list of days to include in the plots")
728  print(" first day to consider: %s (%d, week %d)" % \
729  (date_begin.isoformat(), year_begin, week_begin))
730  print(" last day to consider: %s (%d, week %d)" % \
731  (date_end.isoformat(), year_end, week_end))
732  num_days = (date_end - date_begin).days + 1
733  days = [date_begin + datetime.timedelta(days=i) for i in range(num_days)]
734  years = list(range(year_begin, year_end + 1))
735  weeks = []
736  day_cur = date_begin
737  while day_cur <= date_end:
738  year = day_cur.isocalendar()[0]
739  week = day_cur.isocalendar()[1]
740  weeks.append((year, week))
741  day_cur += datetime.timedelta(days=7)
742  if num_days <= 7:
743  year = date_end.isocalendar()[0]
744  week = date_end.isocalendar()[1]
745  weeks.append((year, week))
746  weeks = list(set(weeks))
747  weeks.sort()
748 
749  # Figure out the last day we want to read back from the cache.
750  # NOTE: The above checking ensures that date_end is <= today, so
751  # the below only assumes that we're never more than two days
752  # behind on our luminosity numbers.
753  last_day_from_cache = min(today - datetime.timedelta(days=2), date_end)
754  if verbose:
755  print("Last day for which the cache will be used: %s" % \
756  last_day_from_cache.isoformat())
757 
758  # First run lumiCalc. Once for each day to be included in the
759  # plots.
760  print("Running lumiCalc for all requested days")
761  for day in days:
762  print(" %s" % day.isoformat())
763  use_cache = (not ignore_cache) and (day <= last_day_from_cache)
764  cache_file_path = CacheFilePath(cache_file_dir, day)
765  cache_file_tmp = cache_file_path.replace(".csv", "_tmp.csv")
766  if (not os.path.exists(cache_file_path)) or (not use_cache):
767  date_begin_str = day.strftime(DATE_FMT_STR_LUMICALC)
768  date_begin_day_str = day.strftime(DATE_FMT_STR_LUMICALC_DAY)
769  date_end_str = (day + datetime.timedelta(days=1)).strftime(DATE_FMT_STR_LUMICALC)
770  date_previous_str = (day - datetime.timedelta(days=1)).strftime(DATE_FMT_STR_LUMICALC)
771  if not beam_energy_from_cfg:
772  year = day.isocalendar()[0]
773  beam_energy = beam_energy_defaults[accel_mode][year]
774  if not beam_fluctuation_from_cfg:
775  year = day.isocalendar()[0]
776  beam_fluctuation = beam_fluctuation_defaults[accel_mode][year]
777 
778  # WORKAROUND WORKAROUND WORKAROUND
779  # Trying to work around the issue with the unfilled
780  # accelerator mode in the RunInfo database.
781  if amodetag_bug_workaround:
782  # Don't use the amodetag in this case. Scary, but
783  # works for the moment.
784  lumicalc_flags = "%s --without-checkforupdate " \
785  "--beamenergy %.1f " \
786  "--beamfluctuation %.2f " \
787  "lumibyls" % \
788  (lumicalc_flags_from_cfg,
789  beam_energy, beam_fluctuation)
790  else:
791  # This is the way things should be.
792  lumicalc_flags = "%s --without-checkforupdate " \
793  "--beamenergy %.1f " \
794  "--beamfluctuation %.2f " \
795  "--amodetag %s " \
796  "lumibyls" % \
797  (lumicalc_flags_from_cfg,
798  beam_energy, beam_fluctuation,
799  accel_mode)
800  # WORKAROUND WORKAROUND WORKAROUND end
801 
802  lumicalc_flags = lumicalc_flags.strip()
803  lumicalc_cmd = "%s %s" % (lumicalc_script, lumicalc_flags)
804  if use_oracle:
805  lumicalc_cmd = "%s %s" % (lumicalc_cmd, oracle_connection_string)
806  cmd = "%s --begin '%s' --end '%s' -o %s" % \
807  (lumicalc_cmd, date_previous_str, date_end_str, cache_file_tmp)
808  if verbose:
809  print(" running lumicalc as '%s'" % cmd)
810  (status, output) = commands.getstatusoutput(cmd)
811  # BUG BUG BUG
812  # Trying to track down the bad-cache problem.
813  output_0 = copy.deepcopy(output)
814  # BUG BUG BUG end
815  if status != 0:
816  # This means 'no qualified data found'.
817  if ((status >> 8) == 13 or (status >> 8) == 14):
818  # If no data is found it never writes the output
819  # file. So for days without data we would keep
820  # querying the database in vain every time the
821  # script runs. To avoid this we just write a dummy
822  # cache file for such days.
823  if verbose:
824  print("No lumi data for %s, " \
825  "writing dummy cache file to avoid re-querying the DB" % \
826  day.isoformat())
827  dummy_file = open(cache_file_tmp, "w")
828  dummy_file.write("Run:Fill,LS,UTCTime,Beam Status,E(GeV),Delivered(/ub),Recorded(/ub),avgPU\r\n")
829  dummy_file.close()
830  else:
831  print("ERROR Problem running lumiCalc: %s" % output, file=sys.stderr)
832  sys.exit(1)
833 
834  # BUG BUG BUG
835  # This works around a bug in lumiCalc where sometimes not
836  # all data for a given day is returned. The work-around is
837  # to ask for data from two days and then filter out the
838  # unwanted day.
839  lines_to_be_kept = []
840  lines_ori = open(cache_file_tmp).readlines()
841  for line in lines_ori:
842  if (date_begin_day_str in line) or ("Delivered" in line):
843  lines_to_be_kept.append(line)
844  newfile = open(cache_file_path, "w")
845  newfile.writelines(lines_to_be_kept)
846  newfile.close()
847  # BUG BUG BUG end
848 
849  if verbose:
850  print(" CSV file for the day written to %s" % \
851  cache_file_path)
852  else:
853  if verbose:
854  print(" cache file for %s exists" % day.isoformat())
855 
856  # Now read back all lumiCalc results.
857  print("Reading back lumiCalc results")
858  lumi_data_by_day = {}
859  for day in days:
860  print(" %s" % day.isoformat())
861  cache_file_path = CacheFilePath(cache_file_dir, day)
862  lumi_data_day = LumiDataBlock()
863  try:
864  in_file = open(cache_file_path)
865  lines = in_file.readlines()
866  if not len(lines):
867  if verbose:
868  print(" skipping empty file for %s" % day.isoformat())
869  else:
870  # DEBUG DEBUG DEBUG
871  assert lines[0] == "Run:Fill,LS,UTCTime,Beam Status,E(GeV),Delivered(/ub),Recorded(/ub),avgPU\r\n"
872  # DEBUG DEBUG DEBUG end
873  for line in lines[1:]:
874  lumi_data_day.add(LumiDataPoint(line, json_file_name))
875  in_file.close()
876  except IOError as err:
877  print("ERROR Could not read lumiCalc results from file '%s': %s" % \
878  (cache_file_path, str(err)), file=sys.stderr)
879  sys.exit(1)
880  # Only store data if there actually is something to store.
881  if not lumi_data_day.is_empty():
882  lumi_data_by_day[day] = lumi_data_day
883 
884  ##########
885 
886  # Bunch lumiCalc data together into weeks.
887  print("Combining lumiCalc data week-by-week")
888  lumi_data_by_week = {}
889  for (day, lumi) in six.iteritems(lumi_data_by_day):
890  year = day.isocalendar()[0]
891  week = day.isocalendar()[1]
892  try:
893  lumi_data_by_week[year][week] += lumi
894  except KeyError:
895  try:
896  lumi_data_by_week[year][week] = lumi.copy()
897  except KeyError:
898  lumi_data_by_week[year] = {week: lumi.copy()}
899 
900  lumi_data_by_week_per_year = {}
901  for (year, tmp_lumi) in six.iteritems(lumi_data_by_week):
902  for (week, lumi) in six.iteritems(tmp_lumi):
903  try:
904  lumi_data_by_week_per_year[year].add(lumi)
905  except KeyError:
906  lumi_data_by_week_per_year[year] = LumiDataBlockCollection(lumi)
907 
908  # Bunch lumiCalc data together into years.
909  print("Combining lumiCalc data year-by-year")
910  lumi_data_by_year = {}
911  for (day, lumi) in six.iteritems(lumi_data_by_day):
912  year = day.isocalendar()[0]
913  try:
914  lumi_data_by_year[year] += lumi
915  except KeyError:
916  lumi_data_by_year[year] = lumi.copy()
917 
918  lumi_data_by_day_per_year = {}
919  for (day, lumi) in six.iteritems(lumi_data_by_day):
920  year = day.isocalendar()[0]
921  try:
922  lumi_data_by_day_per_year[year].add(lumi)
923  except KeyError:
924  lumi_data_by_day_per_year[year] = LumiDataBlockCollection(lumi)
925 
926  ##########
927 
928  # Now dump a lot of info to the user.
929  sep_line = 50 * "-"
930  print(sep_line)
931  units = GetUnits(years[-1], accel_mode, "cum_day")
932  print("Delivered lumi day-by-day (%s):" % units)
933  print(sep_line)
934  for day in days:
935  tmp_str = " - (no data, presumably no lumi either)"
936  try:
937  tmp = lumi_data_by_day[day].lum_del_tot(units)
938  helper_str = ""
939  if (tmp < .1) and (tmp > 0.):
940  helper_str = " (non-zero but very small)"
941  tmp_str = "%6.1f%s" % (tmp, helper_str)
942  except KeyError:
943  pass
944  print(" %s: %s" % (day.isoformat(), tmp_str))
945  print(sep_line)
946  units = GetUnits(years[-1], accel_mode, "cum_week")
947  print("Delivered lumi week-by-week (%s):" % units)
948  print(sep_line)
949  for (year, week) in weeks:
950  tmp_str = " - (no data, presumably no lumi either)"
951  try:
952  tmp = lumi_data_by_week[year][week].lum_del_tot(units)
953  helper_str = ""
954  if (tmp < .1) and (tmp > 0.):
955  helper_str = " (non-zero but very small)"
956  tmp_str = "%6.1f%s" % (tmp, helper_str)
957  except KeyError:
958  pass
959  print(" %d-%2d: %s" % (year, week, tmp_str))
960  print(sep_line)
961  units = GetUnits(years[-1], accel_mode, "cum_year")
962  print("Delivered lumi year-by-year (%s):" % units)
963  print(sep_line)
964  for year in years:
965  tmp_str = " - (no data, presumably no lumi either)"
966  try:
967  tmp = lumi_data_by_year[year].lum_del_tot(units)
968  helper_str = ""
969  if (tmp < .01) and (tmp > 0.):
970  helper_str = " (non-zero but very small)"
971  tmp_str = "%5.2f%s" % (tmp, helper_str)
972  except KeyError:
973  pass
974  print(" %4d: %s" % \
975  (year, tmp_str))
976  print(sep_line)
977 
978  ##########
979 
980  if not len(lumi_data_by_day_per_year):
981  print("ERROR No lumi found?", file=sys.stderr)
982  sys.exit(1)
983 
984  ##########
985 
986  # And this is where the plotting starts.
987  print("Drawing things...")
988  ColorScheme.InitColors()
989 
990  #------------------------------
991  # Create the per-day delivered-lumi plots.
992  #------------------------------
993 
994  for year in years:
995 
996  print(" daily lumi plots for %d" % year)
997 
998  if not beam_energy_from_cfg:
999  beam_energy = beam_energy_defaults[accel_mode][year]
1000  cms_energy = 2. * beam_energy
1001  cms_energy_str = "???"
1002  if accel_mode == "PROTPHYS":
1003  width = 0
1004  if year == 2013:
1005  width = 2
1006  cms_energy_str = "%.*f TeV" % (width, 1.e-3 * cms_energy)
1007  elif accel_mode in ["IONPHYS", "PAPHYS"]:
1008  cms_energy_str = "%.2f TeV/nucleon" % \
1009  (1.e-3 * GetEnergyPerNucleonScaleFactor(accel_mode) * cms_energy)
1010 
1011  lumi_data = sorted(lumi_data_by_day_per_year[year])
1012 
1013  # NOTE: Tweak the time range a bit to force the bins to be
1014  # drawn from midday to midday.
1015  day_lo = AtMidnight(lumi_data.time_begin()) - \
1016  datetime.timedelta(seconds=12*60*60)
1017  day_hi = AtMidnight(lumi_data.time_end()) + \
1018  datetime.timedelta(seconds=12*60*60)
1019 
1020  #----------
1021 
1022  # Build the histograms.
1023  bin_edges = np.linspace(matplotlib.dates.date2num(day_lo),
1024  matplotlib.dates.date2num(day_hi),
1025  (day_hi - day_lo).days + 1)
1026  times_tmp = [AtMidnight(i) for i in lumi_data.times()]
1027  times = [matplotlib.dates.date2num(i) for i in times_tmp]
1028  # Delivered and recorded luminosity integrated per day.
1029  units = GetUnits(year, accel_mode, "cum_day")
1030  weights_del = lumi_data.lum_del(units)
1031  weights_rec = lumi_data.lum_rec(units)
1032  # Cumulative versions of the above.
1033  units = GetUnits(year, accel_mode, "cum_year")
1034  weights_del_for_cum = lumi_data.lum_del(units)
1035  weights_rec_for_cum = lumi_data.lum_rec(units)
1036  weights_cert_for_cum = lumi_data.lum_cert(units)
1037  # Maximum instantaneous delivered luminosity per day.
1038  units = GetUnits(year, accel_mode, "max_inst")
1039  weights_del_inst = lumi_data.lum_inst_max(units)
1040 
1041  # Figure out the time window of the data included for the plot
1042  # subtitles.
1043  time_begin = datetime.datetime.combine(lumi_data.time_begin(),
1044  datetime.time()) - \
1045  datetime.timedelta(days=.5)
1046  time_end = datetime.datetime.combine(lumi_data.time_end(),
1047  datetime.time()) + \
1048  datetime.timedelta(days=.5)
1049  str_begin = None
1050  str_end = None
1051  if sum(weights_del) > 0.:
1052  str_begin = lumi_data.time_begin().strftime(DATE_FMT_STR_OUT)
1053  str_end = lumi_data.time_end().strftime(DATE_FMT_STR_OUT)
1054 
1055  #----------
1056 
1057  # Loop over all color schemes.
1058  for color_scheme_name in color_scheme_names:
1059 
1060  color_scheme = ColorScheme(color_scheme_name)
1061  color_fill_del = color_scheme.color_fill_del
1062  color_fill_rec = color_scheme.color_fill_rec
1063  color_fill_cert = color_scheme.color_fill_cert
1064  color_fill_peak = color_scheme.color_fill_peak
1065  color_line_del = color_scheme.color_line_del
1066  color_line_rec = color_scheme.color_line_rec
1067  color_line_cert = color_scheme.color_line_cert
1068  color_line_peak = color_scheme.color_line_peak
1069  logo_name = color_scheme.logo_name
1070  file_suffix = color_scheme.file_suffix
1071 
1072  fig = plt.figure()
1073 
1074  #----------
1075 
1076  for type in ["lin", "log"]:
1077  is_log = (type == "log")
1078  log_setting = False
1079  if is_log:
1080  min_val = min(weights_del_inst)
1081  exp = math.floor(math.log10(min_val))
1082  log_setting = math.pow(10., exp)
1083 
1084  fig.clear()
1085  ax = fig.add_subplot(111)
1086 
1087  units = GetUnits(year, accel_mode, "max_inst")
1088 
1089  # Figure out the maximum instantaneous luminosity.
1090  max_inst = max(weights_del_inst)
1091 
1092  if sum(weights_del) > 0.:
1093 
1094  ax.hist(times, bin_edges, weights=weights_del_inst,
1095  histtype="stepfilled",
1096  log=log_setting,
1097  facecolor=color_fill_peak, edgecolor=color_line_peak,
1098  label="Max. inst. lumi.: %.2f %s" % \
1099  (max_inst, LatexifyUnits(units)))
1100 
1101  tmp_leg = ax.legend(loc="upper left",
1102  bbox_to_anchor=(0.025, 0., 1., .97),
1103  frameon=False)
1104  tmp_leg.legendHandles[0].set_visible(False)
1105  for t in tmp_leg.get_texts():
1106  t.set_font_properties(FONT_PROPS_TICK_LABEL)
1107 
1108  # Set titles and labels.
1109  fig.suptitle(r"CMS Peak Luminosity Per Day, " \
1110  "%s, %d, $\mathbf{\sqrt{s} =}$ %s" % \
1111  (particle_type_str, year, cms_energy_str),
1112  fontproperties=FONT_PROPS_SUPTITLE)
1113  ax.set_title("Data included from %s to %s UTC \n" % \
1114  (str_begin, str_end),
1115  fontproperties=FONT_PROPS_TITLE)
1116  ax.set_xlabel(r"Date (UTC)", fontproperties=FONT_PROPS_AX_TITLE)
1117  ax.set_ylabel(r"Peak Delivered Luminosity (%s)" % \
1118  LatexifyUnits(units),
1119  fontproperties=FONT_PROPS_AX_TITLE)
1120 
1121  # Add the logo.
1122  AddLogo(logo_name, ax)
1123  TweakPlot(fig, ax, (time_begin, time_end), True)
1124 
1125  log_suffix = ""
1126  if is_log:
1127  log_suffix = "_log"
1128  SavePlot(fig, "peak_lumi_per_day_%s_%d%s%s" % \
1129  (particle_type_str.lower(), year,
1130  log_suffix, file_suffix))
1131 
1132  #----------
1133 
1134  # The lumi-per-day plot.
1135  for type in ["lin", "log"]:
1136  is_log = (type == "log")
1137  log_setting = False
1138  if is_log:
1139  min_val = min(weights_rec)
1140  exp = math.floor(math.log10(min_val))
1141  log_setting = math.pow(10., exp)
1142 
1143  fig.clear()
1144  ax = fig.add_subplot(111)
1145 
1146  units = GetUnits(year, accel_mode, "cum_day")
1147 
1148  # Figure out the maximum delivered and recorded luminosities.
1149  max_del = max(weights_del)
1150  max_rec = max(weights_rec)
1151 
1152  if sum(weights_del) > 0.:
1153 
1154  ax.hist(times, bin_edges, weights=weights_del,
1155  histtype="stepfilled",
1156  log=log_setting,
1157  facecolor=color_fill_del, edgecolor=color_line_del,
1158  label="LHC Delivered, max: %.1f %s/day" % \
1159  (max_del, LatexifyUnits(units)))
1160  ax.hist(times, bin_edges, weights=weights_rec,
1161  histtype="stepfilled",
1162  log=log_setting,
1163  facecolor=color_fill_rec, edgecolor=color_line_rec,
1164  label="CMS Recorded, max: %.1f %s/day" % \
1165  (max_rec, LatexifyUnits(units)))
1166  leg = ax.legend(loc="upper left", bbox_to_anchor=(0.125, 0., 1., 1.01),
1167  frameon=False)
1168  for t in leg.get_texts():
1169  t.set_font_properties(FONT_PROPS_TICK_LABEL)
1170  # Set titles and labels.
1171  fig.suptitle(r"CMS Integrated Luminosity Per Day, " \
1172  "%s, %d, $\mathbf{\sqrt{s} =}$ %s" % \
1173  (particle_type_str, year, cms_energy_str),
1174  fontproperties=FONT_PROPS_SUPTITLE)
1175  ax.set_title("Data included from %s to %s UTC \n" % \
1176  (str_begin, str_end),
1177  fontproperties=FONT_PROPS_TITLE)
1178  ax.set_xlabel(r"Date (UTC)", fontproperties=FONT_PROPS_AX_TITLE)
1179  ax.set_ylabel(r"Integrated Luminosity (%s/day)" % \
1180  LatexifyUnits(units),
1181  fontproperties=FONT_PROPS_AX_TITLE)
1182 
1183  # Add the logo.
1184  AddLogo(logo_name, ax)
1185  TweakPlot(fig, ax, (time_begin, time_end), True)
1186 
1187  log_suffix = ""
1188  if is_log:
1189  log_suffix = "_log"
1190  SavePlot(fig, "int_lumi_per_day_%s_%d%s%s" % \
1191  (particle_type_str.lower(), year,
1192  log_suffix, file_suffix))
1193 
1194  #----------
1195 
1196  # Now for the cumulative plot.
1197  units = GetUnits(year, accel_mode, "cum_year")
1198 
1199  # Figure out the totals.
1200  min_del = min(weights_del_for_cum)
1201  tot_del = sum(weights_del_for_cum)
1202  tot_rec = sum(weights_rec_for_cum)
1203  tot_cert = sum(weights_cert_for_cum)
1204 
1205  for type in ["lin", "log"]:
1206  is_log = (type == "log")
1207  log_setting = False
1208  if is_log:
1209  min_val = min(weights_del_for_cum)
1210  exp = math.floor(math.log10(min_val))
1211  log_setting = math.pow(10., exp)
1212 
1213  fig.clear()
1214  ax = fig.add_subplot(111)
1215 
1216  if sum(weights_del) > 0.:
1217 
1218  ax.hist(times, bin_edges, weights=weights_del_for_cum,
1219  histtype="stepfilled", cumulative=True,
1220  log=log_setting,
1221  facecolor=color_fill_del, edgecolor=color_line_del,
1222  label="LHC Delivered: %.2f %s" % \
1223  (tot_del, LatexifyUnits(units)))
1224  ax.hist(times, bin_edges, weights=weights_rec_for_cum,
1225  histtype="stepfilled", cumulative=True,
1226  log=log_setting,
1227  facecolor=color_fill_rec, edgecolor=color_line_rec,
1228  label="CMS Recorded: %.2f %s" % \
1229  (tot_rec, LatexifyUnits(units)))
1230  if sum(weights_cert_for_cum) > 0.:
1231  ax.hist(times, bin_edges, weights=weights_cert_for_cum,
1232  histtype="stepfilled", cumulative=True,
1233  log=log_setting,
1234  facecolor=color_fill_cert, edgecolor=color_line_cert,
1235  label="CMS Validated: %.2f %s" % \
1236  (tot_cert, LatexifyUnits(units)))
1237  leg = ax.legend(loc="upper left",
1238  bbox_to_anchor=(0.125, 0., 1., 1.01),
1239  frameon=False)
1240  for t in leg.get_texts():
1241  t.set_font_properties(FONT_PROPS_TICK_LABEL)
1242 
1243  # Set titles and labels.
1244  fig.suptitle(r"CMS Integrated Luminosity, " \
1245  r"%s, %d, $\mathbf{\sqrt{s} =}$ %s" % \
1246  (particle_type_str, year, cms_energy_str),
1247  fontproperties=FONT_PROPS_SUPTITLE)
1248  ax.set_title("Data included from %s to %s UTC \n" % \
1249  (str_begin, str_end),
1250  fontproperties=FONT_PROPS_TITLE)
1251  ax.set_xlabel(r"Date (UTC)", fontproperties=FONT_PROPS_AX_TITLE)
1252  ax.set_ylabel(r"Total Integrated Luminosity (%s)" % \
1253  LatexifyUnits(units),
1254  fontproperties=FONT_PROPS_AX_TITLE)
1255 
1256  # Add "CMS Preliminary" to the plot.
1257  if json_file_name:
1258  ax.text(0.05, 0.7, "CMS Preliminary",
1259  verticalalignment="center", horizontalalignment="left",
1260  transform = ax.transAxes, fontsize=15)
1261 
1262  # Add the logo.
1263  AddLogo(logo_name, ax)
1264  TweakPlot(fig, ax, (time_begin, time_end),
1265  add_extra_head_room=is_log)
1266 
1267  log_suffix = ""
1268  if is_log:
1269  log_suffix = "_log"
1270  SavePlot(fig, "int_lumi_per_day_cumulative_%s_%d%s%s" % \
1271  (particle_type_str.lower(), year,
1272  log_suffix, file_suffix))
1273 
1274  #------------------------------
1275  # Create the per-week delivered-lumi plots.
1276  #------------------------------
1277 
1278  for year in years:
1279 
1280  print(" weekly lumi plots for %d" % year)
1281 
1282  if not beam_energy_from_cfg:
1283  beam_energy = beam_energy_defaults[accel_mode][year]
1284  cms_energy = 2. * beam_energy
1285  cms_energy_str = "???"
1286  if accel_mode == "PROTPHYS":
1287  width = 0
1288  if year == 2013:
1289  width = 2
1290  cms_energy_str = "%.*f TeV" % (width, 1.e-3 * cms_energy)
1291  elif accel_mode in ["IONPHYS", "PAPHYS"]:
1292  cms_energy_str = "%.2f TeV/nucleon" % \
1293  (1.e-3 * GetEnergyPerNucleonScaleFactor(accel_mode) * cms_energy)
1294 
1295  lumi_data = sorted(lumi_data_by_week_per_year[year])
1296 
1297  # NOTE: Tweak the time range a bit to force the bins to be
1298  # split at the middle of the weeks.
1299  week_lo = AtMidWeek(lumi_data.time_begin()) - \
1300  datetime.timedelta(days=3, seconds=12*60*60)
1301  week_hi = AtMidWeek(lumi_data.time_end()) + \
1302  datetime.timedelta(days=3, seconds=12*60*60)
1303 
1304  #----------
1305 
1306  # Build the histograms.
1307  num_weeks = week_hi.isocalendar()[1] - week_lo.isocalendar()[1] + 1
1308  bin_edges = np.linspace(matplotlib.dates.date2num(week_lo),
1309  matplotlib.dates.date2num(week_hi),
1310  num_weeks)
1311  times_tmp = [AtMidWeek(i) for i in lumi_data.times()]
1312  times = [matplotlib.dates.date2num(i) for i in times_tmp]
1313  # Delivered and recorded luminosity integrated per week.
1314  units = GetUnits(year, accel_mode, "cum_week")
1315  weights_del = lumi_data.lum_del(units)
1316  weights_rec = lumi_data.lum_rec(units)
1317  # Cumulative versions of the above.
1318  units = GetUnits(year, accel_mode, "cum_year")
1319  weights_del_for_cum = lumi_data.lum_del(units)
1320  weights_rec_for_cum = lumi_data.lum_rec(units)
1321  # Maximum instantaneous delivered luminosity per week.
1322  units = GetUnits(year, accel_mode, "max_inst")
1323  weights_del_inst = lumi_data.lum_inst_max(units)
1324 
1325  # Figure out the time window of the data included for the plot
1326  # subtitles.
1327  str_begin = None
1328  str_end = None
1329  if sum(weights_del) > 0.:
1330  str_begin = lumi_data.time_begin().strftime(DATE_FMT_STR_OUT)
1331  str_end = lumi_data.time_end().strftime(DATE_FMT_STR_OUT)
1332 
1333  #----------
1334 
1335  # Loop over all color schemes.
1336  for color_scheme_name in color_scheme_names:
1337 
1338  print(" color scheme '%s'" % color_scheme_name)
1339 
1340  color_scheme = ColorScheme(color_scheme_name)
1341  color_fill_del = color_scheme.color_fill_del
1342  color_fill_rec = color_scheme.color_fill_rec
1343  color_fill_peak = color_scheme.color_fill_peak
1344  color_line_del = color_scheme.color_line_del
1345  color_line_rec = color_scheme.color_line_rec
1346  color_line_peak = color_scheme.color_line_peak
1347  logo_name = color_scheme.logo_name
1348  file_suffix = color_scheme.file_suffix
1349 
1350  fig = plt.figure()
1351 
1352  #----------
1353 
1354  for type in ["lin", "log"]:
1355  is_log = (type == "log")
1356  log_setting = False
1357  if is_log:
1358  min_val = min(weights_del_inst)
1359  exp = math.floor(math.log10(min_val))
1360  log_setting = math.pow(10., exp)
1361 
1362  fig.clear()
1363  ax = fig.add_subplot(111)
1364 
1365  units = GetUnits(year, accel_mode, "max_inst")
1366 
1367  # Figure out the maximum instantaneous luminosity.
1368  max_inst = max(weights_del_inst)
1369 
1370  if sum(weights_del) > 0.:
1371 
1372  ax.hist(times, bin_edges, weights=weights_del_inst,
1373  histtype="stepfilled",
1374  log=log_setting,
1375  facecolor=color_fill_peak, edgecolor=color_line_peak,
1376  label="Max. inst. lumi.: %.2f %s" % \
1377  (max_inst, LatexifyUnits(units)))
1378 
1379  tmp_leg = ax.legend(loc="upper left",
1380  bbox_to_anchor=(0.025, 0., 1., .97),
1381  frameon=False)
1382  tmp_leg.legendHandles[0].set_visible(False)
1383  for t in tmp_leg.get_texts():
1384  t.set_font_properties(FONT_PROPS_TICK_LABEL)
1385 
1386  # Set titles and labels.
1387  fig.suptitle(r"CMS Peak Luminosity Per Week, " \
1388  "%s, %d, $\mathbf{\sqrt{s} =}$ %s" % \
1389  (particle_type_str, year, cms_energy_str),
1390  fontproperties=FONT_PROPS_SUPTITLE)
1391  ax.set_title("Data included from %s to %s UTC \n" % \
1392  (str_begin, str_end),
1393  fontproperties=FONT_PROPS_TITLE)
1394  ax.set_xlabel(r"Date (UTC)",
1395  fontproperties=FONT_PROPS_AX_TITLE)
1396  ax.set_ylabel(r"Peak Delivered Luminosity (%s)" % \
1397  LatexifyUnits(units),
1398  fontproperties=FONT_PROPS_AX_TITLE)
1399 
1400  # Add the logo.
1401  AddLogo(logo_name, ax)
1402  TweakPlot(fig, ax, (week_lo, week_hi), True)
1403 
1404  log_suffix = ""
1405  if is_log:
1406  log_suffix = "_log"
1407  SavePlot(fig, "peak_lumi_per_week_%s_%d%s%s" % \
1408  (particle_type_str.lower(), year,
1409  log_suffix, file_suffix))
1410 
1411  #----------
1412 
1413  # The lumi-per-week plot.
1414  for type in ["lin", "log"]:
1415  is_log = (type == "log")
1416  log_setting = False
1417  if is_log:
1418  min_val = min(weights_rec)
1419  exp = math.floor(math.log10(min_val))
1420  log_setting = math.pow(10., exp)
1421 
1422  fig.clear()
1423  ax = fig.add_subplot(111)
1424 
1425  units = GetUnits(year, accel_mode, "cum_week")
1426 
1427  # Figure out the maximum delivered and recorded luminosities.
1428  max_del = max(weights_del)
1429  max_rec = max(weights_rec)
1430 
1431  if sum(weights_del) > 0.:
1432 
1433  ax.hist(times, bin_edges, weights=weights_del,
1434  histtype="stepfilled",
1435  log=log_setting,
1436  facecolor=color_fill_del, edgecolor=color_line_del,
1437  label="LHC Delivered, max: %.1f %s/week" % \
1438  (max_del, LatexifyUnits(units)))
1439  ax.hist(times, bin_edges, weights=weights_rec,
1440  histtype="stepfilled",
1441  log=log_setting,
1442  facecolor=color_fill_rec, edgecolor=color_line_rec,
1443  label="CMS Recorded, max: %.1f %s/week" % \
1444  (max_rec, LatexifyUnits(units)))
1445  leg = ax.legend(loc="upper left", bbox_to_anchor=(0.125, 0., 1., 1.01),
1446  frameon=False)
1447  for t in leg.get_texts():
1448  t.set_font_properties(FONT_PROPS_TICK_LABEL)
1449 
1450  # Set titles and labels.
1451  fig.suptitle(r"CMS Integrated Luminosity Per Week, " \
1452  "%s, %d, $\mathbf{\sqrt{s} =}$ %s" % \
1453  (particle_type_str, year, cms_energy_str),
1454  fontproperties=FONT_PROPS_SUPTITLE)
1455  ax.set_title("Data included from %s to %s UTC \n" % \
1456  (str_begin, str_end),
1457  fontproperties=FONT_PROPS_TITLE)
1458  ax.set_xlabel(r"Date (UTC)", fontproperties=FONT_PROPS_AX_TITLE)
1459  ax.set_ylabel(r"Integrated Luminosity (%s/week)" % \
1460  LatexifyUnits(units),
1461  fontproperties=FONT_PROPS_AX_TITLE)
1462 
1463  # Add the logo.
1464  AddLogo(logo_name, ax)
1465  TweakPlot(fig, ax, (week_lo, week_hi), True)
1466 
1467  log_suffix = ""
1468  if is_log:
1469  log_suffix = "_log"
1470  SavePlot(fig, "int_lumi_per_week_%s_%d%s%s" % \
1471  (particle_type_str.lower(), year,
1472  log_suffix, file_suffix))
1473 
1474  #----------
1475 
1476  # Now for the cumulative plot.
1477  units = GetUnits(year, accel_mode, "cum_year")
1478 
1479  # Figure out the totals.
1480  min_del = min(weights_del_for_cum)
1481  tot_del = sum(weights_del_for_cum)
1482  tot_rec = sum(weights_rec_for_cum)
1483 
1484  for type in ["lin", "log"]:
1485  is_log = (type == "log")
1486  log_setting = False
1487  if is_log:
1488  min_val = min(weights_del_for_cum)
1489  exp = math.floor(math.log10(min_val))
1490  log_setting = math.pow(10., exp)
1491 
1492  fig.clear()
1493  ax = fig.add_subplot(111)
1494 
1495  if sum(weights_del) > 0.:
1496 
1497  ax.hist(times, bin_edges, weights=weights_del_for_cum,
1498  histtype="stepfilled", cumulative=True,
1499  log=log_setting,
1500  facecolor=color_fill_del, edgecolor=color_line_del,
1501  label="LHC Delivered: %.2f %s" % \
1502  (tot_del, LatexifyUnits(units)))
1503  ax.hist(times, bin_edges, weights=weights_rec_for_cum,
1504  histtype="stepfilled", cumulative=True,
1505  log=log_setting,
1506  facecolor=color_fill_rec, edgecolor=color_line_rec,
1507  label="CMS Recorded: %.2f %s" % \
1508  (tot_rec, LatexifyUnits(units)))
1509  leg = ax.legend(loc="upper left", bbox_to_anchor=(0.125, 0., 1., 1.01),
1510  frameon=False)
1511  for t in leg.get_texts():
1512  t.set_font_properties(FONT_PROPS_TICK_LABEL)
1513 
1514  # Set titles and labels.
1515  fig.suptitle(r"CMS Integrated Luminosity, " \
1516  r"%s, %d, $\mathbf{\sqrt{s} =}$ %s" % \
1517  (particle_type_str, year, cms_energy_str),
1518  fontproperties=FONT_PROPS_SUPTITLE)
1519  ax.set_title("Data included from %s to %s UTC \n" % \
1520  (str_begin, str_end),
1521  fontproperties=FONT_PROPS_TITLE)
1522  ax.set_xlabel(r"Date (UTC)", fontproperties=FONT_PROPS_AX_TITLE)
1523  ax.set_ylabel(r"Total Integrated Luminosity (%s)" % \
1524  LatexifyUnits(units),
1525  fontproperties=FONT_PROPS_AX_TITLE)
1526 
1527  # Add the logo.
1528  AddLogo(logo_name, ax)
1529  TweakPlot(fig, ax, (week_lo, week_hi),
1530  add_extra_head_room=is_log)
1531 
1532  log_suffix = ""
1533  if is_log:
1534  log_suffix = "_log"
1535  SavePlot(fig, "int_lumi_per_week_cumulative_%s_%d%s%s" % \
1536  (particle_type_str.lower(), year,
1537  log_suffix, file_suffix))
1538 
1539  plt.close()
1540 
1541  #----------
1542 
1543  # Now the cumulative plot showing all years together.
1544  if len(years) > 1:
1545  print(" cumulative luminosity for %s together" % ", ".join([str(i) for i in years]))
1546 
1547  def PlotAllYears(lumi_data_by_day_per_year, mode):
1548  """Mode 1: years side-by-side, mode 2: years overlaid."""
1549 
1550  units = GetUnits(years[-1], accel_mode, "cum_year")
1551 
1552  scale_factor_2010 = 100.
1553 
1554  # Loop over all color schemes and plot.
1555  for color_scheme_name in color_scheme_names:
1556 
1557  print(" color scheme '%s'" % color_scheme_name)
1558 
1559  color_scheme = ColorScheme(color_scheme_name)
1560  color_by_year = color_scheme.color_by_year
1561  logo_name = color_scheme.logo_name
1562  file_suffix = color_scheme.file_suffix
1563 
1564  for type in ["lin", "log"]:
1565  is_log = (type == "log")
1566 
1567  if mode == 1:
1568  aspect_ratio = matplotlib.figure.figaspect(1. / 2.5)
1569  fig = plt.figure(figsize=aspect_ratio)
1570  else:
1571  fig = plt.figure()
1572  ax = fig.add_subplot(111)
1573 
1574  time_begin_ultimate = lumi_data_by_day_per_year[years[0]].time_begin()
1575  str_begin_ultimate = time_begin_ultimate.strftime(DATE_FMT_STR_OUT)
1576  for (year_index, year) in enumerate(years):
1577 
1578  lumi_data = sorted(lumi_data_by_day_per_year[year])
1579  times_tmp = [AtMidnight(i) for i in lumi_data.times()]
1580  # For the plots showing all years overlaid, shift
1581  # all but the first year forward.
1582  # NOTE: Years list is supposed to be sorted.
1583  if mode == 2:
1584  if year_index > 0:
1585  for y in years[:year_index]:
1586  num_days = NumDaysInYear(y)
1587  time_shift = datetime.timedelta(days=num_days)
1588  times_tmp = [(i - time_shift) \
1589  for i in times_tmp]
1590  times = [matplotlib.dates.date2num(i) for i in times_tmp]
1591  # DEBUG DEBUG DEBUG
1592  for i in range(len(times) - 1):
1593  assert times[i] < times[i + 1]
1594  # DEBUG DEBUG DEBUG end
1595  weights_del = lumi_data.lum_del(units)
1596  weights_del_cum = [0.] * len(weights_del)
1597  tot_del = 0.
1598  for (i, val) in enumerate(weights_del):
1599  tot_del += val
1600  weights_del_cum[i] = tot_del
1601  if not beam_energy_from_cfg:
1602  beam_energy = beam_energy_defaults[accel_mode][year]
1603  cms_energy = 2. * beam_energy
1604  cms_energy_str = "???"
1605  if accel_mode == "PROTPHYS":
1606  width = 0
1607  if year == 2013:
1608  width = 2
1609  cms_energy_str = "%.*f TeV" % \
1610  (width, 1.e-3 * cms_energy)
1611  elif accel_mode in ["IONPHYS", "PAPHYS"]:
1612  cms_energy_str = "%.2f TeV/nucleon" % \
1613  (1.e-3 * GetEnergyPerNucleonScaleFactor(accel_mode) * cms_energy)
1614 
1615  # NOTE: Special case for 2010.
1616  label = None
1617  if year == 2010:
1618  label = r"%d, %s, %.1f %s" % \
1619  (year, cms_energy_str,
1620  1.e3 * tot_del,
1621  LatexifyUnits("pb^{-1}"))
1622  else:
1623  label = r"%d, %s, %.1f %s" % \
1624  (year, cms_energy_str, tot_del,
1625  LatexifyUnits(units))
1626 
1627  # NOTE: Special case for 2010
1628  weights_tmp = None
1629  if year == 2010:
1630  weights_tmp = [scale_factor_2010 * i \
1631  for i in weights_del_cum]
1632  else:
1633  weights_tmp = weights_del_cum
1634  ax.plot(times, weights_tmp,
1635  color=color_by_year[year],
1636  marker="none", linestyle="solid",
1637  linewidth=4,
1638  label=label)
1639  if is_log:
1640  ax.set_yscale("log")
1641 
1642  # NOTE: Special case for 2010.
1643  if year == 2010:
1644  ax.annotate(r"$\times$ %.0f" % scale_factor_2010,
1645  xy=(times[-1], weights_tmp[-1]),
1646  xytext=(5., -2.),
1647  xycoords="data", textcoords="offset points")
1648 
1649  # BUG BUG BUG
1650  # Needs work...
1651  time_begin = lumi_data.time_begin()
1652  time_end = lumi_data.time_end()
1653  str_begin = time_begin.strftime(DATE_FMT_STR_OUT)
1654  str_end = time_end.strftime(DATE_FMT_STR_OUT)
1655  if mode == 1:
1656  time_begin = datetime.datetime(years[0], 1, 1, 0, 0, 0)
1657  time_end = datetime.datetime(years[-1], 12, 31, 23, 59,59)
1658  else:
1659  time_begin = datetime.datetime(years[0], 1, 1, 0, 0, 0)
1660  time_end = datetime.datetime(years[0], 12, 31, 23, 59,59)
1661  # BUG BUG BUG end
1662 
1663  num_cols = None
1664  if mode == 1:
1665  num_cols = len(years)
1666  tmp_x = 0.095
1667  tmp_y = .95
1668  else:
1669  num_cols = 1
1670  tmp_x = 0.175
1671  tmp_y = 1.01
1672  leg = ax.legend(loc="upper left", bbox_to_anchor=(tmp_x, 0., 1., tmp_y),
1673  frameon=False, ncol=num_cols)
1674  for t in leg.get_texts():
1675  t.set_font_properties(FONT_PROPS_TICK_LABEL)
1676 
1677  # Set titles and labels.
1678  fig.suptitle(r"CMS Integrated Luminosity, %s" % particle_type_str,
1679  fontproperties=FONT_PROPS_SUPTITLE)
1680  ax.set_title("Data included from %s to %s UTC \n" % \
1681 # (str_begin, str_end),
1682  (str_begin_ultimate, str_end),
1683  fontproperties=FONT_PROPS_TITLE)
1684  ax.set_xlabel(r"Date (UTC)", fontproperties=FONT_PROPS_AX_TITLE)
1685  ax.set_ylabel(r"Total Integrated Luminosity (%s)" % \
1686  LatexifyUnits(units),
1687  fontproperties=FONT_PROPS_AX_TITLE)
1688 
1689  # Add the logo.
1690  zoom = 1.7
1691  if mode == 1:
1692  zoom = .95
1693  AddLogo(logo_name, ax, zoom=zoom)
1694  extra_head_room = 0
1695  if is_log:
1696  if mode == 1:
1697  extra_head_room = 1
1698  elif mode == 2:
1699  extra_head_room = 2
1700 # TweakPlot(fig, ax, (time_begin, time_end),
1701  TweakPlot(fig, ax, (time_begin_ultimate, time_end),
1702  add_extra_head_room=extra_head_room)
1703 
1704  log_suffix = ""
1705  if is_log:
1706  log_suffix = "_log"
1707  SavePlot(fig, "int_lumi_cumulative_%s_%d%s%s" % \
1708  (particle_type_str.lower(), mode,
1709  log_suffix, file_suffix))
1710 
1711  for mode in [1, 2]:
1712  print(" mode %d" % mode)
1713  PlotAllYears(lumi_data_by_day_per_year, mode)
1714 
1715  plt.close()
1716 
1717  #----------
1718 
1719  # Now the peak lumi plot showing all years together.
1720  if len(years) > 1:
1721  print(" peak luminosity for %s together" % ", ".join([str(i) for i in years]))
1722 
1723  units = GetUnits(years[-1], accel_mode, "max_inst")
1724 
1725  scale_factor_2010 = 10.
1726 
1727  # Loop over all color schemes and plot.
1728  for color_scheme_name in color_scheme_names:
1729 
1730  print(" color scheme '%s'" % color_scheme_name)
1731 
1732  color_scheme = ColorScheme(color_scheme_name)
1733  color_by_year = color_scheme.color_by_year
1734  logo_name = color_scheme.logo_name
1735  file_suffix = color_scheme.file_suffix
1736 
1737  for type in ["lin", "log"]:
1738  is_log = (type == "log")
1739 
1740  aspect_ratio = matplotlib.figure.figaspect(1. / 2.5)
1741  fig = plt.figure(figsize=aspect_ratio)
1742  ax = fig.add_subplot(111)
1743 
1744  time_begin_ultimate = lumi_data_by_day_per_year[years[0]].time_begin()
1745  str_begin_ultimate = time_begin_ultimate.strftime(DATE_FMT_STR_OUT)
1746  for (year_index, year) in enumerate(years):
1747 
1748  lumi_data = sorted(lumi_data_by_day_per_year[year])
1749  times_tmp = [AtMidnight(i) for i in lumi_data.times()]
1750  times = [matplotlib.dates.date2num(i) for i in times_tmp]
1751  # DEBUG DEBUG DEBUG
1752  for i in range(len(times) - 1):
1753  assert times[i] < times[i + 1]
1754  # DEBUG DEBUG DEBUG end
1755  weights_inst = lumi_data.lum_inst_max(units)
1756  max_inst = max(weights_inst)
1757  if not beam_energy_from_cfg:
1758  beam_energy = beam_energy_defaults[accel_mode][year]
1759  cms_energy = 2. * beam_energy
1760  cms_energy_str = "???"
1761  if accel_mode == "PROTPHYS":
1762  width = 0
1763  if year == 2013:
1764  width = 2
1765  cms_energy_str = "%.*f TeV" % \
1766  (width, 1.e-3 * cms_energy)
1767  elif accel_mode in ["IONPHYS", "PAPHYS"]:
1768  cms_energy_str = "%.2f TeV/nucleon" % \
1769  (1.e-3 * GetEnergyPerNucleonScaleFactor(accel_mode) * cms_energy)
1770 
1771  # NOTE: Special case for 2010.
1772  label = None
1773  if year == 2010:
1774  label = r"%d, %s, max. %.1f %s" % \
1775  (year, cms_energy_str,
1776  1.e3 * max_inst,
1777  LatexifyUnits("Hz/ub"))
1778  else:
1779  label = r"%d, %s, max. %.1f %s" % \
1780  (year, cms_energy_str, max_inst,
1781  LatexifyUnits(units))
1782 
1783  # NOTE: Special case for 2010
1784  weights_tmp = None
1785  if year == 2010:
1786  weights_tmp = [scale_factor_2010 * i \
1787  for i in weights_inst]
1788  else:
1789  weights_tmp = weights_inst
1790  ax.plot(times, weights_tmp,
1791  color=color_by_year[year],
1792  marker=".", markersize=8.,
1793  linestyle="none",
1794  label=label)
1795  if is_log:
1796  ax.set_yscale("log")
1797 
1798  # NOTE: Special case for 2010.
1799  if year == 2010:
1800  ax.annotate(r"$\times$ %.0f" % scale_factor_2010,
1801  xy=(times[-1], max(weights_tmp)),
1802  xytext=(5., -2.),
1803  xycoords="data", textcoords="offset points")
1804 
1805  # BUG BUG BUG
1806  # Needs work...
1807  time_begin = lumi_data.time_begin()
1808  time_end = lumi_data.time_end()
1809  str_begin = time_begin.strftime(DATE_FMT_STR_OUT)
1810  str_end = time_end.strftime(DATE_FMT_STR_OUT)
1811  time_begin = datetime.datetime(years[0], 1, 1, 0, 0, 0)
1812  time_end = datetime.datetime(years[-1], 12, 31, 23, 59,59)
1813  # BUG BUG BUG end
1814 
1815  num_cols = None
1816  num_cols = len(years) - 2
1817  tmp_x = .09
1818  tmp_y = .97
1819  leg = ax.legend(loc="upper left",
1820  bbox_to_anchor=(tmp_x, 0., 1., tmp_y),
1821  labelspacing=.2,
1822  columnspacing=.2,
1823  frameon=False, ncol=num_cols)
1824  for t in leg.get_texts():
1825  t.set_font_properties(FONT_PROPS_TICK_LABEL)
1826 
1827  # Set titles and labels.
1828  fig.suptitle(r"CMS Peak Luminosity Per Day, %s" % particle_type_str,
1829  fontproperties=FONT_PROPS_SUPTITLE)
1830  ax.set_title("Data included from %s to %s UTC \n" % \
1831 # (str_begin, str_end),
1832  (str_begin_ultimate, str_end),
1833  fontproperties=FONT_PROPS_TITLE)
1834  ax.set_xlabel(r"Date (UTC)", fontproperties=FONT_PROPS_AX_TITLE)
1835  ax.set_ylabel(r"Peak Delivered Luminosity (%s)" % \
1836  LatexifyUnits(units),
1837  fontproperties=FONT_PROPS_AX_TITLE)
1838 
1839  # Add the logo.
1840  zoom = .97
1841  AddLogo(logo_name, ax, zoom=zoom)
1842  head_room = 2.
1843  if is_log:
1844  head_room = 2.
1845 # TweakPlot(fig, ax, (time_begin, time_end),
1846  TweakPlot(fig, ax, (time_begin_ultimate, time_end),
1847  add_extra_head_room=head_room)
1848 
1849  log_suffix = ""
1850  if is_log:
1851  log_suffix = "_log"
1852  SavePlot(fig, "peak_lumi_%s%s%s" % \
1853  (particle_type_str.lower(),
1854  log_suffix, file_suffix))
1855 
1856  #----------
1857 
1858  plt.close()
1859 
1860  ##########
1861 
1862  print("Done")
1863 
1864 ######################################################################
def __init__(self, line, json_file_name=None)
def LatexifyUnits(units_in)
def PlotAllYears(lumi_data_by_day_per_year, mode)
S & print(S &os, JobReport::InputFile const &f)
Definition: JobReport.cc:66
def checkCertification(run_number, ls)
def TweakPlot(fig, ax, time_range, add_extra_head_room=False)
T min(T a, T b)
Definition: MathUtil.h:58
void add(std::map< std::string, TH1 * > &h, TH1 *hist)
static std::string join(char **cmd)
Definition: RemoteFile.cc:18
def loadCertificationJSON(json_file_name)
def CacheFilePath(cache_file_dir, day=None)
def AddLogo(logo_name, ax, zoom=1.2)
def GetUnits(year, accel_mode, mode)
#define str(s)
def SavePlot(fig, file_name_base)
double split
Definition: MVATrainer.cc:139
How EventSelector::AcceptEvent() decides whether to accept an event for output otherwise it is excluding the probing of A single or multiple positive and the trigger will pass if any such matching triggers are PASS or EXCEPTION[A criterion thatmatches no triggers at all is detected and causes a throw.] A single negative with an expectation of appropriate bit checking in the decision and the trigger will pass if any such matching triggers are FAIL or EXCEPTION A wildcarded negative criterion that matches more than one trigger in the trigger list("!*","!HLTx*"if it matches 2 triggers or more) will accept the event if all the matching triggers are FAIL.It will reject the event if any of the triggers are PASS or EXCEPTION(this matches the behavior of"!*"before the partial wildcard feature was incorporated).Triggers which are in the READY state are completely ignored.(READY should never be returned since the trigger paths have been run