CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
ConfigBuilder.py
Go to the documentation of this file.
1 #! /usr/bin/env python3
2 
3 from __future__ import print_function
4 __version__ = "$Revision: 1.19 $"
5 __source__ = "$Source: /local/reps/CMSSW/CMSSW/Configuration/Applications/python/ConfigBuilder.py,v $"
6 
7 import FWCore.ParameterSet.Config as cms
8 from FWCore.ParameterSet.Modules import _Module
9 # The following import is provided for backward compatibility reasons.
10 # The function used to be defined in this file.
11 from FWCore.ParameterSet.MassReplace import massReplaceInputTag as MassReplaceInputTag
12 
13 import hashlib
14 import sys
15 import re
16 import collections
17 from subprocess import Popen,PIPE
18 import FWCore.ParameterSet.DictTypes as DictTypes
19 class Options:
20  pass
21 
22 # the canonical defaults
23 defaultOptions = Options()
24 defaultOptions.datamix = 'DataOnSim'
25 defaultOptions.isMC=False
26 defaultOptions.isData=True
27 defaultOptions.step=''
28 defaultOptions.pileup='NoPileUp'
29 defaultOptions.pileup_input = None
30 defaultOptions.pileup_dasoption = ''
31 defaultOptions.geometry = 'SimDB'
32 defaultOptions.geometryExtendedOptions = ['ExtendedGFlash','Extended','NoCastor']
33 defaultOptions.magField = ''
34 defaultOptions.conditions = None
35 defaultOptions.scenarioOptions=['pp','cosmics','nocoll','HeavyIons']
36 defaultOptions.harvesting= 'AtRunEnd'
37 defaultOptions.gflash = False
38 defaultOptions.number = -1
39 defaultOptions.number_out = None
40 defaultOptions.arguments = ""
41 defaultOptions.name = "NO NAME GIVEN"
42 defaultOptions.evt_type = ""
43 defaultOptions.filein = ""
44 defaultOptions.dasquery=""
45 defaultOptions.dasoption=""
46 defaultOptions.secondfilein = ""
47 defaultOptions.customisation_file = []
48 defaultOptions.customisation_file_unsch = []
49 defaultOptions.customise_commands = ""
50 defaultOptions.inline_custom=False
51 defaultOptions.particleTable = 'pythiapdt'
52 defaultOptions.particleTableList = ['pythiapdt','pdt']
53 defaultOptions.dirin = ''
54 defaultOptions.dirout = ''
55 defaultOptions.filetype = 'EDM'
56 defaultOptions.fileout = 'output.root'
57 defaultOptions.filtername = ''
58 defaultOptions.lazy_download = False
59 defaultOptions.custom_conditions = ''
60 defaultOptions.hltProcess = ''
61 defaultOptions.eventcontent = None
62 defaultOptions.datatier = None
63 defaultOptions.inlineEventContent = True
64 defaultOptions.inlineObjets =''
65 defaultOptions.hideGen=False
66 from Configuration.StandardSequences.VtxSmeared import VtxSmearedDefaultKey,VtxSmearedHIDefaultKey
67 defaultOptions.beamspot=None
68 defaultOptions.outputDefinition =''
69 defaultOptions.inputCommands = None
70 defaultOptions.outputCommands = None
71 defaultOptions.inputEventContent = ''
72 defaultOptions.dropDescendant = False
73 defaultOptions.relval = None
74 defaultOptions.profile = None
75 defaultOptions.isRepacked = False
76 defaultOptions.restoreRNDSeeds = False
77 defaultOptions.donotDropOnInput = ''
78 defaultOptions.python_filename =''
79 defaultOptions.io=None
80 defaultOptions.lumiToProcess=None
81 defaultOptions.fast=False
82 defaultOptions.runsAndWeightsForMC = None
83 defaultOptions.runsScenarioForMC = None
84 defaultOptions.runsAndWeightsForMCIntegerWeights = None
85 defaultOptions.runsScenarioForMCIntegerWeights = None
86 defaultOptions.runUnscheduled = False
87 defaultOptions.timeoutOutput = False
88 defaultOptions.nThreads = '1'
89 defaultOptions.nStreams = '0'
90 defaultOptions.nConcurrentLumis = '0'
91 defaultOptions.nConcurrentIOVs = '1'
92 
93 # some helper routines
94 def dumpPython(process,name):
95  theObject = getattr(process,name)
96  if isinstance(theObject,cms.Path) or isinstance(theObject,cms.EndPath) or isinstance(theObject,cms.Sequence):
97  return "process."+name+" = " + theObject.dumpPython()
98  elif isinstance(theObject,_Module) or isinstance(theObject,cms.ESProducer):
99  return "process."+name+" = " + theObject.dumpPython()+"\n"
100  else:
101  return "process."+name+" = " + theObject.dumpPython()+"\n"
102 def filesFromList(fileName,s=None):
103  import os
104  import FWCore.ParameterSet.Config as cms
105  prim=[]
106  sec=[]
107  for line in open(fileName,'r'):
108  if line.count(".root")>=2:
109  #two files solution...
110  entries=line.replace("\n","").split()
111  prim.append(entries[0])
112  sec.append(entries[1])
113  elif (line.find(".root")!=-1):
114  entry=line.replace("\n","")
115  prim.append(entry)
116  # remove any duplicates
117  prim = sorted(list(set(prim)))
118  sec = sorted(list(set(sec)))
119  if s:
120  if not hasattr(s,"fileNames"):
121  s.fileNames=cms.untracked.vstring(prim)
122  else:
123  s.fileNames.extend(prim)
124  if len(sec)!=0:
125  if not hasattr(s,"secondaryFileNames"):
126  s.secondaryFileNames=cms.untracked.vstring(sec)
127  else:
128  s.secondaryFileNames.extend(sec)
129  print("found files: ",prim)
130  if len(prim)==0:
131  raise Exception("There are not files in input from the file list")
132  if len(sec)!=0:
133  print("found parent files:",sec)
134  return (prim,sec)
135 
136 def filesFromDASQuery(query,option="",s=None):
137  import os,time
138  import FWCore.ParameterSet.Config as cms
139  prim=[]
140  sec=[]
141  print("the query is",query)
142  eC=5
143  count=0
144  while eC!=0 and count<3:
145  if count!=0:
146  print('Sleeping, then retrying DAS')
147  time.sleep(100)
148  p = Popen('dasgoclient %s --query "%s"'%(option,query), stdout=PIPE,shell=True, universal_newlines=True)
149  pipe=p.stdout.read()
150  tupleP = os.waitpid(p.pid, 0)
151  eC=tupleP[1]
152  count=count+1
153  if eC==0:
154  print("DAS succeeded after",count,"attempts",eC)
155  else:
156  print("DAS failed 3 times- I give up")
157  for line in pipe.split('\n'):
158  if line.count(".root")>=2:
159  #two files solution...
160  entries=line.replace("\n","").split()
161  prim.append(entries[0])
162  sec.append(entries[1])
163  elif (line.find(".root")!=-1):
164  entry=line.replace("\n","")
165  prim.append(entry)
166  # remove any duplicates
167  prim = sorted(list(set(prim)))
168  sec = sorted(list(set(sec)))
169  if s:
170  if not hasattr(s,"fileNames"):
171  s.fileNames=cms.untracked.vstring(prim)
172  else:
173  s.fileNames.extend(prim)
174  if len(sec)!=0:
175  if not hasattr(s,"secondaryFileNames"):
176  s.secondaryFileNames=cms.untracked.vstring(sec)
177  else:
178  s.secondaryFileNames.extend(sec)
179  print("found files: ",prim)
180  if len(sec)!=0:
181  print("found parent files:",sec)
182  return (prim,sec)
183 
184 def anyOf(listOfKeys,dict,opt=None):
185  for k in listOfKeys:
186  if k in dict:
187  toReturn=dict[k]
188  dict.pop(k)
189  return toReturn
190  if opt!=None:
191  return opt
192  else:
193  raise Exception("any of "+','.join(listOfKeys)+" are mandatory entries of --output options")
194 
195 class ConfigBuilder(object):
196  """The main building routines """
197 
198  def __init__(self, options, process = None, with_output = False, with_input = False ):
199  """options taken from old cmsDriver and optparse """
200 
201  options.outfile_name = options.dirout+options.fileout
202 
203  self._options = options
204 
205  if self._options.isData and options.isMC:
206  raise Exception("ERROR: You may specify only --data or --mc, not both")
207  #if not self._options.conditions:
208  # raise Exception("ERROR: No conditions given!\nPlease specify conditions. E.g. via --conditions=IDEAL_30X::All")
209 
210  # check that MEtoEDMConverter (running in ENDJOB) and DQMIO don't run in the same job
211  if 'ENDJOB' in self._options.step:
212  if (hasattr(self._options,"outputDefinition") and \
213  self._options.outputDefinition != '' and \
214  any(anyOf(['t','tier','dataTier'],outdic) == 'DQMIO' for outdic in eval(self._options.outputDefinition))) or \
215  (hasattr(self._options,"datatier") and \
216  self._options.datatier and \
217  'DQMIO' in self._options.datatier):
218  print("removing ENDJOB from steps since not compatible with DQMIO dataTier")
219  self._options.step=self._options.step.replace(',ENDJOB','')
220 
221 
222 
223  # what steps are provided by this class?
224  stepList = [re.sub(r'^prepare_', '', methodName) for methodName in ConfigBuilder.__dict__ if methodName.startswith('prepare_')]
225  self.stepMap={}
226  self.stepKeys=[]
227  for step in self._options.step.split(","):
228  if step=='': continue
229  stepParts = step.split(":")
230  stepName = stepParts[0]
231  if stepName not in stepList and not stepName.startswith('re'):
232  raise ValueError("Step "+stepName+" unknown")
233  if len(stepParts)==1:
234  self.stepMap[stepName]=""
235  elif len(stepParts)==2:
236  self.stepMap[stepName]=stepParts[1].split('+')
237  elif len(stepParts)==3:
238  self.stepMap[stepName]=(stepParts[2].split('+'),stepParts[1])
239  else:
240  raise ValueError("Step definition "+step+" invalid")
241  self.stepKeys.append(stepName)
242 
243  #print "map of steps is:",self.stepMap
244 
245  self.with_output = with_output
246  self.process=process
247 
248  if hasattr(self._options,"no_output_flag") and self._options.no_output_flag:
249  self.with_output = False
250  self.with_input = with_input
251  self.imports = []
252  self.create_process()
253  self.define_Configs()
254  self.schedule = list()
256 
257  # we are doing three things here:
258  # creating a process to catch errors
259  # building the code to re-create the process
260 
262  # TODO: maybe a list of to be dumped objects would help as well
263  self.blacklist_paths = []
264  self.addedObjects = []
266 
272 
273  def profileOptions(self):
274  """
275  addIgProfService
276  Function to add the igprof profile service so that you can dump in the middle
277  of the run.
278  """
279  profileOpts = self._options.profile.split(':')
280  profilerStart = 1
281  profilerInterval = 100
282  profilerFormat = None
283  profilerJobFormat = None
284 
285  if len(profileOpts):
286  #type, given as first argument is unused here
287  profileOpts.pop(0)
288  if len(profileOpts):
289  startEvent = profileOpts.pop(0)
290  if not startEvent.isdigit():
291  raise Exception("%s is not a number" % startEvent)
292  profilerStart = int(startEvent)
293  if len(profileOpts):
294  eventInterval = profileOpts.pop(0)
295  if not eventInterval.isdigit():
296  raise Exception("%s is not a number" % eventInterval)
297  profilerInterval = int(eventInterval)
298  if len(profileOpts):
299  profilerFormat = profileOpts.pop(0)
300 
301 
302  if not profilerFormat:
303  profilerFormat = "%s___%s___%%I.gz" % (
304  self._options.evt_type.replace("_cfi", ""),
305  hashlib.md5(
306  (str(self._options.step) + str(self._options.pileup) + str(self._options.conditions) +
307  str(self._options.datatier) + str(self._options.profileTypeLabel)).encode('utf-8')
308  ).hexdigest()
309  )
310  if not profilerJobFormat and profilerFormat.endswith(".gz"):
311  profilerJobFormat = profilerFormat.replace(".gz", "_EndOfJob.gz")
312  elif not profilerJobFormat:
313  profilerJobFormat = profilerFormat + "_EndOfJob.gz"
314 
315  return (profilerStart,profilerInterval,profilerFormat,profilerJobFormat)
316 
317  def load(self,includeFile):
318  includeFile = includeFile.replace('/','.')
319  self.process.load(includeFile)
320  return sys.modules[includeFile]
321 
322  def loadAndRemember(self, includeFile):
323  """helper routine to load am memorize imports"""
324  # we could make the imports a on-the-fly data method of the process instance itself
325  # not sure if the latter is a good idea
326  includeFile = includeFile.replace('/','.')
327  self.imports.append(includeFile)
328  self.process.load(includeFile)
329  return sys.modules[includeFile]
330 
331  def executeAndRemember(self, command):
332  """helper routine to remember replace statements"""
333  self.additionalCommands.append(command)
334  if not command.strip().startswith("#"):
335  # substitute: process.foo = process.bar -> self.process.foo = self.process.bar
336  import re
337  exec(re.sub(r"([^a-zA-Z_0-9]|^)(process)([^a-zA-Z_0-9])",r"\1self.process\3",command))
338  #exec(command.replace("process.","self.process."))
339 
340  def addCommon(self):
341  if 'HARVESTING' in self.stepMap.keys() or 'ALCAHARVEST' in self.stepMap.keys():
342  self.process.options.Rethrow = ['ProductNotFound']
343  self.process.options.fileMode = 'FULLMERGE'
344 
345  self.addedObjects.append(("","options"))
346 
347  if self._options.lazy_download:
348  self.process.AdaptorConfig = cms.Service("AdaptorConfig",
349  stats = cms.untracked.bool(True),
350  enable = cms.untracked.bool(True),
351  cacheHint = cms.untracked.string("lazy-download"),
352  readHint = cms.untracked.string("read-ahead-buffered")
353  )
354  self.addedObjects.append(("Setup lazy download","AdaptorConfig"))
355 
356  #self.process.cmsDriverCommand = cms.untracked.PSet( command=cms.untracked.string('cmsDriver.py '+self._options.arguments) )
357  #self.addedObjects.append(("what cmsDriver command was used","cmsDriverCommand"))
358 
359  if self._options.profile:
360  (start, interval, eventFormat, jobFormat)=self.profileOptions()
361  self.process.IgProfService = cms.Service("IgProfService",
362  reportFirstEvent = cms.untracked.int32(start),
363  reportEventInterval = cms.untracked.int32(interval),
364  reportToFileAtPostEvent = cms.untracked.string("| gzip -c > %s"%(eventFormat)),
365  reportToFileAtPostEndJob = cms.untracked.string("| gzip -c > %s"%(jobFormat)))
366  self.addedObjects.append(("Setup IGProf Service for profiling","IgProfService"))
367 
368  def addMaxEvents(self):
369  """Here we decide how many evts will be processed"""
370  self.process.maxEvents.input = int(self._options.number)
371  if self._options.number_out:
372  self.process.maxEvents.output = int(self._options.number_out)
373  self.addedObjects.append(("","maxEvents"))
374 
375  def addSource(self):
376  """Here the source is built. Priority: file, generator"""
377  self.addedObjects.append(("Input source","source"))
378 
379  def filesFromOption(self):
380  for entry in self._options.filein.split(','):
381  print("entry",entry)
382  if entry.startswith("filelist:"):
383  filesFromList(entry[9:],self.process.source)
384  elif entry.startswith("dbs:") or entry.startswith("das:"):
385  filesFromDASQuery('file dataset = %s'%(entry[4:]),self._options.dasoption,self.process.source)
386  else:
387  self.process.source.fileNames.append(self._options.dirin+entry)
388  if self._options.secondfilein:
389  if not hasattr(self.process.source,"secondaryFileNames"):
390  raise Exception("--secondfilein not compatible with "+self._options.filetype+"input type")
391  for entry in self._options.secondfilein.split(','):
392  print("entry",entry)
393  if entry.startswith("filelist:"):
394  self.process.source.secondaryFileNames.extend((filesFromList(entry[9:]))[0])
395  elif entry.startswith("dbs:") or entry.startswith("das:"):
396  self.process.source.secondaryFileNames.extend((filesFromDASQuery('file dataset = %s'%(entry[4:]),self._options.dasoption))[0])
397  else:
398  self.process.source.secondaryFileNames.append(self._options.dirin+entry)
399 
400  if self._options.filein or self._options.dasquery:
401  if self._options.filetype == "EDM":
402  self.process.source=cms.Source("PoolSource",
403  fileNames = cms.untracked.vstring(),
404  secondaryFileNames= cms.untracked.vstring())
405  filesFromOption(self)
406  elif self._options.filetype == "DAT":
407  self.process.source=cms.Source("NewEventStreamFileReader",fileNames = cms.untracked.vstring())
408  filesFromOption(self)
409  elif self._options.filetype == "LHE":
410  self.process.source=cms.Source("LHESource", fileNames = cms.untracked.vstring())
411  if self._options.filein.startswith("lhe:"):
412  #list the article directory automatically
413  args=self._options.filein.split(':')
414  article=args[1]
415  print('LHE input from article ',article)
416  location='/store/lhe/'
417  import os
418  textOfFiles=os.popen('cmsLHEtoEOSManager.py -l '+article)
419  for line in textOfFiles:
420  for fileName in [x for x in line.split() if '.lhe' in x]:
421  self.process.source.fileNames.append(location+article+'/'+fileName)
422  #check first if list of LHE files is loaded (not empty)
423  if len(line)<2:
424  print('Issue to load LHE files, please check and try again.')
425  sys.exit(-1)
426  #Additional check to protect empty fileNames in process.source
427  if len(self.process.source.fileNames)==0:
428  print('Issue with empty filename, but can pass line check')
429  sys.exit(-1)
430  if len(args)>2:
431  self.process.source.skipEvents = cms.untracked.uint32(int(args[2]))
432  else:
433  filesFromOption(self)
434 
435  elif self._options.filetype == "DQM":
436  self.process.source=cms.Source("DQMRootSource",
437  fileNames = cms.untracked.vstring())
438  filesFromOption(self)
439 
440  elif self._options.filetype == "DQMDAQ":
441  # FIXME: how to configure it if there are no input files specified?
442  self.process.source=cms.Source("DQMStreamerReader")
443 
444 
445  if ('HARVESTING' in self.stepMap.keys() or 'ALCAHARVEST' in self.stepMap.keys()) and (not self._options.filetype == "DQM"):
446  self.process.source.processingMode = cms.untracked.string("RunsAndLumis")
447 
448  if self._options.dasquery!='':
449  self.process.source=cms.Source("PoolSource", fileNames = cms.untracked.vstring(),secondaryFileNames = cms.untracked.vstring())
450  filesFromDASQuery(self._options.dasquery,self._options.dasoption,self.process.source)
451 
452  if ('HARVESTING' in self.stepMap.keys() or 'ALCAHARVEST' in self.stepMap.keys()) and (not self._options.filetype == "DQM"):
453  self.process.source.processingMode = cms.untracked.string("RunsAndLumis")
454 
455  ##drop LHEXMLStringProduct on input to save memory if appropriate
456  if 'GEN' in self.stepMap.keys() and not self._options.filetype == "LHE":
457  if self._options.inputCommands:
458  self._options.inputCommands+=',drop LHEXMLStringProduct_*_*_*,'
459  else:
460  self._options.inputCommands='keep *, drop LHEXMLStringProduct_*_*_*,'
461 
462  if self.process.source and self._options.inputCommands and not self._options.filetype == "LHE":
463  if not hasattr(self.process.source,'inputCommands'): self.process.source.inputCommands=cms.untracked.vstring()
464  for command in self._options.inputCommands.split(','):
465  # remove whitespace around the keep/drop statements
466  command = command.strip()
467  if command=='': continue
468  self.process.source.inputCommands.append(command)
469  if not self._options.dropDescendant:
470  self.process.source.dropDescendantsOfDroppedBranches = cms.untracked.bool(False)
471 
472  if self._options.lumiToProcess:
473  import FWCore.PythonUtilities.LumiList as LumiList
474  self.process.source.lumisToProcess = cms.untracked.VLuminosityBlockRange( LumiList.LumiList(self._options.lumiToProcess).getCMSSWString().split(',') )
475 
476  if 'GEN' in self.stepMap.keys() or 'LHE' in self.stepMap or (not self._options.filein and hasattr(self._options, "evt_type")):
477  if self.process.source is None:
478  self.process.source=cms.Source("EmptySource")
479 
480  # modify source in case of run-dependent MC
481  self.runsAndWeights=None
482  if self._options.runsAndWeightsForMC or self._options.runsScenarioForMC :
483  if not self._options.isMC :
484  raise Exception("options --runsAndWeightsForMC and --runsScenarioForMC are only valid for MC")
485  if self._options.runsAndWeightsForMC:
486  self.runsAndWeights = eval(self._options.runsAndWeightsForMC)
487  else:
488  from Configuration.StandardSequences.RunsAndWeights import RunsAndWeights
489  if isinstance(RunsAndWeights[self._options.runsScenarioForMC], str):
490  __import__(RunsAndWeights[self._options.runsScenarioForMC])
491  self.runsAndWeights = sys.modules[RunsAndWeights[self._options.runsScenarioForMC]].runProbabilityDistribution
492  else:
493  self.runsAndWeights = RunsAndWeights[self._options.runsScenarioForMC]
494 
495  if self.runsAndWeights:
496  import SimGeneral.Configuration.ThrowAndSetRandomRun as ThrowAndSetRandomRun
498  self.additionalCommands.append('import SimGeneral.Configuration.ThrowAndSetRandomRun as ThrowAndSetRandomRun')
499  self.additionalCommands.append('ThrowAndSetRandomRun.throwAndSetRandomRun(process.source,%s)'%(self.runsAndWeights))
500 
501  # modify source in case of run-dependent MC (Run-3 method)
503  if self._options.runsAndWeightsForMCIntegerWeights or self._options.runsScenarioForMCIntegerWeights:
504  if not self._options.isMC :
505  raise Exception("options --runsAndWeightsForMCIntegerWeights and --runsScenarioForMCIntegerWeights are only valid for MC")
506  if self._options.runsAndWeightsForMCIntegerWeights:
507  self.runsAndWeightsInt = eval(self._options.runsAndWeightsForMCIntegerWeights)
508  else:
509  from Configuration.StandardSequences.RunsAndWeights import RunsAndWeights
510  if isinstance(RunsAndWeights[self._options.runsScenarioForMCIntegerWeights], str):
511  __import__(RunsAndWeights[self._options.runsScenarioForMCIntegerWeights])
512  self.runsAndWeightsInt = sys.modules[RunsAndWeights[self._options.runsScenarioForMCIntegerWeights]].runProbabilityDistribution
513  else:
514  self.runsAndWeightsInt = RunsAndWeights[self._options.runsScenarioForMCIntegerWeights]
515 
516  if self.runsAndWeightsInt:
517  if not self._options.relval:
518  raise Exception("--relval option required when using --runsAndWeightsInt")
519  if 'DATAMIX' in self._options.step:
520  from SimGeneral.Configuration.LumiToRun import lumi_to_run
521  total_events, events_per_job = self._options.relval.split(',')
522  lumi_to_run_mapping = lumi_to_run(self.runsAndWeightsInt, int(total_events), int(events_per_job))
523  self.additionalCommands.append("process.source.firstLuminosityBlockForEachRun = cms.untracked.VLuminosityBlockID(*[cms.LuminosityBlockID(x,y) for x,y in " + str(lumi_to_run_mapping) + "])")
524 
525  return
526 
527  def addOutput(self):
528  """ Add output module to the process """
529  result=""
530  if self._options.outputDefinition:
531  if self._options.datatier:
532  print("--datatier & --eventcontent options ignored")
533 
534  #new output convention with a list of dict
535  outList = eval(self._options.outputDefinition)
536  for (id,outDefDict) in enumerate(outList):
537  outDefDictStr=outDefDict.__str__()
538  if not isinstance(outDefDict,dict):
539  raise Exception("--output needs to be passed a list of dict"+self._options.outputDefinition+" is invalid")
540  #requires option: tier
541  theTier=anyOf(['t','tier','dataTier'],outDefDict)
542  #optional option: eventcontent, filtername, selectEvents, moduleLabel, filename
543  ## event content
544  theStreamType=anyOf(['e','ec','eventContent','streamType'],outDefDict,theTier)
545  theFilterName=anyOf(['f','ftN','filterName'],outDefDict,'')
546  theSelectEvent=anyOf(['s','sE','selectEvents'],outDefDict,'')
547  theModuleLabel=anyOf(['l','mL','moduleLabel'],outDefDict,'')
548  theExtraOutputCommands=anyOf(['o','oC','outputCommands'],outDefDict,'')
549  # module label has a particular role
550  if not theModuleLabel:
551  tryNames=[theStreamType.replace(theTier.replace('-',''),'')+theTier.replace('-','')+'output',
552  theStreamType.replace(theTier.replace('-',''),'')+theTier.replace('-','')+theFilterName+'output',
553  theStreamType.replace(theTier.replace('-',''),'')+theTier.replace('-','')+theFilterName+theSelectEvent.split(',')[0].replace(':','for').replace(' ','')+'output'
554  ]
555  for name in tryNames:
556  if not hasattr(self.process,name):
557  theModuleLabel=name
558  break
559  if not theModuleLabel:
560  raise Exception("cannot find a module label for specification: "+outDefDictStr)
561  if id==0:
562  defaultFileName=self._options.outfile_name
563  else:
564  defaultFileName=self._options.outfile_name.replace('.root','_in'+theTier+'.root')
565 
566  theFileName=self._options.dirout+anyOf(['fn','fileName'],outDefDict,defaultFileName)
567  if not theFileName.endswith('.root'):
568  theFileName+='.root'
569 
570  if len(outDefDict):
571  raise Exception("unused keys from --output options: "+','.join(outDefDict.keys()))
572  if theStreamType=='DQMIO': theStreamType='DQM'
573  if theStreamType=='ALL':
574  theEventContent = cms.PSet(outputCommands = cms.untracked.vstring('keep *'))
575  else:
576  theEventContent = getattr(self.process, theStreamType+"EventContent")
577 
578 
579  addAlCaSelects=False
580  if theStreamType=='ALCARECO' and not theFilterName:
581  theFilterName='StreamALCACombined'
582  addAlCaSelects=True
583 
584  CppType='PoolOutputModule'
585  if self._options.timeoutOutput:
586  CppType='TimeoutPoolOutputModule'
587  if theStreamType=='DQM' and theTier=='DQMIO': CppType='DQMRootOutputModule'
588  output = cms.OutputModule(CppType,
589  theEventContent.clone(),
590  fileName = cms.untracked.string(theFileName),
591  dataset = cms.untracked.PSet(
592  dataTier = cms.untracked.string(theTier),
593  filterName = cms.untracked.string(theFilterName))
594  )
595  if not theSelectEvent and hasattr(self.process,'generation_step') and theStreamType!='LHE':
596  output.SelectEvents = cms.untracked.PSet(SelectEvents = cms.vstring('generation_step'))
597  if not theSelectEvent and hasattr(self.process,'filtering_step'):
598  output.SelectEvents = cms.untracked.PSet(SelectEvents = cms.vstring('filtering_step'))
599  if theSelectEvent:
600  output.SelectEvents =cms.untracked.PSet(SelectEvents = cms.vstring(theSelectEvent))
601 
602  if addAlCaSelects:
603  if not hasattr(output,'SelectEvents'):
604  output.SelectEvents=cms.untracked.PSet(SelectEvents=cms.vstring())
605  for alca in self.AlCaPaths:
606  output.SelectEvents.SelectEvents.extend(getattr(self.process,'OutALCARECO'+alca).SelectEvents.SelectEvents)
607 
608 
609  if hasattr(self.process,theModuleLabel):
610  raise Exception("the current process already has a module "+theModuleLabel+" defined")
611  #print "creating output module ",theModuleLabel
612  setattr(self.process,theModuleLabel,output)
613  outputModule=getattr(self.process,theModuleLabel)
614  setattr(self.process,theModuleLabel+'_step',cms.EndPath(outputModule))
615  path=getattr(self.process,theModuleLabel+'_step')
616  self.schedule.append(path)
617 
618  if not self._options.inlineEventContent and hasattr(self.process,theStreamType+"EventContent"):
619  def doNotInlineEventContent(instance,label = "cms.untracked.vstring(process."+theStreamType+"EventContent.outputCommands)"):
620  return label
621  outputModule.outputCommands.__dict__["dumpPython"] = doNotInlineEventContent
622  if theExtraOutputCommands:
623  if not isinstance(theExtraOutputCommands,list):
624  raise Exception("extra ouput command in --option must be a list of strings")
625  if hasattr(self.process,theStreamType+"EventContent"):
626  self.executeAndRemember('process.%s.outputCommands.extend(%s)'%(theModuleLabel,theExtraOutputCommands))
627  else:
628  outputModule.outputCommands.extend(theExtraOutputCommands)
629 
630  result+="\nprocess."+theModuleLabel+" = "+outputModule.dumpPython()
631 
632  ##ends the --output options model
633  return result
634 
635  streamTypes=self._options.eventcontent.split(',')
636  tiers=self._options.datatier.split(',')
637  if not self._options.outputDefinition and len(streamTypes)!=len(tiers):
638  raise Exception("number of event content arguments does not match number of datatier arguments")
639 
640  # if the only step is alca we don't need to put in an output
641  if self._options.step.split(',')[0].split(':')[0] == 'ALCA':
642  return "\n"
643 
644  for i,(streamType,tier) in enumerate(zip(streamTypes,tiers)):
645  if streamType=='': continue
646  if streamType == 'ALCARECO' and not 'ALCAPRODUCER' in self._options.step: continue
647  if streamType=='DQMIO': streamType='DQM'
648  eventContent=streamType
649  ## override streamType to eventContent in case NANOEDM
650  if streamType == "NANOEDMAOD" :
651  eventContent = "NANOAOD"
652  elif streamType == "NANOEDMAODSIM" :
653  eventContent = "NANOAODSIM"
654  theEventContent = getattr(self.process, eventContent+"EventContent")
655  if i==0:
656  theFileName=self._options.outfile_name
657  theFilterName=self._options.filtername
658  else:
659  theFileName=self._options.outfile_name.replace('.root','_in'+streamType+'.root')
660  theFilterName=self._options.filtername
661  CppType='PoolOutputModule'
662  if self._options.timeoutOutput:
663  CppType='TimeoutPoolOutputModule'
664  if streamType=='DQM' and tier=='DQMIO': CppType='DQMRootOutputModule'
665  if "NANOAOD" in streamType : CppType='NanoAODOutputModule'
666  output = cms.OutputModule(CppType,
667  theEventContent,
668  fileName = cms.untracked.string(theFileName),
669  dataset = cms.untracked.PSet(dataTier = cms.untracked.string(tier),
670  filterName = cms.untracked.string(theFilterName)
671  )
672  )
673  if hasattr(self.process,"generation_step") and streamType!='LHE':
674  output.SelectEvents = cms.untracked.PSet(SelectEvents = cms.vstring('generation_step'))
675  if hasattr(self.process,"filtering_step"):
676  output.SelectEvents = cms.untracked.PSet(SelectEvents = cms.vstring('filtering_step'))
677 
678  if streamType=='ALCARECO':
679  output.dataset.filterName = cms.untracked.string('StreamALCACombined')
680 
681  if "MINIAOD" in streamType:
682  from PhysicsTools.PatAlgos.slimming.miniAOD_tools import miniAOD_customizeOutput
684 
685  outputModuleName=streamType+'output'
686  setattr(self.process,outputModuleName,output)
687  outputModule=getattr(self.process,outputModuleName)
688  setattr(self.process,outputModuleName+'_step',cms.EndPath(outputModule))
689  path=getattr(self.process,outputModuleName+'_step')
690  self.schedule.append(path)
691 
692  if self._options.outputCommands and streamType!='DQM':
693  for evct in self._options.outputCommands.split(','):
694  if not evct: continue
695  self.executeAndRemember("process.%s.outputCommands.append('%s')"%(outputModuleName,evct.strip()))
696 
697  if not self._options.inlineEventContent:
698  tmpstreamType=streamType
699  if "NANOEDM" in tmpstreamType :
700  tmpstreamType=tmpstreamType.replace("NANOEDM","NANO")
701  def doNotInlineEventContent(instance,label = "process."+tmpstreamType+"EventContent.outputCommands"):
702  return label
703  outputModule.outputCommands.__dict__["dumpPython"] = doNotInlineEventContent
704 
705  result+="\nprocess."+outputModuleName+" = "+outputModule.dumpPython()
706 
707  return result
708 
710  """
711  Add selected standard sequences to the process
712  """
713  # load the pile up file
714  if self._options.pileup:
715  pileupSpec=self._options.pileup.split(',')[0]
716 
717  # Does the requested pile-up scenario exist?
718  from Configuration.StandardSequences.Mixing import Mixing,defineMixing
719  if not pileupSpec in Mixing and '.' not in pileupSpec and 'file:' not in pileupSpec:
720  message = pileupSpec+' is not a know mixing scenario:\n available are: '+'\n'.join(Mixing.keys())
721  raise Exception(message)
722 
723  # Put mixing parameters in a dictionary
724  if '.' in pileupSpec:
725  mixingDict={'file':pileupSpec}
726  elif pileupSpec.startswith('file:'):
727  mixingDict={'file':pileupSpec[5:]}
728  else:
729  import copy
730  mixingDict=copy.copy(Mixing[pileupSpec])
731  if len(self._options.pileup.split(','))>1:
732  mixingDict.update(eval(self._options.pileup[self._options.pileup.find(',')+1:]))
733 
734  # Load the pu cfg file corresponding to the requested pu scenario
735  if 'file:' in pileupSpec:
736  #the file is local
737  self.process.load(mixingDict['file'])
738  print("inlining mixing module configuration")
739  self._options.inlineObjets+=',mix'
740  else:
741  self.loadAndRemember(mixingDict['file'])
742 
743  mixingDict.pop('file')
744  if not "DATAMIX" in self.stepMap.keys(): # when DATAMIX is present, pileup_input refers to pre-mixed GEN-RAW
745  if self._options.pileup_input:
746  if self._options.pileup_input.startswith('dbs:') or self._options.pileup_input.startswith('das:'):
747  mixingDict['F']=filesFromDASQuery('file dataset = %s'%(self._options.pileup_input[4:],),self._options.pileup_dasoption)[0]
748  elif self._options.pileup_input.startswith("filelist:"):
749  mixingDict['F']=(filesFromList(self._options.pileup_input[9:]))[0]
750  else:
751  mixingDict['F']=self._options.pileup_input.split(',')
752  specialization=defineMixing(mixingDict)
753  for command in specialization:
754  self.executeAndRemember(command)
755  if len(mixingDict)!=0:
756  raise Exception('unused mixing specification: '+mixingDict.keys().__str__())
757 
758 
759  # load the geometry file
760  try:
761  if len(self.stepMap):
762  self.loadAndRemember(self.GeometryCFF)
763  if ('SIM' in self.stepMap or 'reSIM' in self.stepMap) and not self._options.fast:
765  if self.geometryDBLabel:
766  self.executeAndRemember('if hasattr(process, "XMLFromDBSource"): process.XMLFromDBSource.label="%s"'%(self.geometryDBLabel))
767  self.executeAndRemember('if hasattr(process, "DDDetectorESProducerFromDB"): process.DDDetectorESProducerFromDB.label="%s"'%(self.geometryDBLabel))
768 
769  except ImportError:
770  print("Geometry option",self._options.geometry,"unknown.")
771  raise
772 
773  if len(self.stepMap):
774  self.loadAndRemember(self.magFieldCFF)
775 
776  for stepName in self.stepKeys:
777  stepSpec = self.stepMap[stepName]
778  print("Step:", stepName,"Spec:",stepSpec)
779  if stepName.startswith('re'):
780  ##add the corresponding input content
781  if stepName[2:] not in self._options.donotDropOnInput:
782  self._options.inputEventContent='%s,%s'%(stepName.upper(),self._options.inputEventContent)
783  stepName=stepName[2:]
784  if stepSpec=="":
785  getattr(self,"prepare_"+stepName)(sequence = getattr(self,stepName+"DefaultSeq"))
786  elif isinstance(stepSpec, list):
787  getattr(self,"prepare_"+stepName)(sequence = '+'.join(stepSpec))
788  elif isinstance(stepSpec, tuple):
789  getattr(self,"prepare_"+stepName)(sequence = ','.join([stepSpec[1],'+'.join(stepSpec[0])]))
790  else:
791  raise ValueError("Invalid step definition")
792 
793  if self._options.restoreRNDSeeds!=False:
794  #it is either True, or a process name
795  if self._options.restoreRNDSeeds==True:
796  self.executeAndRemember('process.RandomNumberGeneratorService.restoreStateLabel=cms.untracked.string("randomEngineStateProducer")')
797  else:
798  self.executeAndRemember('process.RandomNumberGeneratorService.restoreStateTag=cms.untracked.InputTag("randomEngineStateProducer","","%s")'%(self._options.restoreRNDSeeds))
799  if self._options.inputEventContent or self._options.inputCommands:
800  if self._options.inputCommands:
801  self._options.inputCommands+='keep *_randomEngineStateProducer_*_*,'
802  else:
803  self._options.inputCommands='keep *_randomEngineStateProducer_*_*,'
804 
805 
807  if self._options.inputEventContent:
808  import copy
809  def dropSecondDropStar(iec):
810  #drop occurence of 'drop *' in the list
811  count=0
812  for item in iec:
813  if item=='drop *':
814  if count!=0:
815  iec.remove(item)
816  count+=1
817 
818  ## allow comma separated input eventcontent
819  if not hasattr(self.process.source,'inputCommands'): self.process.source.inputCommands=cms.untracked.vstring()
820  for evct in self._options.inputEventContent.split(','):
821  if evct=='': continue
822  theEventContent = getattr(self.process, evct+"EventContent")
823  if hasattr(theEventContent,'outputCommands'):
824  self.process.source.inputCommands.extend(copy.copy(theEventContent.outputCommands))
825  if hasattr(theEventContent,'inputCommands'):
826  self.process.source.inputCommands.extend(copy.copy(theEventContent.inputCommands))
827 
828  dropSecondDropStar(self.process.source.inputCommands)
829 
830  if not self._options.dropDescendant:
831  self.process.source.dropDescendantsOfDroppedBranches = cms.untracked.bool(False)
832 
833 
834  return
835 
836  def addConditions(self):
837  """Add conditions to the process"""
838  if not self._options.conditions: return
839 
840  if 'FrontierConditions_GlobalTag' in self._options.conditions:
841  print('using FrontierConditions_GlobalTag in --conditions is not necessary anymore and will be deprecated soon. please update your command line')
842  self._options.conditions = self._options.conditions.replace("FrontierConditions_GlobalTag,",'')
843 
845  from Configuration.AlCa.GlobalTag import GlobalTag
846  self.process.GlobalTag = GlobalTag(self.process.GlobalTag, self._options.conditions, self._options.custom_conditions)
847  self.additionalCommands.append('from Configuration.AlCa.GlobalTag import GlobalTag')
848  self.additionalCommands.append('process.GlobalTag = GlobalTag(process.GlobalTag, %s, %s)' % (repr(self._options.conditions), repr(self._options.custom_conditions)))
849 
850 
851  def addCustomise(self,unsch=0):
852  """Include the customise code """
853 
854  custOpt=[]
855  if unsch==0:
856  for c in self._options.customisation_file:
857  custOpt.extend(c.split(","))
858  else:
859  for c in self._options.customisation_file_unsch:
860  custOpt.extend(c.split(","))
861 
862  custMap=DictTypes.SortedKeysDict()
863  for opt in custOpt:
864  if opt=='': continue
865  if opt.count('.')>1:
866  raise Exception("more than . in the specification:"+opt)
867  fileName=opt.split('.')[0]
868  if opt.count('.')==0: rest='customise'
869  else:
870  rest=opt.split('.')[1]
871  if rest=='py': rest='customise' #catch the case of --customise file.py
872 
873  if fileName in custMap:
874  custMap[fileName].extend(rest.split('+'))
875  else:
876  custMap[fileName]=rest.split('+')
877 
878  if len(custMap)==0:
879  final_snippet='\n'
880  else:
881  final_snippet='\n# customisation of the process.\n'
882 
883  allFcn=[]
884  for opt in custMap:
885  allFcn.extend(custMap[opt])
886  for fcn in allFcn:
887  if allFcn.count(fcn)!=1:
888  raise Exception("cannot specify twice "+fcn+" as a customisation method")
889 
890  for f in custMap:
891  # let python search for that package and do syntax checking at the same time
892  packageName = f.replace(".py","").replace("/",".")
893  __import__(packageName)
894  package = sys.modules[packageName]
895 
896  # now ask the package for its definition and pick .py instead of .pyc
897  customiseFile = re.sub(r'\.pyc$', '.py', package.__file__)
898 
899  final_snippet+='\n# Automatic addition of the customisation function from '+packageName+'\n'
900  if self._options.inline_custom:
901  for line in file(customiseFile,'r'):
902  if "import FWCore.ParameterSet.Config" in line:
903  continue
904  final_snippet += line
905  else:
906  final_snippet += 'from %s import %s \n'%(packageName,','.join(custMap[f]))
907  for fcn in custMap[f]:
908  print("customising the process with",fcn,"from",f)
909  if not hasattr(package,fcn):
910  #bound to fail at run time
911  raise Exception("config "+f+" has no function "+fcn)
912  #execute the command
913  self.process=getattr(package,fcn)(self.process)
914  #and print it in the configuration
915  final_snippet += "\n#call to customisation function "+fcn+" imported from "+packageName
916  final_snippet += "\nprocess = %s(process)\n"%(fcn,)
917 
918  if len(custMap)!=0:
919  final_snippet += '\n# End of customisation functions\n'
920 
921  ### now for a useful command
922  return final_snippet
923 
925  final_snippet='\n# Customisation from command line\n'
926  if self._options.customise_commands:
927  import string
928  for com in self._options.customise_commands.split('\\n'):
929  com=com.lstrip()
930  self.executeAndRemember(com)
931  final_snippet +='\n'+com
932 
933  return final_snippet
934 
935  #----------------------------------------------------------------------------
936  # here the methods to define the python includes for each step or
937  # conditions
938  #----------------------------------------------------------------------------
939  def define_Configs(self):
940  if len(self.stepMap):
941  self.loadAndRemember('Configuration/StandardSequences/Services_cff')
942  if self._options.particleTable not in defaultOptions.particleTableList:
943  print('Invalid particle table provided. Options are:')
944  print(defaultOptions.particleTable)
945  sys.exit(-1)
946  else:
947  if len(self.stepMap):
948  self.loadAndRemember('SimGeneral.HepPDTESSource.'+self._options.particleTable+'_cfi')
949 
950  self.loadAndRemember('FWCore/MessageService/MessageLogger_cfi')
951 
952  self.ALCADefaultCFF="Configuration/StandardSequences/AlCaRecoStreams_cff"
953  self.GENDefaultCFF="Configuration/StandardSequences/Generator_cff"
954  self.SIMDefaultCFF="Configuration/StandardSequences/Sim_cff"
955  self.DIGIDefaultCFF="Configuration/StandardSequences/Digi_cff"
956  self.DIGI2RAWDefaultCFF="Configuration/StandardSequences/DigiToRaw_cff"
957  self.L1EMDefaultCFF='Configuration/StandardSequences/SimL1Emulator_cff'
958  self.L1MENUDefaultCFF="Configuration/StandardSequences/L1TriggerDefaultMenu_cff"
959  self.HLTDefaultCFF="Configuration/StandardSequences/HLTtable_cff"
960  self.RAW2DIGIDefaultCFF="Configuration/StandardSequences/RawToDigi_Data_cff"
961  if self._options.isRepacked: self.RAW2DIGIDefaultCFF="Configuration/StandardSequences/RawToDigi_DataMapper_cff"
962  self.L1RecoDefaultCFF="Configuration/StandardSequences/L1Reco_cff"
963  self.L1TrackTriggerDefaultCFF="Configuration/StandardSequences/L1TrackTrigger_cff"
964  self.RECODefaultCFF="Configuration/StandardSequences/Reconstruction_Data_cff"
965  self.RECOSIMDefaultCFF="Configuration/StandardSequences/RecoSim_cff"
966  self.PATDefaultCFF="Configuration/StandardSequences/PAT_cff"
967  self.NANODefaultCFF="PhysicsTools/NanoAOD/nano_cff"
968  self.NANOGENDefaultCFF="PhysicsTools/NanoAOD/nanogen_cff"
969  self.EIDefaultCFF=None
970  self.SKIMDefaultCFF="Configuration/StandardSequences/Skims_cff"
971  self.POSTRECODefaultCFF="Configuration/StandardSequences/PostRecoGenerator_cff"
972  self.VALIDATIONDefaultCFF="Configuration/StandardSequences/Validation_cff"
973  self.L1HwValDefaultCFF = "Configuration/StandardSequences/L1HwVal_cff"
974  self.DQMOFFLINEDefaultCFF="DQMOffline/Configuration/DQMOffline_cff"
975  self.HARVESTINGDefaultCFF="Configuration/StandardSequences/Harvesting_cff"
976  self.ALCAHARVESTDefaultCFF="Configuration/StandardSequences/AlCaHarvesting_cff"
977  self.ENDJOBDefaultCFF="Configuration/StandardSequences/EndOfProcess_cff"
978  self.ConditionsDefaultCFF = "Configuration/StandardSequences/FrontierConditions_GlobalTag_cff"
979  self.CFWRITERDefaultCFF = "Configuration/StandardSequences/CrossingFrameWriter_cff"
980  self.REPACKDefaultCFF="Configuration/StandardSequences/DigiToRaw_Repack_cff"
981 
982  if "DATAMIX" in self.stepMap.keys():
983  self.DATAMIXDefaultCFF="Configuration/StandardSequences/DataMixer"+self._options.datamix+"_cff"
984  self.DIGIDefaultCFF="Configuration/StandardSequences/DigiDM_cff"
985  self.DIGI2RAWDefaultCFF="Configuration/StandardSequences/DigiToRawDM_cff"
986  self.L1EMDefaultCFF='Configuration/StandardSequences/SimL1EmulatorDM_cff'
987 
988  self.ALCADefaultSeq=None
989  self.LHEDefaultSeq='externalLHEProducer'
990  self.GENDefaultSeq='pgen'
991  self.SIMDefaultSeq='psim'
992  self.DIGIDefaultSeq='pdigi'
994  self.DIGI2RAWDefaultSeq='DigiToRaw'
995  self.HLTDefaultSeq='GRun'
996  self.L1DefaultSeq=None
1001  self.RAW2DIGIDefaultSeq='RawToDigi'
1002  self.L1RecoDefaultSeq='L1Reco'
1003  self.L1TrackTriggerDefaultSeq='L1TrackTrigger'
1004  if self._options.fast or ('RAW2DIGI' in self.stepMap and 'RECO' in self.stepMap):
1005  self.RECODefaultSeq='reconstruction'
1006  else:
1007  self.RECODefaultSeq='reconstruction_fromRECO'
1008  self.RECOSIMDefaultSeq='recosim'
1009  self.EIDefaultSeq='top'
1011  self.L1HwValDefaultSeq='L1HwVal'
1012  self.DQMDefaultSeq='DQMOffline'
1014  self.ENDJOBDefaultSeq='endOfProcess'
1015  self.REPACKDefaultSeq='DigiToRawRepack'
1016  self.PATDefaultSeq='miniAOD'
1017  self.PATGENDefaultSeq='miniGEN'
1018  #TODO: Check based of file input
1019  self.NANOGENDefaultSeq='nanogenSequence'
1020  self.NANODefaultSeq='nanoSequence'
1021 
1022  self.EVTCONTDefaultCFF="Configuration/EventContent/EventContent_cff"
1023 
1024  if not self._options.beamspot:
1025  self._options.beamspot=VtxSmearedDefaultKey
1026 
1027  # if its MC then change the raw2digi
1028  if self._options.isMC==True:
1029  self.RAW2DIGIDefaultCFF="Configuration/StandardSequences/RawToDigi_cff"
1030  self.RECODefaultCFF="Configuration/StandardSequences/Reconstruction_cff"
1031  self.PATDefaultCFF="Configuration/StandardSequences/PATMC_cff"
1032  self.PATGENDefaultCFF="Configuration/StandardSequences/PATGEN_cff"
1033  self.DQMOFFLINEDefaultCFF="DQMOffline/Configuration/DQMOfflineMC_cff"
1034  self.ALCADefaultCFF="Configuration/StandardSequences/AlCaRecoStreamsMC_cff"
1035  self.NANODefaultSeq='nanoSequenceMC'
1036  else:
1037  self._options.beamspot = None
1038 
1039  #patch for gen, due to backward incompatibility
1040  if 'reGEN' in self.stepMap:
1041  self.GENDefaultSeq='fixGenInfo'
1042 
1043  if self._options.scenario=='cosmics':
1044  self._options.pileup='Cosmics'
1045  self.DIGIDefaultCFF="Configuration/StandardSequences/DigiCosmics_cff"
1046  self.RECODefaultCFF="Configuration/StandardSequences/ReconstructionCosmics_cff"
1047  self.SKIMDefaultCFF="Configuration/StandardSequences/SkimsCosmics_cff"
1048  self.EVTCONTDefaultCFF="Configuration/EventContent/EventContentCosmics_cff"
1049  self.VALIDATIONDefaultCFF="Configuration/StandardSequences/ValidationCosmics_cff"
1050  self.DQMOFFLINEDefaultCFF="DQMOffline/Configuration/DQMOfflineCosmics_cff"
1051  if self._options.isMC==True:
1052  self.DQMOFFLINEDefaultCFF="DQMOffline/Configuration/DQMOfflineCosmicsMC_cff"
1053  self.HARVESTINGDefaultCFF="Configuration/StandardSequences/HarvestingCosmics_cff"
1054  self.RECODefaultSeq='reconstructionCosmics'
1055  self.DQMDefaultSeq='DQMOfflineCosmics'
1056 
1057  if self._options.scenario=='HeavyIons':
1058  if not self._options.beamspot:
1059  self._options.beamspot=VtxSmearedHIDefaultKey
1060  self.HLTDefaultSeq = 'HIon'
1061  self.VALIDATIONDefaultCFF="Configuration/StandardSequences/ValidationHeavyIons_cff"
1062  self.VALIDATIONDefaultSeq=''
1063  self.EVTCONTDefaultCFF="Configuration/EventContent/EventContentHeavyIons_cff"
1064  self.RECODefaultCFF="Configuration/StandardSequences/ReconstructionHeavyIons_cff"
1065  self.RECODefaultSeq='reconstructionHeavyIons'
1066  self.ALCADefaultCFF = "Configuration/StandardSequences/AlCaRecoStreamsHeavyIons_cff"
1067  self.DQMOFFLINEDefaultCFF="DQMOffline/Configuration/DQMOfflineHeavyIons_cff"
1068  self.DQMDefaultSeq='DQMOfflineHeavyIons'
1069  self.SKIMDefaultCFF="Configuration/StandardSequences/SkimsHeavyIons_cff"
1070  self.HARVESTINGDefaultCFF="Configuration/StandardSequences/HarvestingHeavyIons_cff"
1071  if self._options.isMC==True:
1072  self.DQMOFFLINEDefaultCFF="DQMOffline/Configuration/DQMOfflineHeavyIonsMC_cff"
1073 
1074 
1076 
1077  self.USERDefaultSeq='user'
1078  self.USERDefaultCFF=None
1079 
1080  # the magnetic field
1081  self.magFieldCFF = 'Configuration/StandardSequences/MagneticField_'+self._options.magField.replace('.','')+'_cff'
1082  self.magFieldCFF = self.magFieldCFF.replace("__",'_')
1083 
1084  # the geometry
1085  self.GeometryCFF='Configuration/StandardSequences/GeometryRecoDB_cff'
1087  simGeometry=''
1088  if self._options.fast:
1089  if 'start' in self._options.conditions.lower():
1090  self.GeometryCFF='FastSimulation/Configuration/Geometries_START_cff'
1091  else:
1092  self.GeometryCFF='FastSimulation/Configuration/Geometries_MC_cff'
1093  else:
1094  def inGeometryKeys(opt):
1095  from Configuration.StandardSequences.GeometryConf import GeometryConf
1096  if opt in GeometryConf:
1097  return GeometryConf[opt]
1098  else:
1099  return opt
1100 
1101  geoms=self._options.geometry.split(',')
1102  if len(geoms)==1: geoms=inGeometryKeys(geoms[0]).split(',')
1103  if len(geoms)==2:
1104  #may specify the reco geometry
1105  if '/' in geoms[1] or '_cff' in geoms[1]:
1106  self.GeometryCFF=geoms[1]
1107  else:
1108  self.GeometryCFF='Configuration/Geometry/Geometry'+geoms[1]+'_cff'
1109 
1110  if (geoms[0].startswith('DB:')):
1111  self.SimGeometryCFF='Configuration/StandardSequences/GeometrySimDB_cff'
1112  self.geometryDBLabel=geoms[0][3:]
1113  print("with DB:")
1114  else:
1115  if '/' in geoms[0] or '_cff' in geoms[0]:
1116  self.SimGeometryCFF=geoms[0]
1117  else:
1118  simGeometry=geoms[0]
1119  if self._options.gflash==True:
1120  self.SimGeometryCFF='Configuration/Geometry/Geometry'+geoms[0]+'GFlash_cff'
1121  else:
1122  self.SimGeometryCFF='Configuration/Geometry/Geometry'+geoms[0]+'_cff'
1123 
1124  # synchronize the geometry configuration and the FullSimulation sequence to be used
1125  if simGeometry not in defaultOptions.geometryExtendedOptions:
1126  self.SIMDefaultCFF="Configuration/StandardSequences/SimIdeal_cff"
1127 
1128  if self._options.scenario=='nocoll' or self._options.scenario=='cosmics':
1129  self.SIMDefaultCFF="Configuration/StandardSequences/SimNOBEAM_cff"
1130  self._options.beamspot='NoSmear'
1131 
1132  # fastsim requires some changes to the default cff files and sequences
1133  if self._options.fast:
1134  self.SIMDefaultCFF = 'FastSimulation.Configuration.SimIdeal_cff'
1135  self.RECODefaultCFF= 'FastSimulation.Configuration.Reconstruction_AftMix_cff'
1136  self.RECOBEFMIXDefaultCFF = 'FastSimulation.Configuration.Reconstruction_BefMix_cff'
1137  self.RECOBEFMIXDefaultSeq = 'reconstruction_befmix'
1138  self.NANODefaultSeq = 'nanoSequenceFS'
1139  self.DQMOFFLINEDefaultCFF="DQMOffline.Configuration.DQMOfflineFS_cff"
1140 
1141  # Mixing
1142  if self._options.pileup=='default':
1143  from Configuration.StandardSequences.Mixing import MixingDefaultKey
1144  self._options.pileup=MixingDefaultKey
1145 
1146 
1147  #not driven by a default cff anymore
1148  if self._options.isData:
1149  self._options.pileup=None
1150 
1151 
1153 
1154  # for alca, skims, etc
1155  def addExtraStream(self, name, stream, workflow='full'):
1156  # define output module and go from there
1157  output = cms.OutputModule("PoolOutputModule")
1158  if stream.selectEvents.parameters_().__len__()!=0:
1159  output.SelectEvents = stream.selectEvents
1160  else:
1161  output.SelectEvents = cms.untracked.PSet()
1162  output.SelectEvents.SelectEvents=cms.vstring()
1163  if isinstance(stream.paths,tuple):
1164  for path in stream.paths:
1165  output.SelectEvents.SelectEvents.append(path.label())
1166  else:
1167  output.SelectEvents.SelectEvents.append(stream.paths.label())
1168 
1169 
1170 
1171  if isinstance(stream.content,str):
1172  evtPset=getattr(self.process,stream.content)
1173  for p in evtPset.parameters_():
1174  setattr(output,p,getattr(evtPset,p))
1175  if not self._options.inlineEventContent:
1176  def doNotInlineEventContent(instance,label = "process."+stream.content+".outputCommands"):
1177  return label
1178  output.outputCommands.__dict__["dumpPython"] = doNotInlineEventContent
1179  else:
1180  output.outputCommands = stream.content
1181 
1182 
1183  output.fileName = cms.untracked.string(self._options.dirout+stream.name+'.root')
1184 
1185  output.dataset = cms.untracked.PSet( dataTier = stream.dataTier,
1186  filterName = cms.untracked.string(stream.name))
1187 
1188  if self._options.filtername:
1189  output.dataset.filterName= cms.untracked.string(self._options.filtername+"_"+stream.name)
1190 
1191  #add an automatic flushing to limit memory consumption
1192  output.eventAutoFlushCompressedSize=cms.untracked.int32(5*1024*1024)
1193 
1194  if workflow in ("producers,full"):
1195  if isinstance(stream.paths,tuple):
1196  for path in stream.paths:
1197  self.schedule.append(path)
1198  else:
1199  self.schedule.append(stream.paths)
1200 
1201 
1202  # in case of relvals we don't want to have additional outputs
1203  if (not self._options.relval) and workflow in ("full","output"):
1204  self.additionalOutputs[name] = output
1205  setattr(self.process,name,output)
1206 
1207  if workflow == 'output':
1208  # adjust the select events to the proper trigger results from previous process
1209  filterList = output.SelectEvents.SelectEvents
1210  for i, filter in enumerate(filterList):
1211  filterList[i] = filter+":"+self._options.triggerResultsProcess
1212 
1213  return output
1214 
1215  #----------------------------------------------------------------------------
1216  # here the methods to create the steps. Of course we are doing magic here ;)
1217  # prepare_STEPNAME modifies self.process and what else's needed.
1218  #----------------------------------------------------------------------------
1219 
1220  def loadDefaultOrSpecifiedCFF(self, sequence,defaultCFF):
1221  if ( len(sequence.split('.'))==1 ):
1222  l=self.loadAndRemember(defaultCFF)
1223  elif ( len(sequence.split('.'))==2 ):
1224  l=self.loadAndRemember(sequence.split('.')[0])
1225  sequence=sequence.split('.')[1]
1226  else:
1227  print("sub sequence configuration must be of the form dir/subdir/cff.a+b+c or cff.a")
1228  print(sequence,"not recognized")
1229  raise
1230  return l
1231 
1232  def scheduleSequence(self,seq,prefix,what='Path'):
1233  if '*' in seq:
1234  #create only one path with all sequences in it
1235  for i,s in enumerate(seq.split('*')):
1236  if i==0:
1237  setattr(self.process,prefix,getattr(cms,what)( getattr(self.process, s) ))
1238  else:
1239  p=getattr(self.process,prefix)
1240  tmp = getattr(self.process, s)
1241  if isinstance(tmp, cms.Task):
1242  p.associate(tmp)
1243  else:
1244  p+=tmp
1245  self.schedule.append(getattr(self.process,prefix))
1246  return
1247  else:
1248  #create as many path as many sequences
1249  if not '+' in seq:
1250  if self.nextScheduleIsConditional:
1251  self.conditionalPaths.append(prefix)
1252  setattr(self.process,prefix,getattr(cms,what)( getattr(self.process, seq) ))
1253  self.schedule.append(getattr(self.process,prefix))
1254  else:
1255  for i,s in enumerate(seq.split('+')):
1256  sn=prefix+'%d'%(i)
1257  setattr(self.process,sn,getattr(cms,what)( getattr(self.process, s) ))
1258  self.schedule.append(getattr(self.process,sn))
1259  return
1260 
1261  def scheduleSequenceAtEnd(self,seq,prefix):
1262  self.scheduleSequence(seq,prefix,what='EndPath')
1263  return
1264 
1265  def prepare_ALCAPRODUCER(self, sequence = None):
1266  self.prepare_ALCA(sequence, workflow = "producers")
1267 
1268  def prepare_ALCAOUTPUT(self, sequence = None):
1269  self.prepare_ALCA(sequence, workflow = "output")
1270 
1271  def prepare_ALCA(self, sequence = None, workflow = 'full'):
1272  """ Enrich the process with alca streams """
1273  alcaConfig=self.loadDefaultOrSpecifiedCFF(sequence,self.ALCADefaultCFF)
1274  sequence = sequence.split('.')[-1]
1275 
1276  # decide which ALCA paths to use
1277  alcaList = sequence.split("+")
1278  maxLevel=0
1279  from Configuration.AlCa.autoAlca import autoAlca, AlCaNoConcurrentLumis
1280  # support @X from autoAlca.py, and recursion support: i.e T0:@Mu+@EG+...
1281  self.expandMapping(alcaList,autoAlca)
1282  self.AlCaPaths=[]
1283  for name in alcaConfig.__dict__:
1284  alcastream = getattr(alcaConfig,name)
1285  shortName = name.replace('ALCARECOStream','')
1286  if shortName in alcaList and isinstance(alcastream,cms.FilteredStream):
1287  if shortName in AlCaNoConcurrentLumis:
1288  print("Setting numberOfConcurrentLuminosityBlocks=1 because of AlCa sequence {}".format(shortName))
1289  self._options.nConcurrentLumis = "1"
1290  self._options.nConcurrentIOVs = "1"
1291  output = self.addExtraStream(name,alcastream, workflow = workflow)
1292  self.executeAndRemember('process.ALCARECOEventContent.outputCommands.extend(process.OutALCARECO'+shortName+'_noDrop.outputCommands)')
1293  self.AlCaPaths.append(shortName)
1294  if 'DQM' in alcaList:
1295  if not self._options.inlineEventContent and hasattr(self.process,name):
1296  self.executeAndRemember('process.' + name + '.outputCommands.append("keep *_MEtoEDMConverter_*_*")')
1297  else:
1298  output.outputCommands.append("keep *_MEtoEDMConverter_*_*")
1299 
1300  #rename the HLT process name in the alca modules
1301  if self._options.hltProcess or 'HLT' in self.stepMap:
1302  if isinstance(alcastream.paths,tuple):
1303  for path in alcastream.paths:
1304  self.renameHLTprocessInSequence(path.label())
1305  else:
1306  self.renameHLTprocessInSequence(alcastream.paths.label())
1307 
1308  for i in range(alcaList.count(shortName)):
1309  alcaList.remove(shortName)
1310 
1311  # DQM needs a special handling
1312  elif name == 'pathALCARECODQM' and 'DQM' in alcaList:
1313  path = getattr(alcaConfig,name)
1314  self.schedule.append(path)
1315  alcaList.remove('DQM')
1316 
1317  if isinstance(alcastream,cms.Path):
1318  #black list the alca path so that they do not appear in the cfg
1319  self.blacklist_paths.append(alcastream)
1320 
1321 
1322  if len(alcaList) != 0:
1323  available=[]
1324  for name in alcaConfig.__dict__:
1325  alcastream = getattr(alcaConfig,name)
1326  if isinstance(alcastream,cms.FilteredStream):
1327  available.append(name.replace('ALCARECOStream',''))
1328  print("The following alcas could not be found "+str(alcaList))
1329  print("available ",available)
1330  #print "verify your configuration, ignoring for now"
1331  raise Exception("The following alcas could not be found "+str(alcaList))
1332 
1333  def prepare_LHE(self, sequence = None):
1334  #load the fragment
1335  ##make it loadable
1336  loadFragment = self._options.evt_type.replace('.py','',).replace('.','_').replace('python/','').replace('/','.')
1337  print("Loading lhe fragment from",loadFragment)
1338  __import__(loadFragment)
1339  self.process.load(loadFragment)
1340  ##inline the modules
1341  self._options.inlineObjets+=','+sequence
1342 
1343  getattr(self.process,sequence).nEvents = int(self._options.number)
1344 
1345  #schedule it
1346  self.process.lhe_step = cms.Path( getattr( self.process,sequence) )
1347  self.excludedPaths.append("lhe_step")
1348  self.schedule.append( self.process.lhe_step )
1349 
1350  def prepare_GEN(self, sequence = None):
1351  """ load the fragment of generator configuration """
1352  loadFailure=False
1353  #remove trailing .py
1354  #support old style .cfi by changing into something.cfi into something_cfi
1355  #remove python/ from the name
1356  loadFragment = self._options.evt_type.replace('.py','',).replace('.','_').replace('python/','')
1357  #standard location of fragments
1358  if not '/' in loadFragment:
1359  loadFragment='Configuration.Generator.'+loadFragment
1360  else:
1361  loadFragment=loadFragment.replace('/','.')
1362  try:
1363  print("Loading generator fragment from",loadFragment)
1364  __import__(loadFragment)
1365  except:
1366  loadFailure=True
1367  #if self.process.source and self.process.source.type_()=='EmptySource':
1368  if not (self._options.filein or self._options.dasquery):
1369  raise Exception("Neither gen fragment of input files provided: this is an inconsistent GEN step configuration")
1370 
1371  if not loadFailure:
1372  from Configuration.Generator.concurrentLumisDisable import noConcurrentLumiGenerators
1373 
1374  generatorModule=sys.modules[loadFragment]
1375  genModules=generatorModule.__dict__
1376  #remove lhe producer module since this should have been
1377  #imported instead in the LHE step
1378  if self.LHEDefaultSeq in genModules:
1379  del genModules[self.LHEDefaultSeq]
1380 
1381  if self._options.hideGen:
1382  self.loadAndRemember(loadFragment)
1383  else:
1384  self.process.load(loadFragment)
1385  # expose the objects from that fragment to the configuration
1386  import FWCore.ParameterSet.Modules as cmstypes
1387  for name in genModules:
1388  theObject = getattr(generatorModule,name)
1389  if isinstance(theObject, cmstypes._Module):
1390  self._options.inlineObjets=name+','+self._options.inlineObjets
1391  if theObject.type_() in noConcurrentLumiGenerators:
1392  print("Setting numberOfConcurrentLuminosityBlocks=1 because of generator {}".format(theObject.type_()))
1393  self._options.nConcurrentLumis = "1"
1394  self._options.nConcurrentIOVs = "1"
1395  elif isinstance(theObject, cms.Sequence) or isinstance(theObject, cmstypes.ESProducer):
1396  self._options.inlineObjets+=','+name
1397 
1398  if sequence == self.GENDefaultSeq or sequence == 'pgen_genonly':
1399  if 'ProductionFilterSequence' in genModules and ('generator' in genModules):
1400  self.productionFilterSequence = 'ProductionFilterSequence'
1401  elif 'generator' in genModules:
1402  self.productionFilterSequence = 'generator'
1403 
1404  """ Enrich the schedule with the rest of the generation step """
1405  self.loadDefaultOrSpecifiedCFF(sequence,self.GENDefaultCFF)
1406  genSeqName=sequence.split('.')[-1]
1407 
1408  if True:
1409  try:
1410  from Configuration.StandardSequences.VtxSmeared import VtxSmeared
1411  cffToBeLoaded=VtxSmeared[self._options.beamspot]
1412  self.loadAndRemember(cffToBeLoaded)
1413  except ImportError:
1414  raise Exception("VertexSmearing type or beamspot "+self._options.beamspot+" unknown.")
1415 
1416  if self._options.scenario == 'HeavyIons':
1417  if self._options.pileup=='HiMixGEN':
1418  self.loadAndRemember("Configuration/StandardSequences/GeneratorMix_cff")
1419  elif self._options.pileup=='HiMixEmbGEN':
1420  self.loadAndRemember("Configuration/StandardSequences/GeneratorEmbMix_cff")
1421  else:
1422  self.loadAndRemember("Configuration/StandardSequences/GeneratorHI_cff")
1423 
1424  self.process.generation_step = cms.Path( getattr(self.process,genSeqName) )
1425  self.schedule.append(self.process.generation_step)
1426 
1427  #register to the genstepfilter the name of the path (static right now, but might evolve)
1428  self.executeAndRemember('process.genstepfilter.triggerConditions=cms.vstring("generation_step")')
1429 
1430  if 'reGEN' in self.stepMap:
1431  #stop here
1432  return
1433 
1434  """ Enrich the schedule with the summary of the filter step """
1435  #the gen filter in the endpath
1436  self.loadAndRemember("GeneratorInterface/Core/genFilterSummary_cff")
1437  self.scheduleSequenceAtEnd('genFilterSummary','genfiltersummary_step')
1438  return
1439 
1440  def prepare_SIM(self, sequence = None):
1441  """ Enrich the schedule with the simulation step"""
1442  self.loadDefaultOrSpecifiedCFF(sequence,self.SIMDefaultCFF)
1443  if not self._options.fast:
1444  if self._options.gflash==True:
1445  self.loadAndRemember("Configuration/StandardSequences/GFlashSIM_cff")
1446 
1447  if self._options.magField=='0T':
1448  self.executeAndRemember("process.g4SimHits.UseMagneticField = cms.bool(False)")
1449  else:
1450  if self._options.magField=='0T':
1451  self.executeAndRemember("process.fastSimProducer.detectorDefinition.magneticFieldZ = cms.untracked.double(0.)")
1452 
1453  self.scheduleSequence(sequence.split('.')[-1],'simulation_step')
1454  return
1455 
1456  def prepare_DIGI(self, sequence = None):
1457  """ Enrich the schedule with the digitisation step"""
1458  self.loadDefaultOrSpecifiedCFF(sequence,self.DIGIDefaultCFF)
1459 
1460  if self._options.gflash==True:
1461  self.loadAndRemember("Configuration/StandardSequences/GFlashDIGI_cff")
1462 
1463  if sequence == 'pdigi_valid' or sequence == 'pdigi_hi':
1464  self.executeAndRemember("process.mix.digitizers = cms.PSet(process.theDigitizersValid)")
1465 
1466  if sequence != 'pdigi_nogen' and sequence != 'pdigi_valid_nogen' and sequence != 'pdigi_hi_nogen' and not self.process.source.type_()=='EmptySource' and not self._options.filetype == "LHE":
1467  if self._options.inputEventContent=='':
1468  self._options.inputEventContent='REGEN'
1469  else:
1470  self._options.inputEventContent=self._options.inputEventContent+',REGEN'
1471 
1472 
1473  self.scheduleSequence(sequence.split('.')[-1],'digitisation_step')
1474  return
1475 
1476  def prepare_CFWRITER(self, sequence = None):
1477  """ Enrich the schedule with the crossing frame writer step"""
1479  self.scheduleSequence('pcfw','cfwriter_step')
1480  return
1481 
1482  def prepare_DATAMIX(self, sequence = None):
1483  """ Enrich the schedule with the digitisation step"""
1485  self.scheduleSequence('pdatamix','datamixing_step')
1486 
1487  if self._options.pileup_input:
1488  theFiles=''
1489  if self._options.pileup_input.startswith('dbs:') or self._options.pileup_input.startswith('das:'):
1490  theFiles=filesFromDASQuery('file dataset = %s'%(self._options.pileup_input[4:],),self._options.pileup_dasoption)[0]
1491  elif self._options.pileup_input.startswith("filelist:"):
1492  theFiles= (filesFromList(self._options.pileup_input[9:]))[0]
1493  else:
1494  theFiles=self._options.pileup_input.split(',')
1495  #print theFiles
1496  self.executeAndRemember( "process.mixData.input.fileNames = cms.untracked.vstring(%s)"%( theFiles ) )
1497 
1498  return
1499 
1500  def prepare_DIGI2RAW(self, sequence = None):
1501  self.loadDefaultOrSpecifiedCFF(sequence,self.DIGI2RAWDefaultCFF)
1502  self.scheduleSequence(sequence.split('.')[-1],'digi2raw_step')
1503  return
1504 
1505  def prepare_REPACK(self, sequence = None):
1506  self.loadDefaultOrSpecifiedCFF(sequence,self.REPACKDefaultCFF)
1507  self.scheduleSequence(sequence.split('.')[-1],'digi2repack_step')
1508  return
1509 
1510  def prepare_L1(self, sequence = None):
1511  """ Enrich the schedule with the L1 simulation step"""
1512  assert(sequence == None)
1513  self.loadAndRemember(self.L1EMDefaultCFF)
1514  self.scheduleSequence('SimL1Emulator','L1simulation_step')
1515  return
1516 
1517  def prepare_L1REPACK(self, sequence = None):
1518  """ Enrich the schedule with the L1 simulation step, running the L1 emulator on data unpacked from the RAW collection, and repacking the result in a new RAW collection"""
1519  supported = ['GT','GT1','GT2','GCTGT','Full','FullSimTP','FullMC','Full2015Data','uGT','CalouGT']
1520  if sequence in supported:
1521  self.loadAndRemember('Configuration/StandardSequences/SimL1EmulatorRepack_%s_cff'%sequence)
1522  if self._options.scenario == 'HeavyIons':
1523  self.renameInputTagsInSequence("SimL1Emulator","rawDataCollector","rawDataRepacker")
1524  self.scheduleSequence('SimL1Emulator','L1RePack_step')
1525  else:
1526  print("L1REPACK with '",sequence,"' is not supported! Supported choices are: ",supported)
1527  raise Exception('unsupported feature')
1528 
1529  def prepare_HLT(self, sequence = None):
1530  """ Enrich the schedule with the HLT simulation step"""
1531  if not sequence:
1532  print("no specification of the hlt menu has been given, should never happen")
1533  raise Exception('no HLT sequence provided')
1534 
1535  if '@' in sequence:
1536  # case where HLT:@something was provided
1537  from Configuration.HLT.autoHLT import autoHLT
1538  key = sequence[1:]
1539  if key in autoHLT:
1540  sequence = autoHLT[key]
1541  else:
1542  raise ValueError('no HLT mapping key "%s" found in autoHLT' % key)
1543 
1544  if ',' in sequence:
1545  #case where HLT:something:something was provided
1546  self.executeAndRemember('import HLTrigger.Configuration.Utilities')
1547  optionsForHLT = {}
1548  if self._options.scenario == 'HeavyIons':
1549  optionsForHLT['type'] = 'HIon'
1550  else:
1551  optionsForHLT['type'] = 'GRun'
1552  optionsForHLTConfig = ', '.join('%s=%s' % (key, repr(val)) for (key, val) in optionsForHLT.items())
1553  if sequence == 'run,fromSource':
1554  if hasattr(self.process.source,'firstRun'):
1555  self.executeAndRemember('process.loadHltConfiguration("run:%%d"%%(process.source.firstRun.value()),%s)'%(optionsForHLTConfig))
1556  elif hasattr(self.process.source,'setRunNumber'):
1557  self.executeAndRemember('process.loadHltConfiguration("run:%%d"%%(process.source.setRunNumber.value()),%s)'%(optionsForHLTConfig))
1558  else:
1559  raise Exception('Cannot replace menu to load %s'%(sequence))
1560  else:
1561  self.executeAndRemember('process.loadHltConfiguration("%s",%s)'%(sequence.replace(',',':'),optionsForHLTConfig))
1562  else:
1563  self.loadAndRemember('HLTrigger/Configuration/HLT_%s_cff' % sequence)
1564 
1565  if self._options.isMC:
1566  self._options.customisation_file.append("HLTrigger/Configuration/customizeHLTforMC.customizeHLTforMC")
1567 
1568  if self._options.name != 'HLT':
1569  self.additionalCommands.append('from HLTrigger.Configuration.CustomConfigs import ProcessName')
1570  self.additionalCommands.append('process = ProcessName(process)')
1571  self.additionalCommands.append('')
1572  from HLTrigger.Configuration.CustomConfigs import ProcessName
1573  self.process = ProcessName(self.process)
1574 
1575  if self.process.schedule == None:
1576  raise Exception('the HLT step did not attach a valid schedule to the process')
1577 
1578  self.scheduleIndexOfFirstHLTPath = len(self.schedule)
1579  [self.blacklist_paths.append(path) for path in self.process.schedule if isinstance(path,(cms.Path,cms.EndPath))]
1580 
1581  # this is a fake, to be removed with fastim migration and HLT menu dump
1582  if self._options.fast:
1583  if not hasattr(self.process,'HLTEndSequence'):
1584  self.executeAndRemember("process.HLTEndSequence = cms.Sequence( process.dummyModule )")
1585 
1586 
1587  def prepare_RAW2RECO(self, sequence = None):
1588  if ','in sequence:
1589  seqReco=sequence.split(',')[1]
1590  seqDigi=sequence.split(',')[0]
1591  else:
1592  print("RAW2RECO requires two specifications",sequence,"insufficient")
1593 
1594  self.prepare_RAW2DIGI(seqDigi)
1595  self.prepare_RECO(seqReco)
1596  return
1597 
1598  def prepare_RAW2DIGI(self, sequence = "RawToDigi"):
1599  self.loadDefaultOrSpecifiedCFF(sequence,self.RAW2DIGIDefaultCFF)
1600  self.scheduleSequence(sequence,'raw2digi_step')
1601  # if self._options.isRepacked:
1602  #self.renameInputTagsInSequence(sequence)
1603  return
1604 
1605  def prepare_PATFILTER(self, sequence=None):
1606  self.loadAndRemember("PhysicsTools/PatAlgos/slimming/metFilterPaths_cff")
1607  from PhysicsTools.PatAlgos.slimming.metFilterPaths_cff import allMetFilterPaths
1608  for filt in allMetFilterPaths:
1609  self.schedule.append(getattr(self.process,'Flag_'+filt))
1610 
1611  def prepare_L1HwVal(self, sequence = 'L1HwVal'):
1612  ''' Enrich the schedule with L1 HW validation '''
1613  self.loadDefaultOrSpecifiedCFF(sequence,self.L1HwValDefaultCFF)
1614  #self.scheduleSequence(sequence.split('.')[-1],'l1hwval_step')
1615  print('\n\n\n DEPRECATED this has no action \n\n\n')
1616  return
1617 
1618  def prepare_L1Reco(self, sequence = "L1Reco"):
1619  ''' Enrich the schedule with L1 reconstruction '''
1620  self.loadDefaultOrSpecifiedCFF(sequence,self.L1RecoDefaultCFF)
1621  self.scheduleSequence(sequence.split('.')[-1],'L1Reco_step')
1622  return
1623 
1624  def prepare_L1TrackTrigger(self, sequence = "L1TrackTrigger"):
1625  ''' Enrich the schedule with L1 reconstruction '''
1627  self.scheduleSequence(sequence.split('.')[-1],'L1TrackTrigger_step')
1628  return
1629 
1630  def prepare_FILTER(self, sequence = None):
1631  ''' Enrich the schedule with a user defined filter sequence '''
1632  ## load the relevant part
1633  filterConfig=self.load(sequence.split('.')[0])
1634  filterSeq=sequence.split('.')[-1]
1635  ## print it in the configuration
1636  class PrintAllModules(object):
1637  def __init__(self):
1638  self.inliner=''
1639  pass
1640  def enter(self,visitee):
1641  try:
1642  label=visitee.label()
1643  ##needs to be in reverse order
1644  self.inliner=label+','+self.inliner
1645  except:
1646  pass
1647  def leave(self,v): pass
1648 
1649  expander=PrintAllModules()
1650  getattr(self.process,filterSeq).visit( expander )
1651  self._options.inlineObjets+=','+expander.inliner
1652  self._options.inlineObjets+=','+filterSeq
1653 
1654  ## put the filtering path in the schedule
1655  self.scheduleSequence(filterSeq,'filtering_step')
1656  self.nextScheduleIsConditional=True
1657  ## put it before all the other paths
1658  self.productionFilterSequence = filterSeq
1659 
1660  return
1661 
1662  def prepare_RECO(self, sequence = "reconstruction"):
1663  ''' Enrich the schedule with reconstruction '''
1664  self.loadDefaultOrSpecifiedCFF(sequence,self.RECODefaultCFF)
1665  self.scheduleSequence(sequence.split('.')[-1],'reconstruction_step')
1666  return
1667 
1668  def prepare_RECOSIM(self, sequence = "recosim"):
1669  ''' Enrich the schedule with reconstruction '''
1670  self.loadDefaultOrSpecifiedCFF(sequence,self.RECOSIMDefaultCFF)
1671  self.scheduleSequence(sequence.split('.')[-1],'recosim_step')
1672  return
1673 
1674  def prepare_RECOBEFMIX(self, sequence = "reconstruction"):
1675  ''' Enrich the schedule with the part of reconstruction that is done before mixing in FastSim'''
1676  if not self._options.fast:
1677  print("ERROR: this step is only implemented for FastSim")
1678  sys.exit()
1680  self.scheduleSequence(sequence.split('.')[-1],'reconstruction_befmix_step')
1681  return
1682 
1683  def prepare_PAT(self, sequence = "miniAOD"):
1684  ''' Enrich the schedule with PAT '''
1685  self.prepare_PATFILTER(self)
1686  self.loadDefaultOrSpecifiedCFF(sequence,self.PATDefaultCFF)
1687  self.labelsToAssociate.append('patTask')
1688  if self._options.isData:
1689  self._options.customisation_file_unsch.insert(0,"PhysicsTools/PatAlgos/slimming/miniAOD_tools.miniAOD_customizeAllData")
1690  else:
1691  if self._options.fast:
1692  self._options.customisation_file_unsch.insert(0,"PhysicsTools/PatAlgos/slimming/miniAOD_tools.miniAOD_customizeAllMCFastSim")
1693  else:
1694  self._options.customisation_file_unsch.insert(0,"PhysicsTools/PatAlgos/slimming/miniAOD_tools.miniAOD_customizeAllMC")
1695 
1696  if self._options.hltProcess:
1697  if len(self._options.customise_commands) > 1:
1698  self._options.customise_commands = self._options.customise_commands + " \n"
1699  self._options.customise_commands = self._options.customise_commands + "process.patTrigger.processName = \""+self._options.hltProcess+"\"\n"
1700  self._options.customise_commands = self._options.customise_commands + "process.slimmedPatTrigger.triggerResults= cms.InputTag( 'TriggerResults::"+self._options.hltProcess+"' )\n"
1701  self._options.customise_commands = self._options.customise_commands + "process.patMuons.triggerResults= cms.InputTag( 'TriggerResults::"+self._options.hltProcess+"' )\n"
1702 
1703 # self.renameHLTprocessInSequence(sequence)
1704 
1705  return
1706 
1707  def prepare_PATGEN(self, sequence = "miniGEN"):
1708  ''' Enrich the schedule with PATGEN '''
1709  self.loadDefaultOrSpecifiedCFF(sequence,self.PATGENDefaultCFF) #this is unscheduled
1710  self.labelsToAssociate.append('patGENTask')
1711  if self._options.isData:
1712  raise Exception("PATGEN step can only run on MC")
1713  return
1714 
1715  def prepare_NANO(self, sequence = "nanoAOD"):
1716  ''' Enrich the schedule with NANO '''
1717  self.loadDefaultOrSpecifiedCFF(sequence,self.NANODefaultCFF)
1718  self.scheduleSequence(sequence.split('.')[-1],'nanoAOD_step')
1719  custom = "nanoAOD_customizeData" if self._options.isData else "nanoAOD_customizeMC"
1720  self._options.customisation_file.insert(0,"PhysicsTools/NanoAOD/nano_cff."+custom)
1721  if self._options.hltProcess:
1722  if len(self._options.customise_commands) > 1:
1723  self._options.customise_commands = self._options.customise_commands + " \n"
1724  self._options.customise_commands = self._options.customise_commands + "process.unpackedPatTrigger.triggerResults= cms.InputTag( 'TriggerResults::"+self._options.hltProcess+"' )\n"
1725 
1726  def prepare_NANOGEN(self, sequence = "nanoAOD"):
1727  ''' Enrich the schedule with NANOGEN '''
1728  # TODO: Need to modify this based on the input file type
1729  fromGen = any([x in self.stepMap for x in ['LHE', 'GEN', 'AOD']])
1730  self.loadDefaultOrSpecifiedCFF(sequence,self.NANOGENDefaultCFF)
1731  self.scheduleSequence(sequence.split('.')[-1],'nanoAOD_step')
1732  custom = "customizeNanoGEN" if fromGen else "customizeNanoGENFromMini"
1733  if self._options.runUnscheduled:
1734  self._options.customisation_file_unsch.insert(0, '.'.join([self.NANOGENDefaultCFF, custom]))
1735  else:
1736  self._options.customisation_file.insert(0, '.'.join([self.NANOGENDefaultCFF, custom]))
1737 
1738  def prepare_EI(self, sequence = None):
1739  ''' Enrich the schedule with event interpretation '''
1740  from Configuration.StandardSequences.EventInterpretation import EventInterpretation
1741  if sequence in EventInterpretation:
1742  self.EIDefaultCFF = EventInterpretation[sequence]
1743  sequence = 'EIsequence'
1744  else:
1745  raise Exception('Cannot set %s event interpretation'%( sequence) )
1746  self.loadDefaultOrSpecifiedCFF(sequence,self.EIDefaultCFF)
1747  self.scheduleSequence(sequence.split('.')[-1],'eventinterpretaion_step')
1748  return
1749 
1750  def prepare_SKIM(self, sequence = "all"):
1751  ''' Enrich the schedule with skimming fragments'''
1752  skimConfig = self.loadDefaultOrSpecifiedCFF(sequence,self.SKIMDefaultCFF)
1753  sequence = sequence.split('.')[-1]
1754 
1755  skimlist=sequence.split('+')
1756  ## support @Mu+DiJet+@Electron configuration via autoSkim.py
1757  from Configuration.Skimming.autoSkim import autoSkim
1758  self.expandMapping(skimlist,autoSkim)
1759 
1760  #print "dictionnary for skims:",skimConfig.__dict__
1761  for skim in skimConfig.__dict__:
1762  skimstream = getattr(skimConfig,skim)
1763  if isinstance(skimstream,cms.Path):
1764  #black list the alca path so that they do not appear in the cfg
1765  self.blacklist_paths.append(skimstream)
1766  if (not isinstance(skimstream,cms.FilteredStream)):
1767  continue
1768  shortname = skim.replace('SKIMStream','')
1769  if (sequence=="all"):
1770  self.addExtraStream(skim,skimstream)
1771  elif (shortname in skimlist):
1772  self.addExtraStream(skim,skimstream)
1773  #add a DQM eventcontent for this guy
1774  if self._options.datatier=='DQM':
1775  self.process.load(self.EVTCONTDefaultCFF)
1776  skimstreamDQM = cms.FilteredStream(
1777  responsible = skimstream.responsible,
1778  name = skimstream.name+'DQM',
1779  paths = skimstream.paths,
1780  selectEvents = skimstream.selectEvents,
1781  content = self._options.datatier+'EventContent',
1782  dataTier = cms.untracked.string(self._options.datatier)
1783  )
1784  self.addExtraStream(skim+'DQM',skimstreamDQM)
1785  for i in range(skimlist.count(shortname)):
1786  skimlist.remove(shortname)
1787 
1788 
1789 
1790  if (skimlist.__len__()!=0 and sequence!="all"):
1791  print('WARNING, possible typo with SKIM:'+'+'.join(skimlist))
1792  raise Exception('WARNING, possible typo with SKIM:'+'+'.join(skimlist))
1793 
1794  def prepare_USER(self, sequence = None):
1795  ''' Enrich the schedule with a user defined sequence '''
1796  self.loadDefaultOrSpecifiedCFF(sequence,self.USERDefaultCFF)
1797  self.scheduleSequence(sequence.split('.')[-1],'user_step')
1798  return
1799 
1800  def prepare_POSTRECO(self, sequence = None):
1801  """ Enrich the schedule with the postreco step """
1803  self.scheduleSequence('postreco_generator','postreco_step')
1804  return
1805 
1806 
1807  def prepare_VALIDATION(self, sequence = 'validation'):
1808  print(sequence,"in preparing validation")
1810  from Validation.Configuration.autoValidation import autoValidation
1811  #in case VALIDATION:something:somethingelse -> something,somethingelse
1812  sequence=sequence.split('.')[-1]
1813  if sequence.find(',')!=-1:
1814  prevalSeqName=sequence.split(',')[0].split('+')
1815  valSeqName=sequence.split(',')[1].split('+')
1816  self.expandMapping(prevalSeqName,autoValidation,index=0)
1817  self.expandMapping(valSeqName,autoValidation,index=1)
1818  else:
1819  if '@' in sequence:
1820  prevalSeqName=sequence.split('+')
1821  valSeqName=sequence.split('+')
1822  self.expandMapping(prevalSeqName,autoValidation,index=0)
1823  self.expandMapping(valSeqName,autoValidation,index=1)
1824  else:
1825  postfix=''
1826  if sequence:
1827  postfix='_'+sequence
1828  prevalSeqName=['prevalidation'+postfix]
1829  valSeqName=['validation'+postfix]
1830  if not hasattr(self.process,valSeqName[0]):
1831  prevalSeqName=['']
1832  valSeqName=[sequence]
1833 
1834  def NFI(index):
1835  ##name from index, required to keep backward compatibility
1836  if index==0:
1837  return ''
1838  else:
1839  return '%s'%index
1840 
1841 
1842  #rename the HLT process in validation steps
1843  if ('HLT' in self.stepMap and not self._options.fast) or self._options.hltProcess:
1844  for s in valSeqName+prevalSeqName:
1845  if s:
1847  for (i,s) in enumerate(prevalSeqName):
1848  if s:
1849  setattr(self.process,'prevalidation_step%s'%NFI(i), cms.Path( getattr(self.process, s)) )
1850  self.schedule.append(getattr(self.process,'prevalidation_step%s'%NFI(i)))
1851 
1852  for (i,s) in enumerate(valSeqName):
1853  setattr(self.process,'validation_step%s'%NFI(i), cms.EndPath( getattr(self.process, s)))
1854  self.schedule.append(getattr(self.process,'validation_step%s'%NFI(i)))
1855 
1856  #needed in case the miniAODValidation sequence is run starting from AODSIM
1857  if 'PAT' in self.stepMap and not 'RECO' in self.stepMap:
1858  return
1859 
1860  if not 'DIGI' in self.stepMap and not self._options.fast and not any(map( lambda s : s.startswith('genvalid'), valSeqName)):
1861  if self._options.restoreRNDSeeds==False and not self._options.restoreRNDSeeds==True:
1862  self._options.restoreRNDSeeds=True
1863 
1864  if not 'DIGI' in self.stepMap and not self._options.isData and not self._options.fast:
1865  self.executeAndRemember("process.mix.playback = True")
1866  self.executeAndRemember("process.mix.digitizers = cms.PSet()")
1867  self.executeAndRemember("for a in process.aliases: delattr(process, a)")
1868  self._options.customisation_file.append("SimGeneral/MixingModule/fullMixCustomize_cff.setCrossingFrameOn")
1869 
1870  if hasattr(self.process,"genstepfilter") and len(self.process.genstepfilter.triggerConditions):
1871  #will get in the schedule, smoothly
1872  for (i,s) in enumerate(valSeqName):
1873  getattr(self.process,'validation_step%s'%NFI(i)).insert(0, self.process.genstepfilter)
1874 
1875  return
1876 
1877 
1879  """Visitor that travels within a cms.Sequence, looks for a parameter and replace its value
1880  It will climb down within PSets, VPSets and VInputTags to find its target"""
1881  def __init__(self, paramSearch, paramReplace, verbose=False, whitelist=()):
1882  self._paramReplace = paramReplace
1883  self._paramSearch = paramSearch
1884  self._verbose = verbose
1885  self._whitelist = whitelist
1886 
1887  def doIt(self,pset,base):
1888  if isinstance(pset, cms._Parameterizable):
1889  for name in pset.parameters_().keys():
1890  # skip whitelisted parameters
1891  if name in self._whitelist:
1892  continue
1893  # if I use pset.parameters_().items() I get copies of the parameter values
1894  # so I can't modify the nested pset
1895  value = getattr(pset,name)
1896  type = value.pythonTypeName()
1897  if type in ('cms.PSet', 'cms.untracked.PSet'):
1898  self.doIt(value,base+"."+name)
1899  elif type in ('cms.VPSet', 'cms.untracked.VPSet'):
1900  for (i,ps) in enumerate(value): self.doIt(ps, "%s.%s[%d]"%(base,name,i) )
1901  elif type in ('cms.string', 'cms.untracked.string'):
1902  if value.value() == self._paramSearch:
1903  if self._verbose: print("set string process name %s.%s %s ==> %s"% (base, name, value, self._paramReplace))
1904  setattr(pset, name,self._paramReplace)
1905  elif type in ('cms.VInputTag', 'cms.untracked.VInputTag'):
1906  for (i,n) in enumerate(value):
1907  if not isinstance(n, cms.InputTag):
1908  n=cms.InputTag(n)
1909  if n.processName == self._paramSearch:
1910  # VInputTag can be declared as a list of strings, so ensure that n is formatted correctly
1911  if self._verbose:print("set process name %s.%s[%d] %s ==> %s " % (base, name, i, n, self._paramReplace))
1912  setattr(n,"processName",self._paramReplace)
1913  value[i]=n
1914  elif type in ('cms.vstring', 'cms.untracked.vstring'):
1915  for (i,n) in enumerate(value):
1916  if n==self._paramSearch:
1917  getattr(pset,name)[i]=self._paramReplace
1918  elif type in ('cms.InputTag', 'cms.untracked.InputTag'):
1919  if value.processName == self._paramSearch:
1920  if self._verbose: print("set process name %s.%s %s ==> %s " % (base, name, value, self._paramReplace))
1921  setattr(getattr(pset, name),"processName",self._paramReplace)
1922 
1923  def enter(self,visitee):
1924  label = ''
1925  try:
1926  label = visitee.label()
1927  except AttributeError:
1928  label = '<Module not in a Process>'
1929  except:
1930  label = 'other execption'
1931  self.doIt(visitee, label)
1932 
1933  def leave(self,visitee):
1934  pass
1935 
1936  #visit a sequence to repalce all input tags
1937  def renameInputTagsInSequence(self,sequence,oldT="rawDataCollector",newT="rawDataRepacker"):
1938  print("Replacing all InputTag %s => %s"%(oldT,newT))
1939  from PhysicsTools.PatAlgos.tools.helpers import massSearchReplaceAnyInputTag
1940  massSearchReplaceAnyInputTag(getattr(self.process,sequence),oldT,newT)
1941  loadMe='from PhysicsTools.PatAlgos.tools.helpers import massSearchReplaceAnyInputTag'
1942  if not loadMe in self.additionalCommands:
1943  self.additionalCommands.append(loadMe)
1944  self.additionalCommands.append('massSearchReplaceAnyInputTag(process.%s,"%s","%s",False,True)'%(sequence,oldT,newT))
1945 
1946  #change the process name used to address HLT results in any sequence
1947  def renameHLTprocessInSequence(self,sequence,proc=None,HLTprocess='HLT'):
1948  if self._options.hltProcess:
1949  proc=self._options.hltProcess
1950  else:
1951  proc=self.process.name_()
1952  if proc==HLTprocess: return
1953  # look up all module in dqm sequence
1954  print("replacing %s process name - sequence %s will use '%s'" % (HLTprocess,sequence, proc))
1955  getattr(self.process,sequence).visit(ConfigBuilder.MassSearchReplaceProcessNameVisitor(HLTprocess,proc,whitelist = ("subSystemFolder",)))
1956  if 'from Configuration.Applications.ConfigBuilder import ConfigBuilder' not in self.additionalCommands:
1957  self.additionalCommands.append('from Configuration.Applications.ConfigBuilder import ConfigBuilder')
1958  self.additionalCommands.append('process.%s.visit(ConfigBuilder.MassSearchReplaceProcessNameVisitor("%s", "%s", whitelist = ("subSystemFolder",)))'% (sequence,HLTprocess, proc))
1959 
1960 
1961  def expandMapping(self,seqList,mapping,index=None):
1962  maxLevel=30
1963  level=0
1964  while '@' in repr(seqList) and level<maxLevel:
1965  level+=1
1966  for specifiedCommand in seqList:
1967  if specifiedCommand.startswith('@'):
1968  location=specifiedCommand[1:]
1969  if not location in mapping:
1970  raise Exception("Impossible to map "+location+" from "+repr(mapping))
1971  mappedTo=mapping[location]
1972  if index!=None:
1973  mappedTo=mappedTo[index]
1974  seqList.remove(specifiedCommand)
1975  seqList.extend(mappedTo.split('+'))
1976  break;
1977  if level==maxLevel:
1978  raise Exception("Could not fully expand "+repr(seqList)+" from "+repr(mapping))
1979 
1980  def prepare_DQM(self, sequence = 'DQMOffline'):
1981  # this one needs replacement
1982 
1983  # any 'DQM' job should use DQMStore in non-legacy mode (but not HARVESTING)
1984  self.loadAndRemember("DQMServices/Core/DQMStoreNonLegacy_cff")
1986  sequenceList=sequence.split('.')[-1].split('+')
1987  postSequenceList=sequence.split('.')[-1].split('+')
1988  from DQMOffline.Configuration.autoDQM import autoDQM
1989  self.expandMapping(sequenceList,autoDQM,index=0)
1990  self.expandMapping(postSequenceList,autoDQM,index=1)
1991 
1992  if len(set(sequenceList))!=len(sequenceList):
1993  sequenceList=list(set(sequenceList))
1994  print("Duplicate entries for DQM:, using",sequenceList)
1995 
1996  pathName='dqmoffline_step'
1997  for (i,sequence) in enumerate(sequenceList):
1998  if (i!=0):
1999  pathName='dqmoffline_%d_step'%(i)
2000 
2001  if 'HLT' in self.stepMap.keys() or self._options.hltProcess:
2002  self.renameHLTprocessInSequence(sequence)
2003 
2004  setattr(self.process,pathName, cms.EndPath( getattr(self.process,sequence ) ) )
2005  self.schedule.append(getattr(self.process,pathName))
2006 
2007  if hasattr(self.process,"genstepfilter") and len(self.process.genstepfilter.triggerConditions):
2008  #will get in the schedule, smoothly
2009  getattr(self.process,pathName).insert(0,self.process.genstepfilter)
2010 
2011 
2012  pathName='dqmofflineOnPAT_step'
2013  for (i,sequence) in enumerate(postSequenceList):
2014  #Fix needed to avoid duplication of sequences not defined in autoDQM or without a PostDQM
2015  if (sequenceList[i]==postSequenceList[i]):
2016  continue
2017  if (i!=0):
2018  pathName='dqmofflineOnPAT_%d_step'%(i)
2019 
2020  setattr(self.process,pathName, cms.EndPath( getattr(self.process, sequence ) ) )
2021  self.schedule.append(getattr(self.process,pathName))
2022 
2023  def prepare_HARVESTING(self, sequence = None):
2024  """ Enrich the process with harvesting step """
2025  self.DQMSaverCFF='Configuration/StandardSequences/DQMSaver'+self._options.harvesting+'_cff'
2026  self.loadAndRemember(self.DQMSaverCFF)
2027 
2028  harvestingConfig = self.loadDefaultOrSpecifiedCFF(sequence,self.HARVESTINGDefaultCFF)
2029  sequence = sequence.split('.')[-1]
2030 
2031  # decide which HARVESTING paths to use
2032  harvestingList = sequence.split("+")
2033  from DQMOffline.Configuration.autoDQM import autoDQM
2034  from Validation.Configuration.autoValidation import autoValidation
2035  import copy
2036  combined_mapping = copy.deepcopy( autoDQM )
2037  combined_mapping.update( autoValidation )
2038  self.expandMapping(harvestingList,combined_mapping,index=-1)
2039 
2040  if len(set(harvestingList))!=len(harvestingList):
2041  harvestingList=list(set(harvestingList))
2042  print("Duplicate entries for HARVESTING, using",harvestingList)
2043 
2044  for name in harvestingList:
2045  if not name in harvestingConfig.__dict__:
2046  print(name,"is not a possible harvesting type. Available are",harvestingConfig.__dict__.keys())
2047  # trigger hard error, like for other sequence types
2048  getattr(self.process, name)
2049  continue
2050  harvestingstream = getattr(harvestingConfig,name)
2051  if isinstance(harvestingstream,cms.Path):
2052  self.schedule.append(harvestingstream)
2053  self.blacklist_paths.append(harvestingstream)
2054  if isinstance(harvestingstream,cms.Sequence):
2055  setattr(self.process,name+"_step",cms.Path(harvestingstream))
2056  self.schedule.append(getattr(self.process,name+"_step"))
2057 
2058  self.scheduleSequence('DQMSaver','dqmsave_step')
2059  return
2060 
2061  def prepare_ALCAHARVEST(self, sequence = None):
2062  """ Enrich the process with AlCaHarvesting step """
2063  harvestingConfig = self.loadAndRemember(self.ALCAHARVESTDefaultCFF)
2064  sequence=sequence.split(".")[-1]
2065 
2066  # decide which AlcaHARVESTING paths to use
2067  harvestingList = sequence.split("+")
2068 
2069 
2070 
2071  from Configuration.AlCa.autoPCL import autoPCL
2072  self.expandMapping(harvestingList,autoPCL)
2073 
2074  for name in harvestingConfig.__dict__:
2075  harvestingstream = getattr(harvestingConfig,name)
2076  if name in harvestingList and isinstance(harvestingstream,cms.Path):
2077  self.schedule.append(harvestingstream)
2078  if isinstance(getattr(harvestingConfig,"ALCAHARVEST" + name + "_dbOutput"), cms.VPSet) and \
2079  isinstance(getattr(harvestingConfig,"ALCAHARVEST" + name + "_metadata"), cms.VPSet):
2080  self.executeAndRemember("process.PoolDBOutputService.toPut.extend(process.ALCAHARVEST" + name + "_dbOutput)")
2081  self.executeAndRemember("process.pclMetadataWriter.recordsToMap.extend(process.ALCAHARVEST" + name + "_metadata)")
2082  else:
2083  self.executeAndRemember("process.PoolDBOutputService.toPut.append(process.ALCAHARVEST" + name + "_dbOutput)")
2084  self.executeAndRemember("process.pclMetadataWriter.recordsToMap.append(process.ALCAHARVEST" + name + "_metadata)")
2085  harvestingList.remove(name)
2086  # append the common part at the end of the sequence
2087  lastStep = getattr(harvestingConfig,"ALCAHARVESTDQMSaveAndMetadataWriter")
2088  self.schedule.append(lastStep)
2089 
2090  if len(harvestingList) != 0 and 'dummyHarvesting' not in harvestingList :
2091  print("The following harvesting could not be found : ", harvestingList)
2092  raise Exception("The following harvesting could not be found : "+str(harvestingList))
2093 
2094 
2095 
2096  def prepare_ENDJOB(self, sequence = 'endOfProcess'):
2097  self.loadDefaultOrSpecifiedCFF(sequence,self.ENDJOBDefaultCFF)
2098  self.scheduleSequenceAtEnd(sequence.split('.')[-1],'endjob_step')
2099  return
2100 
2102  self.process.reconstruction = cms.Path(self.process.reconstructionWithFamos)
2103  self.schedule.append(self.process.reconstruction)
2104 
2105 
2106  def build_production_info(self, evt_type, evtnumber):
2107  """ Add useful info for the production. """
2108  self.process.configurationMetadata=cms.untracked.PSet\
2109  (version=cms.untracked.string("$Revision: 1.19 $"),
2110  name=cms.untracked.string("Applications"),
2111  annotation=cms.untracked.string(evt_type+ " nevts:"+str(evtnumber))
2112  )
2113 
2114  self.addedObjects.append(("Production Info","configurationMetadata"))
2115 
2116 
2117  def create_process(self):
2118  self.pythonCfgCode = "# Auto generated configuration file\n"
2119  self.pythonCfgCode += "# using: \n# "+__version__[1:-1]+"\n# "+__source__[1:-1]+'\n'
2120  self.pythonCfgCode += "# with command line options: "+self._options.arguments+'\n'
2121  self.pythonCfgCode += "import FWCore.ParameterSet.Config as cms\n\n"
2122 
2123  # now set up the modifies
2124  modifiers=[]
2125  modifierStrings=[]
2126  modifierImports=[]
2127 
2128  if hasattr(self._options,"era") and self._options.era :
2129  # Multiple eras can be specified in a comma seperated list
2130  from Configuration.StandardSequences.Eras import eras
2131  for requestedEra in self._options.era.split(",") :
2132  modifierStrings.append(requestedEra)
2133  modifierImports.append(eras.pythonCfgLines[requestedEra])
2134  modifiers.append(getattr(eras,requestedEra))
2135 
2136 
2137  if hasattr(self._options,"procModifiers") and self._options.procModifiers:
2138  import importlib
2139  thingsImported=[]
2140  for c in self._options.procModifiers:
2141  thingsImported.extend(c.split(","))
2142  for pm in thingsImported:
2143  modifierStrings.append(pm)
2144  modifierImports.append('from Configuration.ProcessModifiers.'+pm+'_cff import '+pm)
2145  modifiers.append(getattr(importlib.import_module('Configuration.ProcessModifiers.'+pm+'_cff'),pm))
2146 
2147  self.pythonCfgCode += '\n'.join(modifierImports)+'\n\n'
2148  self.pythonCfgCode += "process = cms.Process('"+self._options.name+"'" # Start of the line, finished after the loop
2149 
2150 
2151  if len(modifierStrings)>0:
2152  self.pythonCfgCode+= ','+','.join(modifierStrings)
2153  self.pythonCfgCode+=')\n\n'
2154 
2155  #yes, the cfg code gets out of sync here if a process is passed in. That could be fixed in the future
2156  #assuming there is some way for the fwk to get the list of modifiers (and their stringified name)
2157  if self.process == None:
2158  if len(modifiers)>0:
2159  self.process = cms.Process(self._options.name,*modifiers)
2160  else:
2161  self.process = cms.Process(self._options.name)
2162 
2163 
2164 
2165 
2166  def prepare(self, doChecking = False):
2167  """ Prepare the configuration string and add missing pieces."""
2168 
2169  self.loadAndRemember(self.EVTCONTDefaultCFF) #load the event contents regardless
2170  self.addMaxEvents()
2171  if self.with_input:
2172  self.addSource()
2173  self.addStandardSequences()
2174  ##adding standard sequences might change the inputEventContent option and therefore needs to be finalized after
2175  self.completeInputCommand()
2176  self.addConditions()
2177 
2178 
2179  outputModuleCfgCode=""
2180  if not 'HARVESTING' in self.stepMap.keys() and not 'ALCAHARVEST' in self.stepMap.keys() and not 'ALCAOUTPUT' in self.stepMap.keys() and self.with_output:
2181  outputModuleCfgCode=self.addOutput()
2182 
2183  self.addCommon()
2184 
2185  self.pythonCfgCode += "# import of standard configurations\n"
2186  for module in self.imports:
2187  self.pythonCfgCode += ("process.load('"+module+"')\n")
2188 
2189  # production info
2190  if not hasattr(self.process,"configurationMetadata"):
2191  self.build_production_info(self._options.evt_type, self._options.number)
2192  else:
2193  #the PSet was added via a load
2194  self.addedObjects.append(("Production Info","configurationMetadata"))
2195 
2196  self.pythonCfgCode +="\n"
2197  for comment,object in self.addedObjects:
2198  if comment!="":
2199  self.pythonCfgCode += "\n# "+comment+"\n"
2200  self.pythonCfgCode += dumpPython(self.process,object)
2201 
2202  # dump the output definition
2203  self.pythonCfgCode += "\n# Output definition\n"
2204  self.pythonCfgCode += outputModuleCfgCode
2205 
2206  # dump all additional outputs (e.g. alca or skim streams)
2207  self.pythonCfgCode += "\n# Additional output definition\n"
2208  #I do not understand why the keys are not normally ordered.
2209  nl=sorted(self.additionalOutputs.keys())
2210  for name in nl:
2211  output = self.additionalOutputs[name]
2212  self.pythonCfgCode += "process.%s = %s" %(name, output.dumpPython())
2213  tmpOut = cms.EndPath(output)
2214  setattr(self.process,name+'OutPath',tmpOut)
2215  self.schedule.append(tmpOut)
2216 
2217  # dump all additional commands
2218  self.pythonCfgCode += "\n# Other statements\n"
2219  for command in self.additionalCommands:
2220  self.pythonCfgCode += command + "\n"
2221 
2222  #comma separated list of objects that deserve to be inlined in the configuration (typically from a modified config deep down)
2223  for object in self._options.inlineObjets.split(','):
2224  if not object:
2225  continue
2226  if not hasattr(self.process,object):
2227  print('cannot inline -'+object+'- : not known')
2228  else:
2229  self.pythonCfgCode +='\n'
2230  self.pythonCfgCode +=dumpPython(self.process,object)
2231 
2232  if self._options.pileup=='HiMixEmbGEN':
2233  self.pythonCfgCode += "\nprocess.generator.embeddingMode=cms.bool(True)\n"
2234 
2235  # dump all paths
2236  self.pythonCfgCode += "\n# Path and EndPath definitions\n"
2237  for path in self.process.paths:
2238  if getattr(self.process,path) not in self.blacklist_paths:
2239  self.pythonCfgCode += dumpPython(self.process,path)
2240 
2241  for endpath in self.process.endpaths:
2242  if getattr(self.process,endpath) not in self.blacklist_paths:
2243  self.pythonCfgCode += dumpPython(self.process,endpath)
2244 
2245  # dump the schedule
2246  self.pythonCfgCode += "\n# Schedule definition\n"
2247 
2248  # handling of the schedule
2249  pathNames = ['process.'+p.label_() for p in self.schedule]
2250  if self.process.schedule == None:
2251  self.process.schedule = cms.Schedule()
2252  for item in self.schedule:
2253  self.process.schedule.append(item)
2254  result = 'process.schedule = cms.Schedule('+','.join(pathNames)+')\n'
2255  else:
2256  if not isinstance(self.scheduleIndexOfFirstHLTPath, int):
2257  raise Exception('the schedule was imported from a cff in HLTrigger.Configuration, but the final index of the first HLT path is undefined')
2258 
2259  for index, item in enumerate(self.schedule):
2260  if index < self.scheduleIndexOfFirstHLTPath:
2261  self.process.schedule.insert(index, item)
2262  else:
2263  self.process.schedule.append(item)
2264 
2265  result = "# process.schedule imported from cff in HLTrigger.Configuration\n"
2266  for index, item in enumerate(pathNames[:self.scheduleIndexOfFirstHLTPath]):
2267  result += 'process.schedule.insert('+str(index)+', '+item+')\n'
2268  if self.scheduleIndexOfFirstHLTPath < len(pathNames):
2269  result += 'process.schedule.extend(['+','.join(pathNames[self.scheduleIndexOfFirstHLTPath:])+'])\n'
2270 
2271  self.pythonCfgCode += result
2272 
2273  for labelToAssociate in self.labelsToAssociate:
2274  self.process.schedule.associate(getattr(self.process, labelToAssociate))
2275  self.pythonCfgCode += 'process.schedule.associate(process.' + labelToAssociate + ')\n'
2276 
2277  from PhysicsTools.PatAlgos.tools.helpers import associatePatAlgosToolsTask
2279  self.pythonCfgCode+="from PhysicsTools.PatAlgos.tools.helpers import associatePatAlgosToolsTask\n"
2280  self.pythonCfgCode+="associatePatAlgosToolsTask(process)\n"
2281 
2282  if self._options.nThreads != "1":
2283  self.pythonCfgCode +="\n"
2284  self.pythonCfgCode +="#Setup FWK for multithreaded\n"
2285  self.pythonCfgCode +="process.options.numberOfThreads = "+self._options.nThreads+"\n"
2286  self.pythonCfgCode +="process.options.numberOfStreams = "+self._options.nStreams+"\n"
2287  self.pythonCfgCode +="process.options.numberOfConcurrentLuminosityBlocks = "+self._options.nConcurrentLumis+"\n"
2288  self.pythonCfgCode +="process.options.eventSetup.numberOfConcurrentIOVs = "+self._options.nConcurrentIOVs+"\n"
2289  if int(self._options.nConcurrentLumis) > 1:
2290  self.pythonCfgCode +="if hasattr(process, 'DQMStore'): process.DQMStore.assertLegacySafe=cms.untracked.bool(False)\n"
2291  self.process.options.numberOfThreads = int(self._options.nThreads)
2292  self.process.options.numberOfStreams = int(self._options.nStreams)
2293  self.process.options.numberOfConcurrentLuminosityBlocks = int(self._options.nConcurrentLumis)
2294  self.process.options.eventSetup.numberOfConcurrentIOVs = int(self._options.nConcurrentIOVs)
2295  #repacked version
2296  if self._options.isRepacked:
2297  self.pythonCfgCode +="\n"
2298  self.pythonCfgCode +="from Configuration.Applications.ConfigBuilder import MassReplaceInputTag\n"
2299  self.pythonCfgCode +="MassReplaceInputTag(process, new=\"rawDataMapperByLabel\", old=\"rawDataCollector\")\n"
2300  MassReplaceInputTag(self.process, new="rawDataMapperByLabel", old="rawDataCollector")
2301 
2302  # special treatment in case of production filter sequence 2/2
2303  if self.productionFilterSequence and not (self._options.pileup=='HiMixEmbGEN'):
2304  self.pythonCfgCode +='# filter all path with the production filter sequence\n'
2305  self.pythonCfgCode +='for path in process.paths:\n'
2306  if len(self.conditionalPaths):
2307  self.pythonCfgCode +='\tif not path in %s: continue\n'%str(self.conditionalPaths)
2308  if len(self.excludedPaths):
2309  self.pythonCfgCode +='\tif path in %s: continue\n'%str(self.excludedPaths)
2310  self.pythonCfgCode +='\tgetattr(process,path).insert(0, process.%s)\n'%(self.productionFilterSequence,)
2311  pfs = getattr(self.process,self.productionFilterSequence)
2312  for path in self.process.paths:
2313  if not path in self.conditionalPaths: continue
2314  if path in self.excludedPaths: continue
2315  getattr(self.process,path).insert(0, pfs)
2316 
2317 
2318  # dump customise fragment
2319  self.pythonCfgCode += self.addCustomise()
2320 
2321  if self._options.runUnscheduled:
2322  print("--runUnscheduled is deprecated and not necessary anymore, and will be removed soon. Please update your command line.")
2323  # Keep the "unscheduled customise functions" separate for now,
2324  # there are customize functions given by users (in our unit
2325  # tests) that need to be run before the "unscheduled customise
2326  # functions"
2327  self.pythonCfgCode += self.addCustomise(1)
2328 
2329  self.pythonCfgCode += self.addCustomiseCmdLine()
2330 
2331  if hasattr(self.process,"logErrorHarvester"):
2332  #configure logErrorHarvester to wait for same EDProducers to finish as the OutputModules
2333  self.pythonCfgCode +="\n#Have logErrorHarvester wait for the same EDProducers to finish as those providing data for the OutputModule\n"
2334  self.pythonCfgCode +="from FWCore.Modules.logErrorHarvester_cff import customiseLogErrorHarvesterUsingOutputCommands\n"
2335  self.pythonCfgCode +="process = customiseLogErrorHarvesterUsingOutputCommands(process)\n"
2336  from FWCore.Modules.logErrorHarvester_cff import customiseLogErrorHarvesterUsingOutputCommands
2338 
2339  # Temporary hack to put the early delete customization after
2340  # everything else
2341  #
2342  # FIXME: remove when no longer needed
2343  self.pythonCfgCode += "\n# Add early deletion of temporary data products to reduce peak memory need\n"
2344  self.pythonCfgCode += "from Configuration.StandardSequences.earlyDeleteSettings_cff import customiseEarlyDelete\n"
2345  self.pythonCfgCode += "process = customiseEarlyDelete(process)\n"
2346  self.pythonCfgCode += "# End adding early deletion\n"
2347  from Configuration.StandardSequences.earlyDeleteSettings_cff import customiseEarlyDelete
2348  self.process = customiseEarlyDelete(self.process)
2349 
2350  imports = cms.specialImportRegistry.getSpecialImports()
2351  if len(imports) > 0:
2352  #need to inject this at the top
2353  index = self.pythonCfgCode.find("import FWCore.ParameterSet.Config")
2354  #now find the end of line
2355  index = self.pythonCfgCode.find("\n",index)
2356  self.pythonCfgCode = self.pythonCfgCode[:index]+ "\n" + "\n".join(imports)+"\n" +self.pythonCfgCode[index:]
2357 
2358 
2359  # make the .io file
2360 
2361  if self._options.io:
2362  #io=open(self._options.python_filename.replace('.py','.io'),'w')
2363  if not self._options.io.endswith('.io'): self._option.io+='.io'
2364  io=open(self._options.io,'w')
2365  ioJson={}
2366  if hasattr(self.process.source,"fileNames"):
2367  if len(self.process.source.fileNames.value()):
2368  ioJson['primary']=self.process.source.fileNames.value()
2369  if hasattr(self.process.source,"secondaryFileNames"):
2370  if len(self.process.source.secondaryFileNames.value()):
2371  ioJson['secondary']=self.process.source.secondaryFileNames.value()
2372  if self._options.pileup_input and (self._options.pileup_input.startswith('dbs:') or self._options.pileup_input.startswith('das:')):
2373  ioJson['pileup']=self._options.pileup_input[4:]
2374  for (o,om) in self.process.outputModules_().items():
2375  ioJson[o]=om.fileName.value()
2376  ioJson['GT']=self.process.GlobalTag.globaltag.value()
2377  if self.productionFilterSequence:
2378  ioJson['filter']=self.productionFilterSequence
2379  import json
2380  io.write(json.dumps(ioJson))
2381  return
2382 
bool any(const std::vector< T > &v, const T &what)
Definition: ECalSD.cc:37
inliner
load the relevant part
process
adding standard sequences might change the inputEventContent option and therefore needs to be finaliz...
def lumi_to_run
Definition: LumiToRun.py:1
assert(be >=bs)
const uint16_t range(const Frame &aFrame)
def defineMixing
Definition: Mixing.py:190
OutputIterator zip(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result, Compare comp)
void print(TMatrixD &m, const char *label=nullptr, bool mathematicaFormat=false)
Definition: Utilities.cc:47
productionFilterSequence
put it before all the other paths
runsAndWeights
drop LHEXMLStringProduct on input to save memory if appropriate
bool insert(Storage &iStorage, ItemType *iItem, const IdTag &iIdTag)
Definition: HCMethods.h:50
def associatePatAlgosToolsTask
Definition: helpers.py:24
def miniAOD_customizeOutput
static std::string join(char **cmd)
Definition: RemoteFile.cc:19
def massSearchReplaceAnyInputTag
Definition: MassReplace.py:79
#define str(s)
nextScheduleIsConditional
put the filtering path in the schedule