CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
validation.py
Go to the documentation of this file.
1 import os
2 import re
3 import sys
4 import shutil
5 import subprocess
6 
7 import ROOT
8 ROOT.gROOT.SetBatch(True)
9 ROOT.PyConfig.IgnoreCommandLineOptions = True
10 
11 import plotting
12 
13 # Mapping from releases to GlobalTags
14 _globalTags = {
15  "CMSSW_6_2_0_SLHC15": {"UPG2019withGEM": "DES19_62_V8", "UPG2023SHNoTaper": "DES23_62_V1"},
16  "CMSSW_6_2_0_SLHC17": {"UPG2019withGEM": "DES19_62_V8", "UPG2023SHNoTaper": "DES23_62_V1"},
17  "CMSSW_6_2_0_SLHC20": {"UPG2019withGEM": "DES19_62_V8", "UPG2023SHNoTaper": "DES23_62_V1"},
18  "CMSSW_7_0_0_AlcaCSA14": {"default": "POSTLS170_V5_AlcaCSA14", "fullsim_50ns": "POSTLS170_V6_AlcaCSA14"},
19  "CMSSW_7_0_7_pmx": {"default": "PLS170_V7AN1", "fullsim_50ns": "PLS170_V6AN1"},
20  "CMSSW_7_0_9_patch3": {"default": "PLS170_V7AN2", "fullsim_50ns": "PLS170_V6AN2"},
21  "CMSSW_7_0_9_patch3_Premix": {"default": "PLS170_V7AN2", "fullsim_50ns": "PLS170_V6AN2"},
22  "CMSSW_7_1_0": {"default": "POSTLS171_V15", "fullsim_50ns": "POSTLS171_V16"},
23  "CMSSW_7_1_9": {"default": "POSTLS171_V17", "fullsim_50ns": "POSTLS171_V18"},
24  "CMSSW_7_1_9_patch2": {"default": "POSTLS171_V17", "fullsim_50ns": "POSTLS171_V18"},
25  "CMSSW_7_1_10_patch2": {"default": "MCRUN2_71_V1", "fullsim_50ns": "MCRUN2_71_V0"},
26  "CMSSW_7_2_0_pre5": {"default": "POSTLS172_V3", "fullsim_50ns": "POSTLS172_V4"},
27  "CMSSW_7_2_0_pre7": {"default": "PRE_LS172_V11", "fullsim_50ns": "PRE_LS172_V12"},
28  "CMSSW_7_2_0_pre8": {"default": "PRE_LS172_V15", "fullsim_50ns": "PRE_LS172_V16"},
29  "CMSSW_7_2_0": {"default": "PRE_LS172_V15", "fullsim_50ns": "PRE_LS172_V16"},
30  "CMSSW_7_2_0_PHYS14": {"default": "PHYS14_25_V1_Phys14"},
31  "CMSSW_7_2_2_patch1": {"default": "MCRUN2_72_V1", "fullsim_50ns": "MCRUN2_72_V0"},
32  "CMSSW_7_2_2_patch1_Fall14DR": {"default": "MCRUN2_72_V3_71XGENSIM"},
33 # "CMSSW_7_3_0_pre1": {"default": "PRE_LS172_V15", "fullsim_25ns": "PRE_LS172_V15_OldPU", "fullsim_50ns": "PRE_LS172_V16_OldPU"},
34  "CMSSW_7_3_0_pre1": {"default": "PRE_LS172_V15", "fullsim_50ns": "PRE_LS172_V16"},
35 # "CMSSW_7_3_0_pre2": {"default": "MCRUN2_73_V1_OldPU", "fullsim_50ns": "MCRUN2_73_V0_OldPU"},
36  "CMSSW_7_3_0_pre2": {"default": "MCRUN2_73_V1", "fullsim_50ns": "MCRUN2_73_V0"},
37  "CMSSW_7_3_0_pre3": {"default": "MCRUN2_73_V5", "fullsim_50ns": "MCRUN2_73_V4"},
38  "CMSSW_7_3_0": {"default": "MCRUN2_73_V7", "fullsim_50ns": "MCRUN2_73_V6"},
39  "CMSSW_7_3_0_71XGENSIM": {"default": "MCRUN2_73_V7_71XGENSIM"},
40  "CMSSW_7_3_0_71XGENSIM_FIXGT": {"default": "MCRUN2_73_V9_71XGENSIM_FIXGT"},
41  "CMSSW_7_3_1_patch1": {"default": "MCRUN2_73_V9", "fastsim": "MCRUN2_73_V7"},
42  "CMSSW_7_3_1_patch1_GenSim_7113": {"default": "MCRUN2_73_V9_GenSim_7113"},
43  "CMSSW_7_3_3": {"default": "MCRUN2_73_V11", "fullsim_50ns": "MCRUN2_73_V10", "fastsim": "MCRUN2_73_V13"},
44  "CMSSW_7_4_0_pre1": {"default": "MCRUN2_73_V5", "fullsim_50ns": "MCRUN2_73_V4"},
45  "CMSSW_7_4_0_pre2": {"default": "MCRUN2_73_V7", "fullsim_50ns": "MCRUN2_73_V6"},
46  "CMSSW_7_4_0_pre2_73XGENSIM": {"default": "MCRUN2_73_V7_73XGENSIM_Pythia6", "fullsim_50ns": "MCRUN2_73_V6_73XGENSIM_Pythia6"},
47  "CMSSW_7_4_0_pre5": {"default": "MCRUN2_73_V7", "fullsim_50ns": "MCRUN2_73_V6"},
48  "CMSSW_7_4_0_pre5_BS": {"default": "MCRUN2_73_V9_postLS1beamspot", "fullsim_50ns": "MCRUN2_73_V8_postLS1beamspot"},
49  "CMSSW_7_4_0_pre6": {"default": "MCRUN2_74_V1", "fullsim_50ns": "MCRUN2_74_V0"},
50  "CMSSW_7_4_0_pre6_pmx": {"default": "MCRUN2_74_V1", "fullsim_50ns": "MCRUN2_74_V0"},
51  "CMSSW_7_4_0_pre8": {"default": "MCRUN2_74_V7", "fullsim_25ns": "MCRUN2_74_V5_AsympMinGT", "fullsim_50ns": "MCRUN2_74_V4_StartupMinGT"},
52  "CMSSW_7_4_0_pre8_25ns_asymptotic": {"default": "MCRUN2_74_V7"},
53  "CMSSW_7_4_0_pre8_50ns_startup": {"default": "MCRUN2_74_V6"},
54  "CMSSW_7_4_0_pre8_50ns_asympref": {"default": "MCRUN2_74_V5A_AsympMinGT"}, # for reference of 50ns asymptotic
55  "CMSSW_7_4_0_pre8_50ns_asymptotic": {"default": "MCRUN2_74_V7A_AsympGT"},
56  "CMSSW_7_4_0_pre8_ROOT6": {"default": "MCRUN2_74_V7"},
57  "CMSSW_7_4_0_pre8_pmx": {"default": "MCRUN2_74_V7", "fullsim_50ns": "MCRUN2_74_V6"},
58  "CMSSW_7_4_0_pre8_pmx_v2": {"default": "MCRUN2_74_V7_gs_pre7", "fullsim_50ns": "MCRUN2_74_V6_gs_pre7"},
59 }
60 
61 _releasePostfixes = ["_AlcaCSA14", "_PHYS14", "_TEST", "_pmx_v2", "_pmx", "_Fall14DR", "_71XGENSIM_FIXGT", "_71XGENSIM", "_73XGENSIM", "_BS", "_GenSim_7113",
62  "_25ns_asymptotic", "_50ns_startup", "_50ns_asympref", "_50ns_asymptotic"]
63 def _stripRelease(release):
64  for pf in _releasePostfixes:
65  if pf in release:
66  return release.replace(pf, "")
67  return release
68 
69 
70 def _getGlobalTag(sample, release):
71  """Get a GlobalTag.
72 
73  Arguments:
74  sample -- Sample object
75  release -- CMSSW release string
76  """
77  if not release in _globalTags:
78  print "Release %s not found from globaltag map in validation.py" % release
79  sys.exit(1)
80  gtmap = _globalTags[release]
81  if sample.hasOverrideGlobalTag():
82  ogt = sample.overrideGlobalTag()
83  if release in ogt:
84  gtmap = _globalTags[ogt[release]]
85  if sample.fullsim():
86  if sample.hasScenario():
87  return gtmap[sample.scenario()]
88  if sample.pileupType() == "50ns":
89  return gtmap.get("fullsim_50ns", gtmap["default"])
90  if sample.pileupType() == "25ns":
91  return gtmap.get("fullsim_25ns", gtmap["default"])
92  if sample.fastsim():
93  return gtmap.get("fastsim", gtmap["default"])
94  return gtmap["default"]
95 
96 # Mapping from release series to RelVal download URLs
97 _relvalUrls = {
98  "6_2_X": "https://cmsweb.cern.ch/dqm/relval/data/browse/ROOT/RelVal/CMSSW_6_2_x/",
99  "7_0_X": "https://cmsweb.cern.ch/dqm/relval/data/browse/ROOT/RelVal/CMSSW_7_0_x/",
100  "7_1_X": "https://cmsweb.cern.ch/dqm/relval/data/browse/ROOT/RelVal/CMSSW_7_1_x/",
101  "7_2_X": "https://cmsweb.cern.ch/dqm/relval/data/browse/ROOT/RelVal/CMSSW_7_2_x/",
102  "7_3_X": "https://cmsweb.cern.ch/dqm/relval/data/browse/ROOT/RelVal/CMSSW_7_3_x/",
103  "7_4_X": "https://cmsweb.cern.ch/dqm/relval/data/browse/ROOT/RelVal/CMSSW_7_4_x/",
104 }
105 
106 def _getRelValUrl(release):
107  """Get RelVal download URL for a given release."""
108  version_re = re.compile("CMSSW_(?P<X>\d+)_(?P<Y>\d+)")
109  m = version_re.search(release)
110  if not m:
111  raise Exception("Regex %s does not match to release version %s" % (version_re.pattern, release))
112  version = "%s_%s_X" % (m.group("X"), m.group("Y"))
113  if not version in _relvalUrls:
114  print "No RelVal URL for version %s, please update _relvalUrls" % version
115  sys.exit(1)
116  return _relvalUrls[version]
117 
118 class Sample:
119  """Represents a RelVal sample."""
120  def __init__(self, sample, append=None, midfix=None, putype=None,
121  fastsim=False, fastsimCorrespondingFullsimPileup=None,
122  version="v1", scenario=None, overrideGlobalTag=None):
123  """Constructor.
124 
125  Arguments:
126  sample -- String for name of the sample
127 
128  Keyword arguments
129  append -- String for a variable name within the DWM file names, to be directly appended to sample name (e.g. "HS"; default None)
130  midfix -- String for a variable name within the DQM file names, to be appended after underscore to "sample name+append" (e.g. "13", "UP15"; default None)
131  putype -- String for pileup type (e.g. "25ns"/"50ns" for FullSim, "AVE20" for FastSim; default None)
132  fastsim -- Bool indicating the FastSim status (default False)
133  fastsimCorrespondingFullSimPileup -- String indicating what is the FullSim pileup sample corresponding this FastSim sample. Must be set if fastsim=True and putype!=None (default None)
134  version -- String for dataset/DQM file version (default "v1")
135  scenario -- Geometry scenario for upgrade samples (default None)
136  overrideGlobalTag -- GlobalTag obtained from release information (in the form of {"release": "actualRelease"}; default None)
137  """
138  self._sample = sample
139  self._append = append
140  self._midfix = midfix
141  self._putype = putype
142  self._fastsim = fastsim
143  self._fastsimCorrespondingFullsimPileup = fastsimCorrespondingFullsimPileup
144  self._version = version
145  self._scenario = scenario
146  self._overrideGlobalTag = overrideGlobalTag
147 
148  if self._fastsim and self.hasPileup() and self._fastsimCorrespondingFullsimPileup is None:
149  raise Exception("If fastsim=True and putype!=None, also fastsimCorrespondingFullsimPileup must be != None")
150 
151  def sample(self):
152  """Get the sample name"""
153  return self._sample
154 
155  def name(self):
156  """Get the sample name"""
157  return self._sample
158 
159  def hasPileup(self):
160  """Return True if sample has pileup"""
161  return self._putype is not None
162 
163  def pileup(self):
164  """Return "PU"/"noPU" corresponding the pileup status"""
165  if self.hasPileup():
166  return "PU"
167  else:
168  return "noPU"
169 
170  def pileupType(self, release=None):
171  """Return the pileup type"""
172  if isinstance(self._putype, dict):
173  return self._putype.get(release, self._putype["default"])
174  else:
175  return self._putype
176 
177  def version(self, release=None):
178  if isinstance(self._version, dict):
179  return self._version.get(release, self._version["default"])
180  else:
181  return self._version
182 
183  def hasScenario(self):
184  return self._scenario is not None
185 
186  def scenario(self):
187  return self._scenario
188 
190  return self._overrideGlobalTag is not None
191 
192  def overrideGlobalTag(self):
193  return self._overrideGlobalTag
194 
195  def fastsim(self):
196  """Return True for FastSim sample"""
197  return self._fastsim
198 
199  def fullsim(self):
200  """Return True for FullSim sample"""
201  return not self._fastsim
202 
205 
206  def dirname(self, newRepository, newRelease, newSelection):
207  """Return the output directory name
208 
209  Arguments:
210  newRepository -- String for base directory for output files
211  newRelease -- String for CMSSW release
212  newSelection -- String for histogram selection
213  """
214  pileup = ""
215  if self.hasPileup() and not self._fastsim:
216  pileup = "_"+self._putype
217  return "{newRepository}/{newRelease}/{newSelection}{pileup}/{sample}".format(
218  newRepository=newRepository, newRelease=newRelease, newSelection=newSelection,
219  pileup=pileup, sample=sample)
220 
221  def filename(self, newRelease):
222  """Return the DQM file name
223 
224  Arguments:
225  newRelease -- String for CMSSW release
226  """
227  pileup = ""
228  fastsim = ""
229  midfix = ""
230  scenario = ""
231  if self._append is not None:
232  midfix += self._append
233  if self._midfix is not None:
234  midfix += "_"+self._midfix
235  if self.hasPileup():
236  if self._fastsim:
237  pileup = "PU_"
238  midfix += "_"+self.pileupType(newRelease)
239  else:
240  pileup = "PU"+self.pileupType(newRelease)+"_"
241  if self._fastsim:
242  fastsim = "_FastSim"
243  if self._scenario is not None:
244  scenario = "_"+self._scenario
245 
246  globalTag = _getGlobalTag(self, newRelease)
247 
248  fname = 'DQM_V0001_R000000001__{sample}{midfix}__{newrelease}-{pileup}{globaltag}{scenario}{fastsim}-{version}__DQMIO.root'.format(
249  sample=self._sample, midfix=midfix, newrelease=_stripRelease(newRelease),
250  pileup=pileup, globaltag=globalTag, scenario=scenario, fastsim=fastsim,
251  version=self.version(newRelease)
252  )
253 
254  return fname
255 
256  def datasetpattern(self, newRelease):
257  """Return the dataset pattern
258 
259  Arguments:
260  newRelease -- String for CMSSW release
261  """
262  pileup = ""
263  fastsim = ""
264  digi = ""
265  if self.hasPileup():
266  pileup = "-PU_"
267  if self._fastsim:
268  fastsim = "_FastSim-"
269  digi = "DIGI-"
270  else:
271  fastsim = "*"
272  globalTag = _getGlobalTag(self, newRelease)
273  return "{sample}/{newrelease}-{pileup}{globaltag}{fastsim}{version}/GEN-SIM-{digi}RECO".format(
274  sample=self._sample, newrelease=newRelease,
275  pileup=pileup, globaltag=globalTag, fastsim=fastsim, digi=digi,
276  version=self.version(newRelease)
277  )
278 
280  """Base class for Tracking/Vertex validation."""
281  def __init__(self, fullsimSamples, fastsimSamples, newRelease, newFileModifier=None, selectionName=""):
282  """Constructor.
283 
284  Arguments:
285  fullsimSamples -- List of Sample objects for FullSim samples (may be empty)
286  fastsimSamples -- List of Sample objects for FastSim samples (may be empty)
287  newRelease -- CMSSW release to be validated
288  newFileModifier -- If given, a function to modify the names of the new files (function takes a string and returns a string)
289  selectionName -- If given, use this string as the selection name (appended to GlobalTag for directory names)
290  """
291  try:
292  self._newRelease = os.environ["CMSSW_VERSION"]
293  except KeyError:
294  print >>sys.stderr, 'Error: CMSSW environment variables are not available.'
295  print >>sys.stderr, ' Please run cmsenv'
296  sys.exit()
297 
298  self._fullsimSamples = fullsimSamples
299  self._fastsimSamples = fastsimSamples
300  if newRelease != "":
301  self._newRelease = newRelease
302  self._newFileModifier = newFileModifier
303  self._selectionName = selectionName
304 
305  def _getDirectoryName(self, *args, **kwargs):
306  return None
307 
308  def _getSelectionName(self, *args, **kwargs):
309  return self._selectionName
310 
311  def download(self):
312  """Download DQM files. Requires grid certificate and asks your password for it."""
313  filenames = [s.filename(self._newRelease) for s in self._fullsimSamples+self._fastsimSamples]
314  if self._newFileModifier is not None:
315  filenames = map(self._newFileModifier, filenames)
316  filenames = filter(lambda f: not os.path.exists(f), filenames)
317  if len(filenames) == 0:
318  print "All files already downloaded"
319  return
320 
321  relvalUrl = _getRelValUrl(self._newRelease)
322  urls = [relvalUrl+f for f in filenames]
323  certfile = os.path.join(os.environ["HOME"], ".globus", "usercert.pem")
324  if not os.path.exists(certfile):
325  print "Certificate file {certfile} does not exist, unable to download RelVal files from {url}".format(certfile=certfile, url=relvalUrl)
326  sys.exit(1)
327  keyfile = os.path.join(os.environ["HOME"], ".globus", "userkey.pem")
328  if not os.path.exists(certfile):
329  print "Private key file {keyfile} does not exist, unable to download RelVal files from {url}".format(keyfile=keyfile, url=relvalUrl)
330  sys.exit(1)
331 
332  cmd = ["curl", "--cert-type", "PEM", "--cert", certfile, "--key", keyfile, "-k"]
333  for u in urls:
334  cmd.extend(["-O", u])
335  print "Downloading %d files from RelVal URL %s:" % (len(filenames), relvalUrl)
336  print " "+"\n ".join(filenames)
337  print "Please provide your private key pass phrase when curl asks it"
338  ret = subprocess.call(cmd)
339  if ret != 0:
340  print "Downloading failed with exit code %d" % ret
341  sys.exit(1)
342 
343  # verify
344  allFine = True
345  for f in filenames:
346  p = subprocess.Popen(["file", f], stdout=subprocess.PIPE)
347  stdout = p.communicate()[0]
348  if p.returncode != 0:
349  print "file command failed with exit code %d" % p.returncode
350  sys.exit(1)
351  if not "ROOT" in stdout:
352  print "File {f} is not ROOT, please check the correct version, GobalTag etc. from {url}".format(f=f, url=relvalUrl)
353  allFine = False
354  if os.path.exists(f):
355  os.remove(f)
356  if not allFine:
357  sys.exit(1)
358 
359  def doPlots(self, algos, qualities, refRelease, refRepository, newRepository, plotter, plotterDrawArgs={}):
360  """Create validation plots.
361 
362  Arguments:
363  algos -- List of strings for algoritms
364  qualities -- List of strings for quality flags (can be None)
365  refRelease -- String for reference CMSSW release
366  refRepository -- String for directory where reference root files are
367  newRepository -- String for directory whete to put new files
368  plotter -- plotting.Plotter object that does the plotting
369 
370  Keyword arguments:
371  plotterDrawArgs -- Dictionary for additional arguments to Plotter.draw() (default: {})
372  """
373  self._refRelease = refRelease
374  self._refRepository = refRepository
375  self._newRepository = newRepository
376  self._plotter = plotter
377  self._plotterDrawArgs = plotterDrawArgs
378 
379  if qualities is None:
380  qualities = [None]
381  if algos is None:
382  algos = [None]
383 
384  # New vs. Ref
385  for s in self._fullsimSamples+self._fastsimSamples:
386  for q in qualities:
387  for a in algos:
388  self._doPlots(a, q, s)
389 # if s.fullsim() and s.hasPileup():
390 # self._doPlotsPileup(a, q, s)
391 
392  # Fast vs. Full in New
393  for fast in self._fastsimSamples:
394  correspondingFull = None
395  for full in self._fullsimSamples:
396  if fast.name() != full.name():
397  continue
398  if fast.hasPileup():
399  if not full.hasPileup():
400  continue
401  if fast.fastsimCorrespondingFullsimPileup() != full.pileupType():
402  continue
403  else:
404  if full.hasPileup():
405  continue
406 
407  if correspondingFull is None:
408  correspondingFull = full
409  else:
410  raise Exception("Got multiple compatible FullSim samples for FastSim sample %s %s" % (fast.name(), fast.pileup()))
411  if correspondingFull is None:
412  raise Exception("Did not find compatible FullSim sample for FastSim sample %s %s" % (fast.name(), fast.pileup()))
413  for q in qualities:
414  for a in algos:
415  self._doPlotsFastFull(a, q, fast, correspondingFull)
416 
417  def _doPlots(self, algo, quality, sample):
418  """Do the real plotting work for a given algorithm, quality flag, and sample."""
419  # Get GlobalTags
420  refGlobalTag = _getGlobalTag(sample, self._refRelease)
421  newGlobalTag = _getGlobalTag(sample, self._newRelease)
422 
423  # Construct selection string
424  tmp = ""
425  if sample.hasScenario():
426  tmp += "_"+sample.scenario()
427  tmp += "_"+sample.pileup()
428  tmp += self._getSelectionName(quality, algo)
429  refSelection = refGlobalTag+tmp
430  newSelection = newGlobalTag+tmp
431  if sample.hasPileup() and not sample.fastsim():
432  refSelection += "_"+sample.pileupType(self._refRelease)
433  newSelection += "_"+sample.pileupType(self._newRelease)
434 
435  # Check that the new DQM file exists
436  harvestedfile = sample.filename(self._newRelease)
437  if not os.path.exists(harvestedfile):
438  print "Harvested file %s does not exist!" % harvestedfile
439  sys.exit(1)
440 
441  valname = "val.{sample}.root".format(sample=sample.name())
442 
443  # Construct reference directory name
444  tmp = [self._refRepository, self._refRelease]
445  if sample.fastsim():
446  tmp.extend(["fastsim", self._refRelease])
447  tmp.extend([refSelection, sample.name()])
448  refdir = os.path.join(*tmp)
449 
450  # Construct new directory name
451  tmp = [self._newRepository, self._newRelease]
452  if sample.fastsim():
453  tmp.extend(["fastsim", self._newRelease])
454  tmp.extend([newSelection, sample.name()])
455  newdir = os.path.join(*tmp)
456 
457  # Open reference file if it exists
458  refValFilePath = os.path.join(refdir, valname)
459  if not os.path.exists(refValFilePath):
460  print "Reference file %s not found" % refValFilePath
461  if not plotting.missingOk:
462  print "If this is acceptable, please set 'plotting.missingOk=True'"
463  sys.exit(1)
464  else:
465  refValFile = None
466  else:
467  refValFile = ROOT.TFile.Open(refValFilePath)
468 
469  # Copy the relevant histograms to a new validation root file
470  newValFile = _copySubDir(harvestedfile, valname, self._plotter.getPossibleDirectoryNames(), self._getDirectoryName(quality, algo))
471  fileList = [valname]
472 
473  # Do the plots
474  print "Comparing ref and new {sim} {sample} {algo} {quality}".format(
475  sim="FullSim" if not sample.fastsim() else "FastSim",
476  sample=sample.name(), algo=algo, quality=quality)
477  self._plotter.create([refValFile, newValFile], [
478  "%s, %s %s" % (sample.name(), _stripRelease(self._refRelease), refSelection),
479  "%s, %s %s" % (sample.name(), _stripRelease(self._newRelease), newSelection)
480  ],
481  subdir = self._getDirectoryName(quality, algo))
482  fileList.extend(self._plotter.draw(algo, **self._plotterDrawArgs))
483 
484  newValFile.Close()
485  if refValFile is not None:
486  refValFile.Close()
487 
488  # Move plots to new directory
489  print "Moving plots and %s to %s" % (valname, newdir)
490  if not os.path.exists(newdir):
491  os.makedirs(newdir)
492  for f in fileList:
493  shutil.move(f, os.path.join(newdir, f))
494 
495  def _doPlotsFastFull(self, algo, quality, fastSample, fullSample):
496  """Do the real plotting work for FastSim vs. FullSim for a given algorithm, quality flag, and sample."""
497  # Get GlobalTags
498  fastGlobalTag = _getGlobalTag(fastSample, self._newRelease)
499  fullGlobalTag = _getGlobalTag(fullSample, self._newRelease)
500 
501  # Construct selection string
502  tmp = self._getSelectionName(quality, algo)
503  fastSelection = fastGlobalTag+"_"+fastSample.pileup()+tmp
504  fullSelection = fullGlobalTag+"_"+fullSample.pileup()+tmp
505  if fullSample.hasPileup():
506  fullSelection += "_"+fullSample.pileupType(self._newRelease)
507 
508  # Construct directories for FastSim, FullSim, and for the results
509  fastdir = os.path.join(self._newRepository, self._newRelease, "fastsim", self._newRelease, fastSelection, fastSample.name())
510  fulldir = os.path.join(self._newRepository, self._newRelease, fullSelection, fullSample.name())
511  newdir = os.path.join(self._newRepository, self._newRelease, "fastfull", self._newRelease, fastSelection, fastSample.name())
512 
513  # Open input root files
514  valname = "val.{sample}.root".format(sample=fastSample.name())
515  fastValFilePath = os.path.join(fastdir, valname)
516  if not os.path.exists(fastValFilePath):
517  print "FastSim file %s not found" % fastValFilePath
518  fullValFilePath = os.path.join(fulldir, valname)
519  if not os.path.exists(fullValFilePath):
520  print "FullSim file %s not found" % fullValFilePath
521 
522  fastValFile = ROOT.TFile.Open(fastValFilePath)
523  fullValFile = ROOT.TFile.Open(fullValFilePath)
524 
525  # Do plots
526  print "Comparing FullSim and FastSim {sample} {algo} {quality}".format(
527  sample=fastSample.name(), algo=algo, quality=quality)
528  self._plotter.create([fullValFile, fastValFile], [
529  "FullSim %s, %s %s" % (fullSample.name(), _stripRelease(self._newRelease), fullSelection),
530  "FastSim %s, %s %s" % (fastSample.name(), _stripRelease(self._newRelease), fastSelection),
531  ],
532  subdir = self._getDirectoryName(quality, algo))
533  fileList = self._plotter.draw(algo, **self._plotterDrawArgs)
534 
535  fullValFile.Close()
536  fastValFile.Close()
537 
538  # Move plots to new directory
539  print "Moving plots to %s" % (newdir)
540  if not os.path.exists(newdir):
541  os.makedirs(newdir)
542  for f in fileList:
543  shutil.move(f, os.path.join(newdir, f))
544 
545  def _doPlotsPileup(self, algo, quality, sample):
546  """Do the real plotting work for Old vs. New pileup scenarios for a given algorithm, quality flag, and sample."""
547  # Get GlobalTags
548  newGlobalTag = _getGlobalTag(sample, self._newRelease)
549  refGlobalTag = newGlobalTag + "_OldPU"
550 
551  # Construct selection string
552  tmp = self._getSelectionName(quality, algo)
553  refSelection = refGlobalTag+"_"+sample.pileup()+tmp+"_"+sample.pileupType(self._newRelease)
554  newSelection = newGlobalTag+"_"+sample.pileup()+tmp+"_"+sample.pileupType(self._newRelease)
555 
556  # Construct directories for FastSim, FullSim, and for the results
557  refdir = os.path.join(self._newRepository, self._newRelease, refSelection, sample.name())
558  newdir = os.path.join(self._newRepository, self._newRelease, newSelection, sample.name())
559  resdir = os.path.join(self._newRepository, self._newRelease, "pileup", self._newRelease, newSelection, sample.name())
560 
561  # Open input root files
562  valname = "val.{sample}.root".format(sample=sample.name())
563  refValFilePath = os.path.join(refdir, valname)
564  if not os.path.exists(refValFilePath):
565  print "Ref pileup file %s not found" % refValFilePath
566  newValFilePath = os.path.join(newdir, valname)
567  if not os.path.exists(newValFilePath):
568  print "New pileup file %s not found" % newValFilePath
569 
570  refValFile = ROOT.TFile.Open(refValFilePath)
571  newValFile = ROOT.TFile.Open(newValFilePath)
572 
573  # Do plots
574  print "Comparing Old and New pileup {sample} {algo} {quality}".format(
575  sample=sample.name(), algo=algo, quality=quality)
576  self._plotter.create([refValFile, newValFile], [
577  "%d BX %s, %s %s" % ({"25ns": 10, "50ns": 20}[sample.pileupType(self._newRelease)], sample.name(), _stripRelease(self._newRelease), refSelection),
578  "35 BX %s, %s %s" % (sample.name(), _stripRelease(self._newRelease), newSelection),
579  ],
580  subdir = self._getDirectoryName(quality, algo))
581  fileList = self._plotter.draw(algo, **self._plotterDrawArgs)
582 
583  newValFile.Close()
584  refValFile.Close()
585 
586  # Move plots to new directory
587  print "Moving plots to %s" % (resdir)
588  if not os.path.exists(resdir):
589  os.makedirs(resdir)
590  for f in fileList:
591  shutil.move(f, os.path.join(resdir, f))
592 
593 def _copySubDir(oldfile, newfile, basenames, dirname):
594  """Copy a subdirectory from oldfile to newfile.
595 
596  Arguments:
597  oldfile -- String for source TFile
598  newfile -- String for destination TFile
599  basenames -- List of strings for base directories, first existing one is picked
600  dirname -- String for directory name under the base directory
601  """
602  oldf = ROOT.TFile.Open(oldfile)
603 
604  dirold = None
605  for basename in basenames:
606  dirold = oldf.GetDirectory(basename)
607  if dirold:
608  break
609  if not dirold:
610  raise Exception("Did not find any of %s directories from file %s" % (",".join(basenames, oldfile)))
611  if dirname:
612  d = dirold.Get(dirname)
613  if not d:
614  raise Exception("Did not find directory %s under %s" % (dirname, dirold.GetPath()))
615  dirold = d
616 
617  newf = ROOT.TFile.Open(newfile, "RECREATE")
618  dirnew = newf
619  for d in basenames[0].split("/"):
620  dirnew = dirnew.mkdir(d)
621  if dirname:
622  dirnew = dirnew.mkdir(dirname)
623  _copyDir(dirold, dirnew)
624 
625  oldf.Close()
626  return newf
627 
628 def _copyDir(src, dst):
629  """Copy recursively objects from src TDirectory to dst TDirectory."""
630  keys = src.GetListOfKeys()
631  for key in keys:
632  classname = key.GetClassName()
633  cl = ROOT.TClass.GetClass(classname)
634  if not cl:
635  continue
636  if cl.InheritsFrom("TDirectory"):
637  src2 = src.GetDirectory(key.GetName())
638  dst2 = dst.mkdir(key.GetName())
639  _copyDir(src2, dst2)
640  elif cl.InheritsFrom("TTree"):
641  t = key.ReadObj()
642  dst.cd()
643  newt = t.CloneTree(-1, "fast")
644  newt.Write()
645  newt.Delete()
646  else:
647  dst.cd()
648  obj = key.ReadObj()
649  obj.Write()
650  obj.Delete()
651 
653  def __init__(self, files, labels, newdir):
654  self._files = files
655  self._labels = labels
656  self._newdir = newdir
657 
658  def doPlots(self, algos, qualities, plotter, algoDirMap=None, newdirFunc=None, plotterDrawArgs={}):
659  self._plotter = plotter
660  self._algoDirMap = algoDirMap
661  self._newdirFunc = newdirFunc
662  self._plotterDrawArgs = plotterDrawArgs
663 
664  if qualities is None:
665  qualities = [None]
666  if algos is None:
667  algos = [None]
668 
669  for q in qualities:
670  for a in algos:
671  self._doPlots(a, q)
672 
673  def _doPlots(self, algo, quality):
674  openFiles = []
675  for f in self._files:
676  if not os.path.exists(f):
677  print "File %s not found" % f
678  sys.exit(1)
679  openFiles.append(ROOT.TFile.Open(f))
680 
681  # dirs = []
682  # for tf in openFiles:
683  # theDir = None
684  # for pd in self._plotter.getPossibleDirectoryNames():
685  # theDir = tf.GetDirectory(pd)
686  # if theDir:
687  # break
688  # if not theDir:
689  # print "Did not find any of %s directories from file %s" % (",".join(self._plotter.getPossibleDirectoryNames()), tf.GetName())
690  # sys.exit(1)
691  # if self._algoDirMap is not None:
692  # d = theDir.Get(self._algoDirMap[quality][algo])
693  # if not theDir:
694  # print "Did not find dir %s from %s" % (self._algoDirMap[quality][algo], theDir.GetPath())
695  # sys.exit(1)
696  # theDir = d
697  # dirs.append(theDir)
698 
699  subdir = None
700  if self._algoDirMap is not None:
701  subdir = self._algoDirMap[quality][algo]
702  self._plotter.create(openFiles, self._labels, subdir=subdir)
703  fileList = self._plotter.draw(algo, **self._plotterDrawArgs)
704 
705  for tf in openFiles:
706  tf.Close()
707 
708  newdir = self._newdir
709  if self._newdirFunc is not None:
710  newdir = os.path.join(newdir, self._newdirFunc(algo, quality))
711 
712  print "Moving plots to %s" % newdir
713  if not os.path.exists(newdir):
714  os.makedirs(newdir)
715  for f in fileList:
716  shutil.move(f, os.path.join(newdir, f))
_fastsimCorrespondingFullsimPileup
Definition: validation.py:143
def _copySubDir
Definition: validation.py:593
def _getGlobalTag
Definition: validation.py:70
def _stripRelease
Definition: validation.py:63
def fastsimCorrespondingFullsimPileup
Definition: validation.py:203
static std::string join(char **cmd)
Definition: RemoteFile.cc:18
double split
Definition: MVATrainer.cc:139
def _getRelValUrl
Definition: validation.py:106
def _copyDir
Definition: validation.py:628