CMS 3D CMS Logo

confdb.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 
3 from __future__ import absolute_import
4 import sys
5 import re
6 import os
7 from .pipe import pipe as _pipe
8 from .options import globalTag
9 from itertools import islice
10 
11 def splitter(iterator, n):
12  i = iterator.__iter__()
13  while True:
14  l = list(islice(i, n))
15  if l:
16  yield l
17  else:
18  break
19 
20 
22 
23  def __init__(self, configuration):
24  self.config = configuration
25  self.data = None
26  self.source = []
27  self.parent = []
28 
29  self.options = {
30  'essources' : [],
31  'esmodules' : [],
32  'modules' : [],
33  'sequences' : [],
34  'services' : [],
35  'paths' : [],
36  'psets' : [],
37  'blocks' : [],
38  }
39 
40  self.labels = {}
41  if self.config.fragment:
42  self.labels['process'] = 'fragment'
43  self.labels['dict'] = 'fragment.__dict__'
44  else:
45  self.labels['process'] = 'process'
46  self.labels['dict'] = 'process.__dict__'
47 
48  if self.config.prescale and (self.config.prescale.lower() != 'none'):
49  self.labels['prescale'] = self.config.prescale
50 
51  # get the configuration from ConfdB
52  from .confdbOfflineConverter import OfflineConverter
53  self.converter = OfflineConverter(version = self.config.menu.version, database = self.config.menu.database, proxy = self.config.proxy, proxyHost = self.config.proxy_host, proxyPort = self.config.proxy_port, tunnel = self.config.tunnel, tunnelPort = self.config.tunnel_port)
54  self.buildPathList()
55  self.buildOptions()
58  self.customize()
59 
61  if not self.config.setup:
62  return
63 
64  if ".py" in self.config.setup:
65  self.config.setupFile = self.config.setup.split(".py")[0]
66  return
67  args = ['--configName', self.config.setup ]
68  args.append('--noedsources')
69  args.append('--nopaths')
70  for key, vals in self.options.items():
71  if vals:
72  args.extend(('--'+key, ','.join(vals)))
73  args.append('--cff')
74  data, err = self.converter.query( *args )
75  if 'ERROR' in err or 'Exhausted Resultset' in err or 'CONFIG_NOT_FOUND' in err:
76  sys.stderr.write("%s: error while retrieving the HLT setup menu\n\n" % os.path.basename(sys.argv[0]))
77  sys.stderr.write(err + "\n\n")
78  sys.exit(1)
79  self.config.setupFile = "setup_"+self.config.setup[1:].replace("/","_")+"_cff"
80  outfile = open(self.config.setupFile+".py","w+")
81  outfile.write("# This file is automatically generated by hltGetConfiguration.\n" + data)
82 
84  if self.config.menu.run:
85  args = ['--runNumber', self.config.menu.run]
86  else:
87  args = ['--configName', self.config.menu.name ]
88  if not self.config.hilton:
89  # keep the original Source when running on Hilton
90  args.append('--noedsources')
91  for key, vals in self.options.items():
92  if vals:
93  args.extend(('--'+key, ','.join(vals)))
94  data, err = self.converter.query( *args )
95  if 'ERROR' in err or 'Exhausted Resultset' in err or 'CONFIG_NOT_FOUND' in err:
96  sys.stderr.write("%s: error while retrieving the HLT menu\n\n" % os.path.basename(sys.argv[0]))
97  sys.stderr.write(err + "\n\n")
98  sys.exit(1)
99  self.data = data
100 
101  def getPathList(self):
102  if self.config.menu.run:
103  args = ['--runNumber', self.config.menu.run]
104  else:
105  args = ['--configName', self.config.menu.name]
106  args.extend( (
107  '--cff',
108  '--noedsources',
109  '--noes',
110  '--noservices',
111  '--nosequences',
112  '--nomodules'
113  ) )
114 
115  data, err = self.converter.query( *args )
116  if 'ERROR' in err or 'Exhausted Resultset' in err or 'CONFIG_NOT_FOUND' in err:
117  sys.stderr.write("%s: error while retrieving the list of paths from the HLT menu\n\n" % os.path.basename(sys.argv[0]))
118  sys.stderr.write(err + "\n\n")
119  sys.exit(1)
120  filter = re.compile(r' *= *cms.(End|Final)?Path.*')
121  paths = [ filter.sub('', line) for line in data.splitlines() if filter.search(line) ]
122  return paths
123 
124 
125  @staticmethod
126  def expandWildcards(globs, collection):
127  # expand a list of unix-style wildcards matching a given collection
128  # wildcards with no matches are silently discarded
129  matches = []
130  for glob in globs:
131  negate = ''
132  if glob[0] == '-':
133  negate = '-'
134  glob = glob[1:]
135  # translate a unix-style glob expression into a regular expression
136  filter = re.compile(r'^' + glob.replace('?', '.').replace('*', '.*').replace('[!', '[^') + r'$')
137  matches.extend( negate + element for element in collection if filter.match(element) )
138  return matches
139 
140 
141  @staticmethod
142  def consolidateNegativeList(elements):
143  # consolidate a list of path exclusions and re-inclusions
144  # the result is the list of paths to be removed from the dump
145  result = set()
146  for element in elements:
147  if element[0] == '-':
148  result.add( element )
149  else:
150  result.discard( '-' + element )
151  return sorted( element for element in result )
152 
153  @staticmethod
154  def consolidatePositiveList(elements):
155  # consolidate a list of path selection and re-exclusions
156  # the result is the list of paths to be included in the dump
157  result = set()
158  for element in elements:
159  if element[0] == '-':
160  result.discard( element[1:] )
161  else:
162  result.add( element )
163  return sorted( element for element in result )
164 
165 
166  # dump the final configuration
167  def dump(self):
168  self.data = self.data % self.labels
169  if self.config.fragment:
170  self.data = re.sub( r'\bprocess\b', 'fragment', self.data )
171  self.data = re.sub( r'\bProcess\b', 'ProcessFragment', self.data )
172  return self.data
173 
174 
175  # add specific customizations
176  def specificCustomize(self):
177  # specific customizations now live in HLTrigger.Configuration.customizeHLTforALL.customizeHLTforAll(.,.)
178  if self.config.fragment:
179  self.data += """
180 # add specific customizations
181 from HLTrigger.Configuration.customizeHLTforALL import customizeHLTforAll
182 fragment = customizeHLTforAll(fragment,"%s")
183 """ % (self.config.type)
184  elif self.config.hilton:
185  # do not apply the STORM-specific customisation
186  pass
187  else:
188  if self.config.type=="Fake":
189  prefix = "run1"
190  elif self.config.type in ("Fake1","Fake2","2018"):
191  prefix = "run2"
192  else:
193  prefix = "run3"
194  _gtData = "auto:"+prefix+"_hlt_"+self.config.type
195  _gtMc = "auto:"+prefix+"_mc_" +self.config.type
196  self.data += """
197 # add specific customizations
198 _customInfo = {}
199 _customInfo['menuType' ]= "%s"
200 _customInfo['globalTags']= {}
201 _customInfo['globalTags'][True ] = "%s"
202 _customInfo['globalTags'][False] = "%s"
203 _customInfo['inputFiles']={}
204 _customInfo['inputFiles'][True] = "file:RelVal_Raw_%s_DATA.root"
205 _customInfo['inputFiles'][False] = "file:RelVal_Raw_%s_MC.root"
206 _customInfo['maxEvents' ]= %s
207 _customInfo['globalTag' ]= "%s"
208 _customInfo['inputFile' ]= %s
209 _customInfo['realData' ]= %s
210 
211 from HLTrigger.Configuration.customizeHLTforALL import customizeHLTforAll
212 %%(process)s = customizeHLTforAll(%%(process)s,"%s",_customInfo)
213 """ % (self.config.type,_gtData,_gtMc,self.config.type,self.config.type,self.config.events,self.config.globaltag,self.source,self.config.data,self.config.type)
214 
215  self.data += """
216 from HLTrigger.Configuration.customizeHLTforCMSSW import customizeHLTforCMSSW
217 %%(process)s = customizeHLTforCMSSW(%%(process)s,"%s")
218 """ % (self.config.type)
219 
220  # Eras-based customisations
221  self.data += """
222 # Eras-based customisations
223 from HLTrigger.Configuration.Eras import modifyHLTforEras
224 modifyHLTforEras(%(process)s)
225 """
226  # add the user-defined customization functions, if any
227  if self.config.customise:
228  self.data += "\n"
229  self.data += "#User-defined customization functions\n"
230  for customise in self.config.customise.split(","):
231  customiseValues = customise.split(".")
232  if len(customiseValues)>=3: raise Exception("--customise option cannot contain more than one dot.")
233  if len(customiseValues)==1:
234  customiseValues.append("customise")
235  customiseValues[0] = customiseValues[0].replace("/",".")
236  self.data += "from "+customiseValues[0]+" import "+customiseValues[1]+"\n"
237  self.data += "process = "+customiseValues[1]+"(process)\n"
238 
239 
240  # customize the configuration according to the options
241  def customize(self):
242 
243  # adapt the source to the current scenario
244  if not self.config.fragment:
245  self.build_source()
246 
247  # manual override some parameters
248  if self.config.type in ('HIon', ):
249  if self.config.data:
250  if not self.config.fragment:
251  self._fix_parameter( type = 'InputTag', value = 'rawDataCollector', replace = 'rawDataRepacker')
252 
253  # if requested, remove the HLT prescales
254  self.fixPrescales()
255 
256  # if requested, override all ED/HLTfilters to always pass ("open" mode)
257  self.instrumentOpenMode()
258 
259  # if requested, change all HLTTriggerTypeFilter EDFilters to accept only error events (SelectedTriggerType = 0)
261 
262  # if requested, instrument the self with the modules and EndPath needed for timing studies
263  self.instrumentTiming()
264 
265  # if requested, override the L1 self from the GlobalTag (Xml)
266  self.overrideL1MenuXml()
267 
268  # if requested, run the L1 emulator
269  self.runL1Emulator()
270 
271  # add process.load("setup_cff")
272  self.loadSetupCff()
273 
274  if self.config.fragment:
275  self.data += """
276 # dummify hltGetConditions in cff's
277 if 'hltGetConditions' in %(dict)s and 'HLTriggerFirstPath' in %(dict)s :
278  %(process)s.hltDummyConditions = cms.EDFilter( "HLTBool",
279  result = cms.bool( True )
280  )
281  %(process)s.HLTriggerFirstPath.replace(%(process)s.hltGetConditions,%(process)s.hltDummyConditions)
282 """
283 
284  # the scouting path issue:
285  # 1) for config fragments, we remove all output modules
286  # 2) however in old style datasets, the scouting output paths also run the unpackers which are needed
287  # 3) therefore they have to keep the scouting path but remove the scouting output module
288  # 4) in new style datasets, aka datasetpaths & finalpaths, the scouting unpackers are on another path and all of this is unnecessary
289  # 5) however its hard to detect whether we have new style or old style so we run this for both
290  # 6) therefore we end up with a superfluous Scouting*OutputPaths which are empty
291  for path in self.all_paths:
292  match = re.match(r'(Scouting\w+)Output$', path)
293  if match:
294  module = 'hltOutput' + match.group(1)
295  self.data = self.data.replace(path+' = cms.EndPath', path+' = cms.Path')
296  self.data = self.data.replace(' + process.'+module, '')
297  self.data = self.data.replace(' process.'+module, '')
298  else:
299 
300  # override the process name and adapt the relevant filters
301  self.overrideProcessName()
302 
303  # select specific Eras
304  self.addEras()
305 
306  # override the output modules to output root files
307  self.overrideOutput()
308 
309  # add global options
310  self.addGlobalOptions()
311 
312  # if requested or necessary, override the GlobalTag and connection strings (incl. L1!)
313  self.overrideGlobalTag()
314 
315  # request summary informations from the MessageLogger
316  self.updateMessageLogger()
317 
318  # replace DQMStore and DQMRootOutputModule with a configuration suitable for running offline
319  self.instrumentDQM()
320 
321  # add specific customisations
322  self.specificCustomize()
323 
324 
325  def addGlobalOptions(self):
326  # add global options
327  self.data += """
328 # limit the number of events to be processed
329 %%(process)s.maxEvents = cms.untracked.PSet(
330  input = cms.untracked.int32( %d )
331 )
332 """ % self.config.events
333 
334  self.data += """
335 # enable TrigReport, TimeReport and MultiThreading
336 %(process)s.options.wantSummary = True
337 %(process)s.options.numberOfThreads = 4
338 %(process)s.options.numberOfStreams = 0
339 """
340 
341  def _fix_parameter(self, **args):
342  """arguments:
343  name: parameter name (optional)
344  type: parameter type (look for tracked and untracked variants)
345  value: original value
346  replace: replacement value
347  """
348  if 'name' in args:
349  self.data = re.sub(
350  r'%(name)s = cms(?P<tracked>(?:\.untracked)?)\.%(type)s\( (?P<quote>["\']?)%(value)s(?P=quote)' % args,
351  r'%(name)s = cms\g<tracked>.%(type)s( \g<quote>%(replace)s\g<quote>' % args,
352  self.data)
353  else:
354  self.data = re.sub(
355  r'cms(?P<tracked>(?:\.untracked)?)\.%(type)s\( (?P<quote>["\']?)%(value)s(?P=quote)' % args,
356  r'cms\g<tracked>.%(type)s( \g<quote>%(replace)s\g<quote>' % args,
357  self.data)
358 
359 
360  def fixPrescales(self):
361  # update the PrescaleService to match the new list of paths
362  if self.options['paths']:
363  if self.options['paths'][0][0] == '-':
364  # drop requested paths
365  for minuspath in self.options['paths']:
366  path = minuspath[1:]
367  self.data = re.sub(r' cms.PSet\( pathName = cms.string\( "%s" \),\n prescales = cms.vuint32\( .* \)\n \),?\n' % path, '', self.data)
368  else:
369  # keep requested paths
370  for path in self.all_paths:
371  if path not in self.options['paths']:
372  self.data = re.sub(r' cms.PSet\( pathName = cms.string\( "%s" \),\n prescales = cms.vuint32\( .* \)\n \),?\n' % path, '', self.data)
373 
374  if self.config.prescale and (self.config.prescale.lower() != 'none'):
375  # TO DO: check that the requested prescale column is valid
376  self.data += """
377 # force the use of a specific HLT prescale column
378 if 'PrescaleService' in %(dict)s:
379  %(process)s.PrescaleService.forceDefault = True
380  %(process)s.PrescaleService.lvl1DefaultLabel = '%(prescale)s'
381 """
382 
383 
385  if self.config.open:
386  # find all EDfilters
387  filters = [ match[1] for match in re.findall(r'(process\.)?\b(\w+) = cms.EDFilter', self.data) ]
388  re_sequence = re.compile( r'cms\.(Path|Sequence)\((.*)\)' )
389  # remove existing 'cms.ignore' and '~' modifiers
390  self.data = re_sequence.sub( lambda line: re.sub( r'cms\.ignore *\( *((process\.)?\b(\w+)) *\)', r'\1', line.group(0) ), self.data )
391  self.data = re_sequence.sub( lambda line: re.sub( r'~', '', line.group(0) ), self.data )
392  # wrap all EDfilters with "cms.ignore( ... )", 1000 at a time (python 2.6 complains for too-big regular expressions)
393  for some in splitter(filters, 1000):
394  re_filters = re.compile( r'\b((process\.)?(' + r'|'.join(some) + r'))\b' )
395  self.data = re_sequence.sub( lambda line: re_filters.sub( r'cms.ignore( \1 )', line.group(0) ), self.data )
396 
397 
399  if self.config.errortype:
400  # change all HLTTriggerTypeFilter EDFilters to accept only error events (SelectedTriggerType = 0)
401  self._fix_parameter(name = 'SelectedTriggerType', type ='int32', value = '1', replace = '0')
402  self._fix_parameter(name = 'SelectedTriggerType', type ='int32', value = '2', replace = '0')
403  self._fix_parameter(name = 'SelectedTriggerType', type ='int32', value = '3', replace = '0')
404 
405 
406  def overrideGlobalTag(self):
407  # overwrite GlobalTag
408  # the logic is:
409  # - if a GlobalTag is specified on the command line:
410  # - override the global tag
411  # - if the GT is "auto:...", insert the code to read it from Configuration.AlCa.autoCond
412  # - if a GlobalTag is NOT specified on the command line:
413  # - when running on data, do nothing, and keep the global tag in the menu
414  # - when running on mc, take the GT from the configuration.type
415 
416  # override the GlobalTag connection string and pfnPrefix
417 
418  # when running on MC, override the global tag even if not specified on the command line
419  if not self.config.data and not self.config.globaltag:
420  if self.config.type in globalTag:
421  self.config.globaltag = globalTag[self.config.type]
422  else:
423  self.config.globaltag = globalTag['GRun']
424 
425  # if requested, override the L1 menu from the GlobalTag
426  if self.config.l1.override:
427  self.config.l1.tag = self.config.l1.override
428  self.config.l1.record = 'L1TUtmTriggerMenuRcd'
429  self.config.l1.connect = ''
430  self.config.l1.label = ''
431  if not self.config.l1.snapshotTime:
432  self.config.l1.snapshotTime = '9999-12-31 23:59:59.000'
433  self.config.l1cond = '%(tag)s,%(record)s,%(connect)s,%(label)s,%(snapshotTime)s' % self.config.l1.__dict__
434  else:
435  self.config.l1cond = None
436 
437  if self.config.globaltag or self.config.l1cond:
438  text = """
439 # override the GlobalTag, connection string and pfnPrefix
440 if 'GlobalTag' in %(dict)s:
441  from Configuration.AlCa.GlobalTag import GlobalTag as customiseGlobalTag
442  %(process)s.GlobalTag = customiseGlobalTag(%(process)s.GlobalTag"""
443  if self.config.globaltag:
444  text += ", globaltag = %s" % repr(self.config.globaltag)
445  if self.config.l1cond:
446  text += ", conditions = %s" % repr(self.config.l1cond)
447  text += ")\n"
448  self.data += text
449 
450  def overrideL1MenuXml(self):
451  # if requested, override the GlobalTag's L1T menu from an Xml file
452  if self.config.l1Xml.XmlFile:
453  text = """
454 # override the GlobalTag's L1T menu from an Xml file
455 from HLTrigger.Configuration.CustomConfigs import L1XML
456 %%(process)s = L1XML(%%(process)s,"%s")
457 """ % (self.config.l1Xml.XmlFile)
458  self.data += text
459 
460  def runL1Emulator(self):
461  # if requested, run the Full L1T emulator, then repack the data into a new RAW collection, to be used by the HLT
462  if self.config.emulator:
463  text = """
464 # run the Full L1T emulator, then repack the data into a new RAW collection, to be used by the HLT
465 from HLTrigger.Configuration.CustomConfigs import L1REPACK
466 %%(process)s = L1REPACK(%%(process)s,"%s")
467 """ % (self.config.emulator)
468  self.data += text
469 
470  def overrideOutput(self):
471  # if not running on Hilton, override the "online" output modules with the "offline" one (i.e. PoolOutputModule)
472  # in Run 1 and Run 2, the online output modules were instances of ShmStreamConsumer
473  # in Run 3, ShmStreamConsumer has been replaced with EvFOutputModule, and later GlobalEvFOutputModule
474  if not self.config.hilton:
475  self.data = re.sub(
476  r'\b(process\.)?hltOutput(\w+) *= *cms\.OutputModule\( *"(ShmStreamConsumer)" *,',
477  r'%(process)s.hltOutput\2 = cms.OutputModule( "PoolOutputModule",\n fileName = cms.untracked.string( "output\2.root" ),\n fastCloning = cms.untracked.bool( False ),\n dataset = cms.untracked.PSet(\n filterName = cms.untracked.string( "" ),\n dataTier = cms.untracked.string( "RAW" )\n ),',
478  self.data
479  )
480 
481  self.data = re.sub("""\
482 \\b(process\.)?hltOutput(\w+) *= *cms\.OutputModule\( *['"](EvFOutputModule|GlobalEvFOutputModule)['"] *,
483  use_compression = cms.untracked.bool\( (True|False) \),
484  compression_algorithm = cms.untracked.string\( ['"](.+?)['"] \),
485  compression_level = cms.untracked.int32\( (-?\d+) \),
486  lumiSection_interval = cms.untracked.int32\( (-?\d+) \),
487 (.+?),
488  psetMap = cms.untracked.InputTag\( ['"]hltPSetMap['"] \)
489 ""","""\
490 %(process)s.hltOutput\g<2> = cms.OutputModule( "PoolOutputModule",
491  fileName = cms.untracked.string( "output\g<2>.root" ),
492  compressionAlgorithm = cms.untracked.string( "\g<5>" ),
493  compressionLevel = cms.untracked.int32( \g<6> ),
494  fastCloning = cms.untracked.bool( False ),
495  dataset = cms.untracked.PSet(
496  filterName = cms.untracked.string( "" ),
497  dataTier = cms.untracked.string( "RAW" )
498  ),
499 \g<8>
500 """, self.data, 0, re.DOTALL)
501 
502  if not self.config.fragment and self.config.output == 'minimal':
503  # add a single output to keep the TriggerResults and TriggerEvent
504  self.data += """
505 # add a single "keep *" output
506 %(process)s.hltOutputMinimal = cms.OutputModule( "PoolOutputModule",
507  fileName = cms.untracked.string( "output.root" ),
508  fastCloning = cms.untracked.bool( False ),
509  dataset = cms.untracked.PSet(
510  dataTier = cms.untracked.string( 'AOD' ),
511  filterName = cms.untracked.string( '' )
512  ),
513  outputCommands = cms.untracked.vstring( 'drop *',
514  'keep edmTriggerResults_*_*_*',
515  'keep triggerTriggerEvent_*_*_*',
516  'keep GlobalAlgBlkBXVector_*_*_*',
517  'keep GlobalExtBlkBXVector_*_*_*',
518  'keep l1tEGammaBXVector_*_EGamma_*',
519  'keep l1tEtSumBXVector_*_EtSum_*',
520  'keep l1tJetBXVector_*_Jet_*',
521  'keep l1tMuonBXVector_*_Muon_*',
522  'keep l1tTauBXVector_*_Tau_*',
523  )
524 )
525 %(process)s.MinimalOutput = cms.FinalPath( %(process)s.hltOutputMinimal )
526 %(process)s.schedule.append( %(process)s.MinimalOutput )
527 """
528  elif not self.config.fragment and self.config.output == 'full':
529  # add a single "keep *" output
530  self.data += """
531 # add a single "keep *" output
532 %(process)s.hltOutputFull = cms.OutputModule( "PoolOutputModule",
533  fileName = cms.untracked.string( "output.root" ),
534  fastCloning = cms.untracked.bool( False ),
535  dataset = cms.untracked.PSet(
536  dataTier = cms.untracked.string( 'RECO' ),
537  filterName = cms.untracked.string( '' )
538  ),
539  outputCommands = cms.untracked.vstring( 'keep *' )
540 )
541 %(process)s.FullOutput = cms.FinalPath( %(process)s.hltOutputFull )
542 %(process)s.schedule.append( %(process)s.FullOutput )
543 """
544 
545  # select specific Eras
546  def addEras(self):
547  if self.config.eras is None:
548  return
549  from Configuration.StandardSequences.Eras import eras
550  erasSplit = self.config.eras.split(',')
551  self.data = re.sub(r'process = cms.Process\( *"\w+"', '\n'.join(eras.pythonCfgLines[era] for era in erasSplit)+'\n\g<0>, '+', '.join(era for era in erasSplit), self.data)
552 
553  # select specific Eras
554  def loadSetupCff(self):
555  if self.config.setup is None:
556  return
557  processLine = self.data.find("\n",self.data.find("cms.Process"))
558  self.data = self.data[:processLine]+'\nprocess.load("%s")'%self.config.setupFile+self.data[processLine:]
559 
560  # override the process name and adapt the relevant filters
562  if self.config.name is None:
563  return
564 
565  # sanitise process name
566  self.config.name = self.config.name.replace("_","")
567  # override the process name
568  quote = '[\'\"]'
569  self.data = re.compile(r'^(process\s*=\s*cms\.Process\(\s*' + quote + r')\w+(' + quote + r'\s*\).*)$', re.MULTILINE).sub(r'\1%s\2' % self.config.name, self.data, 1)
570 
571  # when --setup option is used, remove possible errors from PrescaleService due to missing HLT paths.
572  if self.config.setup: self.data += """
573 # avoid PrescaleService error due to missing HLT paths
574 if 'PrescaleService' in process.__dict__:
575  for pset in reversed(process.PrescaleService.prescaleTable):
576  if not hasattr(process,pset.pathName.value()):
577  process.PrescaleService.prescaleTable.remove(pset)
578 """
579 
580 
582  # request summary informations from the MessageLogger
583  self.data += """
584 # show summaries from trigger analysers used at HLT
585 if 'MessageLogger' in %(dict)s:
586  %(process)s.MessageLogger.TriggerSummaryProducerAOD = cms.untracked.PSet()
587  %(process)s.MessageLogger.L1GtTrigReport = cms.untracked.PSet()
588  %(process)s.MessageLogger.L1TGlobalSummary = cms.untracked.PSet()
589  %(process)s.MessageLogger.HLTrigReport = cms.untracked.PSet()
590  %(process)s.MessageLogger.FastReport = cms.untracked.PSet()
591  %(process)s.MessageLogger.ThroughputService = cms.untracked.PSet()
592 """
593 
594 
595  def loadAdditionalConditions(self, comment, *conditions):
596  # load additional conditions
597  self.data += """
598 # %s
599 if 'GlobalTag' in %%(dict)s:
600 """ % comment
601  for condition in conditions:
602  self.data += """ %%(process)s.GlobalTag.toGet.append(
603  cms.PSet(
604  record = cms.string( '%(record)s' ),
605  tag = cms.string( '%(tag)s' ),
606  label = cms.untracked.string( '%(label)s' ),
607  )
608  )
609 """ % condition
610 
611 
612  def loadCffCommand(self, module):
613  # load a cfi or cff module
614  if self.config.fragment:
615  return 'from %s import *\n' % module
616  else:
617  return 'process.load( "%s" )\n' % module
618 
619  def loadCff(self, module):
620  self.data += self.loadCffCommand(module)
621 
622 
623  def overrideParameters(self, module, parameters):
624  # override a module's parameter if the module is present in the configuration
625  self.data += "if '%s' in %%(dict)s:\n" % module
626  for (parameter, value) in parameters:
627  self.data += " %%(process)s.%s.%s = %s\n" % (module, parameter, value)
628  self.data += "\n"
629 
630 
632  if label in self.data:
633  label_re = r'\b(process\.)?' + label
634  self.data = re.sub(r' *(\+|,) *' + label_re, '', self.data)
635  self.data = re.sub(label_re + r' *(\+|,) *', '', self.data)
636  self.data = re.sub(label_re, '', self.data)
637 
638 
639  def instrumentTiming(self):
640 
641  if self.config.timing:
642  self.data += """
643 # instrument the menu with the modules and EndPath needed for timing studies
644 """
645 
646  self.data += '\n# configure the FastTimerService\n'
647  self.loadCff('HLTrigger.Timer.FastTimerService_cfi')
648 
649  self.data += """# print a text summary at the end of the job
650 %(process)s.FastTimerService.printEventSummary = False
651 %(process)s.FastTimerService.printRunSummary = False
652 %(process)s.FastTimerService.printJobSummary = True
653 
654 # enable DQM plots
655 %(process)s.FastTimerService.enableDQM = True
656 
657 # enable per-path DQM plots
658 %(process)s.FastTimerService.enableDQMbyPath = True
659 
660 # enable per-module DQM plots
661 %(process)s.FastTimerService.enableDQMbyModule = True
662 
663 # enable per-event DQM plots vs lumisection
664 %(process)s.FastTimerService.enableDQMbyLumiSection = True
665 %(process)s.FastTimerService.dqmLumiSectionsRange = 2500
666 
667 # set the time resolution of the DQM plots
668 %(process)s.FastTimerService.dqmTimeRange = 2000.
669 %(process)s.FastTimerService.dqmTimeResolution = 10.
670 %(process)s.FastTimerService.dqmPathTimeRange = 1000.
671 %(process)s.FastTimerService.dqmPathTimeResolution = 5.
672 %(process)s.FastTimerService.dqmModuleTimeRange = 200.
673 %(process)s.FastTimerService.dqmModuleTimeResolution = 1.
674 
675 # set the base DQM folder for the DQM plots
676 %(process)s.FastTimerService.dqmPath = 'HLT/TimerService'
677 %(process)s.FastTimerService.enableDQMbyProcesses = False
678 
679 # write a JSON file with the information to be displayed in a pie chart
680 %(process)s.FastTimerService.writeJSONSummary = True
681 %(process)s.FastTimerService.jsonFileName = 'resources.json'
682 """
683 
684  self.data += '\n# configure the ThroughputService\n'
685  self.loadCff('HLTrigger.Timer.ThroughputService_cfi')
686 
687  self.data += """# enable DQM plots
688 %(process)s.ThroughputService.enableDQM = True
689 
690 # set the resolution of the DQM plots
691 %(process)s.ThroughputService.eventRange = 10000
692 %(process)s.ThroughputService.eventResolution = 1
693 %(process)s.ThroughputService.timeRange = 60000
694 %(process)s.ThroughputService.timeResolution = 10
695 
696 # set the base DQM folder for the DQM plots
697 %(process)s.ThroughputService.dqmPath = 'HLT/Throughput'
698 %(process)s.ThroughputService.dqmPathByProcesses = False
699 """
700 
701 
702  def instrumentDQM(self):
703  if not self.config.hilton:
704  # remove any reference to the hltDQMFileSaver and hltDQMFileSaverPB:
705  # note the convert options remove the module itself,
706  # here we are just removing the references in paths, sequences, etc
707  self.removeElementFromSequencesTasksAndPaths('hltDQMFileSaverPB')
708  self.removeElementFromSequencesTasksAndPaths('hltDQMFileSaver')
709 
710  # instrument the HLT menu with DQMStore and DQMRootOutputModule suitable for running offline
711  dqmstore = "\n# load the DQMStore and DQMRootOutputModule\n"
712  dqmstore += self.loadCffCommand('DQMServices.Core.DQMStore_cfi')
713  dqmstore += """
714 %(process)s.dqmOutput = cms.OutputModule("DQMRootOutputModule",
715  fileName = cms.untracked.string("DQMIO.root")
716 )
717 """
718  empty_path = re.compile(r'.*\b(process\.)?DQMOutput = cms\.(Final|End)Path\( *\).*')
719  other_path = re.compile(r'(.*\b(process\.)?DQMOutput = cms\.(Final|End)Path\()(.*)')
720  if empty_path.search(self.data):
721  # replace an empty DQMOutput path
722  self.data = empty_path.sub(dqmstore + '\n%(process)s.DQMOutput = cms.FinalPath( %(process)s.dqmOutput )\n', self.data)
723  elif other_path.search(self.data):
724  # prepend the dqmOutput to the DQMOutput path
725  self.data = other_path.sub(dqmstore + r'\g<1> %(process)s.dqmOutput +\g<4>', self.data)
726  else:
727  # create a new DQMOutput path with the dqmOutput module
728  self.data += dqmstore
729  self.data += '\n%(process)s.DQMOutput = cms.FinalPath( %(process)s.dqmOutput )\n'
730  self.data += '%(process)s.schedule.append( %(process)s.DQMOutput )\n'
731 
732 
733  @staticmethod
734  def dumppaths(paths):
735  sys.stderr.write('Path selection:\n')
736  for path in paths:
737  sys.stderr.write('\t%s\n' % path)
738  sys.stderr.write('\n\n')
739 
740  def buildPathList(self):
741  self.all_paths = self.getPathList()
742 
743  if self.config.paths:
744  # no path list was requested, dump the full table, minus unsupported / unwanted paths
745  paths = self.config.paths.split(',')
746  else:
747  # dump only the requested paths, plus the eventual output endpaths
748  paths = []
749 
750  # 'none' should remove all outputs
751  # 'dqm' should remove all outputs but DQMHistograms
752  # 'minimal' should remove all outputs but DQMHistograms, and add a single output module to keep the TriggerResults and TriggerEvent
753  # 'full' should remove all outputs but DQMHistograms, and add a single output module to "keep *"
754  # See also the `overrideOutput` method
755  if self.config.fragment or self.config.output in ('none', ):
756  if self.config.paths:
757  # keep only the Paths and EndPaths requested explicitly
758  pass
759  else:
760  # drop all output EndPaths but the Scouting ones, and drop the RatesMonitoring and DQMHistograms
761  paths.append( "-*Output" )
762  paths.append( "-RatesMonitoring")
763  paths.append( "-DQMHistograms")
764  if self.config.fragment: paths.append( "Scouting*Output" )
765 
766  elif self.config.output in ('dqm', 'minimal', 'full'):
767  if self.config.paths:
768  # keep only the Paths and EndPaths requested explicitly, and the DQMHistograms
769  paths.append( "DQMHistograms" )
770  else:
771  # drop all output EndPaths but the Scouting ones, and drop the RatesMonitoring
772  paths.append( "-*Output" )
773  paths.append( "-RatesMonitoring")
774  if self.config.fragment: paths.append( "Scouting*Output" )
775 
776  else:
777  if self.config.paths:
778  # keep all output EndPaths, including the DQMHistograms
779  paths.append( "*Output" )
780  paths.append( "DQMHistograms" )
781  else:
782  # keep all Paths and EndPaths
783  pass
784 
785  # drop unwanted paths for profiling (and timing studies)
786  if self.config.profiling:
787  paths.append( "-HLTAnalyzerEndpath" )
788 
789  # this should never be in any dump (nor online menu)
790  paths.append( "-OfflineOutput" )
791 
792  # expand all wildcards
793  paths = self.expandWildcards(paths, self.all_paths)
794 
795  if self.config.paths:
796  # do an "additive" consolidation
797  paths = self.consolidatePositiveList(paths)
798  if not paths:
799  raise RuntimeError('Error: option "--paths %s" does not select any valid paths' % self.config.paths)
800  else:
801  # do a "subtractive" consolidation
802  paths = self.consolidateNegativeList(paths)
803  self.options['paths'] = paths
804 
805  def buildOptions(self):
806  # common configuration for all scenarios
807  self.options['services'].append( "-DQM" )
808  self.options['services'].append( "-FUShmDQMOutputService" )
809  self.options['services'].append( "-MicroStateService" )
810  self.options['services'].append( "-ModuleWebRegistry" )
811  self.options['services'].append( "-TimeProfilerService" )
812 
813  # remove the DAQ modules and the online definition of the DQMStore and DQMFileSaver
814  # unless a hilton-like configuration has been requested
815  if not self.config.hilton:
816  self.options['services'].append( "-EvFDaqDirector" )
817  self.options['services'].append( "-FastMonitoringService" )
818  self.options['services'].append( "-DQMStore" )
819  self.options['modules'].append( "-hltDQMFileSaver" )
820  self.options['modules'].append( "-hltDQMFileSaverPB" )
821 
822  if self.config.fragment:
823  # extract a configuration file fragment
824  self.options['essources'].append( "-GlobalTag" )
825  self.options['essources'].append( "-HepPDTESSource" )
826  self.options['essources'].append( "-XMLIdealGeometryESSource" )
827  self.options['essources'].append( "-eegeom" )
828  self.options['essources'].append( "-es_hardcode" )
829  self.options['essources'].append( "-magfield" )
830 
831  self.options['esmodules'].append( "-SlaveField0" )
832  self.options['esmodules'].append( "-SlaveField20" )
833  self.options['esmodules'].append( "-SlaveField30" )
834  self.options['esmodules'].append( "-SlaveField35" )
835  self.options['esmodules'].append( "-SlaveField38" )
836  self.options['esmodules'].append( "-SlaveField40" )
837  self.options['esmodules'].append( "-VBF0" )
838  self.options['esmodules'].append( "-VBF20" )
839  self.options['esmodules'].append( "-VBF30" )
840  self.options['esmodules'].append( "-VBF35" )
841  self.options['esmodules'].append( "-VBF38" )
842  self.options['esmodules'].append( "-VBF40" )
843  self.options['esmodules'].append( "-CSCGeometryESModule" )
844  self.options['esmodules'].append( "-CaloGeometryBuilder" )
845  self.options['esmodules'].append( "-CaloTowerHardcodeGeometryEP" )
846  self.options['esmodules'].append( "-CastorHardcodeGeometryEP" )
847  self.options['esmodules'].append( "-DTGeometryESModule" )
848  self.options['esmodules'].append( "-EcalBarrelGeometryEP" )
849  self.options['esmodules'].append( "-EcalElectronicsMappingBuilder" )
850  self.options['esmodules'].append( "-EcalEndcapGeometryEP" )
851  self.options['esmodules'].append( "-EcalLaserCorrectionService" )
852  self.options['esmodules'].append( "-EcalPreshowerGeometryEP" )
853  self.options['esmodules'].append( "-GEMGeometryESModule" )
854  self.options['esmodules'].append( "-HcalHardcodeGeometryEP" )
855  self.options['esmodules'].append( "-HcalTopologyIdealEP" )
856  self.options['esmodules'].append( "-MuonNumberingInitialization" )
857  self.options['esmodules'].append( "-ParametrizedMagneticFieldProducer" )
858  self.options['esmodules'].append( "-RPCGeometryESModule" )
859  self.options['esmodules'].append( "-SiStripGainESProducer" )
860  self.options['esmodules'].append( "-SiStripRecHitMatcherESProducer" )
861  self.options['esmodules'].append( "-SiStripQualityESProducer" )
862  self.options['esmodules'].append( "-StripCPEfromTrackAngleESProducer" )
863  self.options['esmodules'].append( "-TrackerAdditionalParametersPerDetESModule" )
864  self.options['esmodules'].append( "-TrackerDigiGeometryESModule" )
865  self.options['esmodules'].append( "-TrackerGeometricDetESModule" )
866  self.options['esmodules'].append( "-VolumeBasedMagneticFieldESProducer" )
867  self.options['esmodules'].append( "-ZdcHardcodeGeometryEP" )
868  self.options['esmodules'].append( "-hcal_db_producer" )
869  self.options['esmodules'].append( "-L1GtTriggerMaskAlgoTrigTrivialProducer" )
870  self.options['esmodules'].append( "-L1GtTriggerMaskTechTrigTrivialProducer" )
871  self.options['esmodules'].append( "-hltESPEcalTrigTowerConstituentsMapBuilder" )
872  self.options['esmodules'].append( "-hltESPGlobalTrackingGeometryESProducer" )
873  self.options['esmodules'].append( "-hltESPMuonDetLayerGeometryESProducer" )
874  self.options['esmodules'].append( "-hltESPTrackerRecoGeometryESProducer" )
875  self.options['esmodules'].append( "-trackerTopology" )
876 
877  self.options['esmodules'].append( "-CaloTowerGeometryFromDBEP" )
878  self.options['esmodules'].append( "-CastorGeometryFromDBEP" )
879  self.options['esmodules'].append( "-EcalBarrelGeometryFromDBEP" )
880  self.options['esmodules'].append( "-EcalEndcapGeometryFromDBEP" )
881  self.options['esmodules'].append( "-EcalPreshowerGeometryFromDBEP" )
882  self.options['esmodules'].append( "-HcalGeometryFromDBEP" )
883  self.options['esmodules'].append( "-ZdcGeometryFromDBEP" )
884  self.options['esmodules'].append( "-XMLFromDBSource" )
885  self.options['esmodules'].append( "-sistripconn" )
886 
887  self.options['services'].append( "-MessageLogger" )
888 
889  self.options['psets'].append( "-maxEvents" )
890  self.options['psets'].append( "-options" )
891 
892  # remove Scouting OutputModules even though the EndPaths are kept
893  self.options['modules'].append( "-hltOutputScoutingCaloMuon" )
894  self.options['modules'].append( "-hltOutputScoutingPF" )
895 
896  if self.config.fragment or (self.config.prescale and (self.config.prescale.lower() == 'none')):
897  self.options['services'].append( "-PrescaleService" )
898 
899  if self.config.fragment or self.config.timing:
900  self.options['services'].append( "-FastTimerService" )
901  self.options['services'].append( "-ThroughputService" )
902 
903 
904  def append_filenames(self, name, filenames):
905  if len(filenames) > 255:
906  token_open = "( *("
907  token_close = ") )"
908  else:
909  token_open = "("
910  token_close = ")"
911 
912  self.data += " %s = cms.untracked.vstring%s\n" % (name, token_open)
913  for line in filenames:
914  self.data += " '%s',\n" % line
915  self.data += " %s,\n" % (token_close)
916 
917 
918  def expand_filenames(self, input):
919  # check if the input is a dataset or a list of files
920  if input[0:8] == 'dataset:':
921  from .dasFileQuery import dasFileQuery
922  # extract the dataset name, and use DAS to fine the list of LFNs
923  dataset = input[8:]
924  files = dasFileQuery(dataset)
925  else:
926  # assume a comma-separated list of input files
927  files = input.split(',')
928  return files
929 
930  def build_source(self):
931  if self.config.hilton:
932  # use the DAQ source
933  return
934 
935  if self.config.input:
936  # if a dataset or a list of input files was given, use it
937  self.source = self.expand_filenames(self.config.input)
938  elif self.config.data:
939  # offline we can run on data...
940  self.source = [ "file:RelVal_Raw_%s_DATA.root" % self.config.type ]
941  else:
942  # ...or on mc
943  self.source = [ "file:RelVal_Raw_%s_MC.root" % self.config.type ]
944 
945  if self.config.parent:
946  # if a dataset or a list of input files was given for the parent data, use it
947  self.parent = self.expand_filenames(self.config.parent)
948 
949  self.data += """
950 # source module (EDM inputs)
951 %(process)s.source = cms.Source( "PoolSource",
952 """
953  self.append_filenames("fileNames", self.source)
954  if (self.parent):
955  self.append_filenames("secondaryFileNames", self.parent)
956  self.data += """\
957  inputCommands = cms.untracked.vstring(
958  'keep *'
959  )
960 )
961 """
def removeElementFromSequencesTasksAndPaths(self, label)
Definition: confdb.py:631
def __init__(self, configuration)
Definition: confdb.py:23
def splitter(iterator, n)
Definition: confdb.py:11
def loadSetupCff(self)
Definition: confdb.py:554
def addGlobalOptions(self)
Definition: confdb.py:325
def getSetupConfigurationFromDB(self)
Definition: confdb.py:60
def overrideProcessName(self)
Definition: confdb.py:561
def runL1Emulator(self)
Definition: confdb.py:460
def instrumentErrorEventType(self)
Definition: confdb.py:398
def buildOptions(self)
Definition: confdb.py:805
def replace(string, replacements)
void find(edm::Handle< EcalRecHitCollection > &hits, DetId thisDet, std::vector< EcalRecHitCollection::const_iterator > &hit, bool debug=false)
Definition: FindCaloHit.cc:19
def overrideOutput(self)
Definition: confdb.py:470
def dump(self)
Definition: confdb.py:167
def getPathList(self)
Definition: confdb.py:101
def customize(self)
Definition: confdb.py:241
Definition: query.py:1
def addEras(self)
Definition: confdb.py:546
def expand_filenames(self, input)
Definition: confdb.py:918
def updateMessageLogger(self)
Definition: confdb.py:581
def overrideL1MenuXml(self)
Definition: confdb.py:450
def overrideGlobalTag(self)
Definition: confdb.py:406
def specificCustomize(self)
Definition: confdb.py:176
def consolidatePositiveList(elements)
Definition: confdb.py:154
def overrideParameters(self, module, parameters)
Definition: confdb.py:623
def instrumentOpenMode(self)
Definition: confdb.py:384
def dumppaths(paths)
Definition: confdb.py:734
def getRawConfigurationFromDB(self)
Definition: confdb.py:83
def loadAdditionalConditions(self, comment, conditions)
Definition: confdb.py:595
def build_source(self)
Definition: confdb.py:930
def loadCffCommand(self, module)
Definition: confdb.py:612
def instrumentDQM(self)
Definition: confdb.py:702
static std::string join(char **cmd)
Definition: RemoteFile.cc:19
def loadCff(self, module)
Definition: confdb.py:619
def buildPathList(self)
Definition: confdb.py:740
def fixPrescales(self)
Definition: confdb.py:360
def consolidateNegativeList(elements)
Definition: confdb.py:142
def instrumentTiming(self)
Definition: confdb.py:639
def expandWildcards(globs, collection)
Definition: confdb.py:126
def _fix_parameter(self, args)
Definition: confdb.py:341
def append_filenames(self, name, filenames)
Definition: confdb.py:904