CMS 3D CMS Logo

runTheMatrix.py
Go to the documentation of this file.
1 #!/usr/bin/env python3
2 from __future__ import print_function
3 import sys, os
4 
5 from Configuration.PyReleaseValidation.MatrixReader import MatrixReader
6 from Configuration.PyReleaseValidation.MatrixRunner import MatrixRunner
7 from Configuration.PyReleaseValidation.MatrixInjector import MatrixInjector,performInjectionOptionTest
8 
9 # ================================================================================
10 
11 def showRaw(opt):
12 
13  mrd = MatrixReader(opt)
14  mrd.showRaw(opt.useInput, opt.refRel, opt.fromScratch, opt.raw, opt.step1Only, selected=opt.testList)
15 
16  return 0
17 
18 # ================================================================================
19 
20 def runSelected(opt):
21 
22  mrd = MatrixReader(opt)
23  mrd.prepare(opt.useInput, opt.refRel, opt.fromScratch)
24 
25  # test for wrong input workflows
26  if opt.testList:
27  definedWf = [dwf.numId for dwf in mrd.workFlows]
28  definedSet = set(definedWf)
29  testSet = set(opt.testList)
30  undefSet = testSet - definedSet
31  if len(undefSet)>0: raise ValueError('Undefined workflows: '+', '.join(map(str,list(undefSet))))
32  duplicates = [wf for wf in testSet if definedWf.count(wf)>1 ]
33  if len(duplicates)>0: raise ValueError('Duplicated workflows: '+', '.join(map(str,list(duplicates))))
34 
35  ret = 0
36  if opt.show:
37  mrd.show(opt.testList, opt.extended, opt.cafVeto)
38  if opt.testList : print('testListected items:', opt.testList)
39  else:
40  mRunnerHi = MatrixRunner(mrd.workFlows, opt.nProcs, opt.nThreads)
41  ret = mRunnerHi.runTests(opt)
42 
43  if opt.wmcontrol:
44  if ret!=0:
45  print('Cannot go on with wmagent injection with failing workflows')
46  else:
47  wfInjector = MatrixInjector(opt,mode=opt.wmcontrol,options=opt.wmoptions)
48  ret= wfInjector.prepare(mrd,
49  mRunnerHi.runDirs)
50  if ret==0:
51  wfInjector.upload()
52  wfInjector.submit()
53  return ret
54 
55 # ================================================================================
56 
57 if __name__ == '__main__':
58 
59  #this can get out of here
60  predefinedSet={
61  'limited' : [
62  # See README for further details
63 
66  5.1, # TTbar_8TeV_TuneCUETP8M1 FastSim
67  8, # RelValBeamHalo Cosmics
68  9.0, # RelValHiggs200ChargedTaus
69  25, # RelValTTbar
70  101.0, # SingleElectronE120EHCAL + ECALHCAL.customise + fullMixCustomize_cff.setCrossingFrameOn
71 
72  # Run2
73  7.3, # UndergroundCosmicSPLooseMu
74  1306.0, # RelValSingleMuPt1_UP15
75  1330, # RelValZMM_13
76  135.4, # ZEE_13TeV_TuneCUETP8M1
77  25202.0, # RelValTTbar_13 PU = AVE_35_BX_25ns
78  250202.181, # RelValTTbar_13 PREMIX
79 
80  # Run3
81  11634.0, # TTbar_14TeV
82  13234.0, # RelValTTbar_14TeV FastsSim
83  12434.0, # RelValTTbar_14TeV
84  12446.0, # RelValZEE_13
85  12634.0, # RelValTTbar_14TeV PU = Run3_Flat55To75_PoissonOOTPU
86  12434.7, # RelValTTbar_14TeV mkFit
87  14034.0, # RelValTTbar_14TeV Run3_2023_FastSim
88  14234.0, # RelValTTbar_14TeV Run3_2023_FastSim PU = Run3_Flat55To75_PoissonOOTPU
89  2500.4, # RelValTTbar_14TeV NanoAOD from existing MINI
90 
91  # Phase2
92  24834.0, # RelValTTbar_14TeV phase2_realistic_T25 Extended2026D98 (Phase-2 baseline)
93  24834.911, # TTbar_14TeV_TuneCP5 phase2_realistic_T25 DD4hepExtended2026D98 DD4Hep (HLLHC14TeV BeamSpot)
94  25034.999, # RelValTTbar_14TeV (PREMIX) phase2_realistic_T25 Extended2026D98 AVE_50_BX_25ns_m3p3
95  24896.0, # RelValCloseByPGun_CE_E_Front_120um phase2_realistic_T25 Extended2026D98
96  24900.0, # RelValCloseByPGun_CE_H_Coarse_Scint phase2_realistic_T25 Extended2026D98
97  23234.0, # TTbar_14TeV_TuneCP5 phase2_realistic_T21 Extended2026D94 (exercise with HFNose)
98 
99 
100 
102  4.22, # Run2011A Cosmics
103  4.53, # Run2012B Photon miniAODs
104  1000, # Run2011A MinimumBias Prompt RecoTLR.customisePrompt
105  1001, # Run2011A MinimumBias Data+Express
106 
107  136.731, # Run2016B SinglePhoton
108  136.7611, # Run2016E JetHT (reMINIAOD) Run2_2016_HIPM + run2_miniAOD_80XLegacy
109  136.8311, # Run2017F JetHT (reMINIAOD) run2_miniAOD_94XFall17
110  136.88811, # Run2018D JetHT (reMINIAOD) run2_miniAOD_UL_preSummer20 (UL MINI)
111  136.793, # Run2017C DoubleEG
112  136.874, # Run2018C EGamma
113 
114 
116  139.001, # Run2021 MinimumBias Commissioning2021
117 
118  # 2022
119  140.023, # Run2022B ZeroBias
120  140.043, # Run2022C ZeroBias
121  140.063, # Run2022D ZeroBias
122 
123  # 2023
124  141.044, # Run2023D JetMET0
125  141.042, # Run2023D ZeroBias
126  141.046, # Run2023D EGamma0
127 
128 
131  140.53, # HIRun2011 HIMinBiasUPC
132  # Run2
133  140.56, # HIRun2018A HIHardProbes Run2_2018_pp_on_AA
134 
135  158.01, # RelValHydjetQ_B12_5020GeV_2018_ppReco (reMINIAOD) (HI MC with pp-like reco)
136  312.0, # Pyquen_ZeemumuJets_pt10_2760GeV PU : HiMixGEN
137 
138  ],
139  'jetmc': [5.1, 13, 15, 25, 38, 39], #MC
140  'metmc' : [5.1, 15, 25, 37, 38, 39], #MC
141  'muonmc' : [5.1, 124.4, 124.5, 20, 21, 22, 23, 25, 30], #MC
142  }
143 
144 
145  import argparse
146  usage = 'usage: runTheMatrix.py --show -s '
147 
148  parser = argparse.ArgumentParser(usage,formatter_class=argparse.ArgumentDefaultsHelpFormatter)
149 
150  parser.add_argument('-b','--batchName',
151  help='relval batch: suffix to be appended to Campaign name',
152  dest='batchName',
153  default='')
154 
155  parser.add_argument('-m','--memoryOffset',
156  help='memory of the wf for single core',
157  dest='memoryOffset',
158  type=int,
159  default=3000)
160 
161  parser.add_argument('--addMemPerCore',
162  help='increase of memory per each n > 1 core: memory(n_core) = memoryOffset + (n_core-1) * memPerCore',
163  dest='memPerCore',
164  type=int,
165  default=1500)
166 
167  parser.add_argument('-j','--nproc',
168  help='number of processes. 0 Will use 4 processes, not execute anything but create the wfs',
169  dest='nProcs',
170  type=int,
171  default=4)
172 
173  parser.add_argument('-t','--nThreads',
174  help='number of threads per process to use in cmsRun.',
175  dest='nThreads',
176  type=int,
177  default=1)
178 
179  parser.add_argument('--nStreams',
180  help='number of streams to use in cmsRun.',
181  dest='nStreams',
182  type=int,
183  default=0)
184 
185  parser.add_argument('--nEvents',
186  help='number of events to process in cmsRun. If 0 will use the standard 10 events.',
187  dest='nEvents',
188  type=int,
189  default=0)
190 
191  parser.add_argument('--numberEventsInLuminosityBlock',
192  help='number of events in a luminosity block',
193  dest='numberEventsInLuminosityBlock',
194  type=int,
195  default=-1)
196 
197  parser.add_argument('-n','--showMatrix',
198  help='Only show the worflows. Use --ext to show more',
199  dest='show',
200  default=False,
201  action='store_true')
202 
203  parser.add_argument('-e','--extended',
204  help='Show details of workflows, used with --show',
205  dest='extended',
206  default=False,
207  action='store_true')
208 
209  parser.add_argument('-s','--selected',
210  help='Run a pre-defined selected matrix of wf. Deprecated, please use -l limited',
211  dest='restricted',
212  default=False,
213  action='store_true')
214 
215  parser.add_argument('-l','--list',
216  help='Comma separated list of workflow to be shown or ran. Possible keys are also '+str(predefinedSet.keys())+'. and wild card like muon, or mc',
217  dest='testList',
218  default=None)
219 
220  parser.add_argument('-f','--failed-from',
221  help='Provide a matrix report to specify the workflows to be run again. Augments the -l option if specified already',
222  dest='failed_from',
223  default=None)
224 
225  parser.add_argument('-r','--raw',
226  help='Temporary dump the .txt needed for prodAgent interface. To be discontinued soon. Argument must be the name of the set (standard, pileup,...)',
227  dest='raw')
228 
229  parser.add_argument('-i','--useInput',
230  help='Use recyling where available. Either all, or a comma separated list of wf number.',
231  dest='useInput',
232  type=lambda x: x.split(','),
233  default=None)
234 
235  parser.add_argument('-w','--what',
236  help='Specify the set to be used. Argument must be the name of a set (standard, pileup,...) or multiple sets separated by commas (--what standard,pileup )',
237  dest='what',
238  default='all')
239 
240  parser.add_argument('--step1',
241  help='Used with --raw. Limit the production to step1',
242  dest='step1Only',
243  default=False)
244 
245  parser.add_argument('--maxSteps',
246  help='Only run maximum on maxSteps. Used when we are only interested in first n steps.',
247  dest='maxSteps',
248  default=9999,
249  type=int)
250 
251  parser.add_argument('--fromScratch',
252  help='Comma separated list of wf to be run without recycling. all is not supported as default.',
253  dest='fromScratch',
254  type=lambda x: x.split(','),
255  default=None)
256 
257  parser.add_argument('--refRelease',
258  help='Allow to modify the recycling dataset version',
259  dest='refRel',
260  default=None)
261 
262  parser.add_argument('--wmcontrol',
263  help='Create the workflows for injection to WMAgent. In the WORKING. -wmcontrol init will create the the workflows, -wmcontrol test will dryRun a test, -wmcontrol submit will submit to wmagent',
264  choices=['init','test','submit','force'],
265  dest='wmcontrol',
266  default=None)
267 
268  parser.add_argument('--revertDqmio',
269  help='When submitting workflows to wmcontrol, force DQM outout to use pool and not DQMIO',
270  choices=['yes','no'],
271  dest='revertDqmio',
272  default='no')
273 
274  parser.add_argument('--optionswm',
275  help='Specify a few things for wm injection',
276  default='',
277  dest='wmoptions')
278 
279  parser.add_argument('--keep',
280  help='allow to specify for which comma separated steps the output is needed',
281  default=None)
282 
283  parser.add_argument('--label',
284  help='allow to give a special label to the output dataset name',
285  default='')
286 
287  parser.add_argument('--command',
288  help='provide a way to add additional command to all of the cmsDriver commands in the matrix',
289  dest='command',
290  action='append',
291  default=None)
292 
293  parser.add_argument('--apply',
294  help='allow to use the --command only for 1 comma separeated',
295  dest='apply',
296  default=None)
297 
298  parser.add_argument('--workflow',
299  help='define a workflow to be created or altered from the matrix',
300  action='append',
301  dest='workflow',
302  default=None)
303 
304  parser.add_argument('--dryRun',
305  help='do not run the wf at all',
306  action='store_true',
307  dest='dryRun',
308  default=False)
309 
310  parser.add_argument('--testbed',
311  help='workflow injection to cmswebtest (you need dedicated rqmgr account)',
312  dest='testbed',
313  default=False,
314  action='store_true')
315 
316  parser.add_argument('--noCafVeto',
317  help='Run from any source, ignoring the CAF label',
318  dest='cafVeto',
319  default=True,
320  action='store_false')
321 
322  parser.add_argument('--overWrite',
323  help='Change the content of a step for another. List of pairs.',
324  dest='overWrite',
325  default=None)
326 
327  parser.add_argument('--noRun',
328  help='Remove all run list selection from wfs',
329  dest='noRun',
330  default=False,
331  action='store_true')
332 
333  parser.add_argument('--das-options',
334  help='Options to be passed to dasgoclient.',
335  dest='dasOptions',
336  default="--limit 0",
337  action='store')
338 
339  parser.add_argument('--job-reports',
340  help='Dump framework job reports',
341  dest='jobReports',
342  default=False,
343  action='store_true')
344 
345  parser.add_argument('--ibeos',
346  help='Use IB EOS site configuration',
347  dest='IBEos',
348  default=False,
349  action='store_true')
350 
351  parser.add_argument('--sites',
352  help='Run DAS query to get data from a specific site. Set it to empty string to search all sites.',
353  dest='dasSites',
354  default='T2_CH_CERN',
355  action='store')
356 
357  parser.add_argument('--interactive',
358  help="Open the Matrix interactive shell",
359  action='store_true',
360  default=False)
361 
362  parser.add_argument('--dbs-url',
363  help='Overwrite DbsUrl value in JSON submitted to ReqMgr2',
364  dest='dbsUrl',
365  default=None,
366  action='store')
367 
368  gpugroup = parser.add_argument_group('GPU-related options','These options are only meaningful when --gpu is used, and is not set to forbidden.')
369 
370  gpugroup.add_argument('--gpu','--requires-gpu',
371  help='Enable GPU workflows. Possible options are "forbidden" (default), "required" (implied if no argument is given), or "optional".',
372  dest='gpu',
373  choices=['forbidden', 'optional', 'required'],
374  nargs='?',
375  const='required',
376  default='forbidden',
377  action='store')
378 
379  gpugroup.add_argument('--gpu-memory',
380  help='Specify the minimum amount of GPU memory required by the job, in MB.',
381  dest='GPUMemoryMB',
382  type=int,
383  default=8000)
384 
385  gpugroup.add_argument('--cuda-capabilities',
386  help='Specify a comma-separated list of CUDA "compute capabilities", or GPU hardware architectures, that the job can use.',
387  dest='CUDACapabilities',
388  type=lambda x: x.split(','),
389  default='6.0,6.1,6.2,7.0,7.2,7.5,8.0,8.6')
390 
391  # read the CUDA runtime version included in CMSSW
392  cudart_version = None
393  libcudart = os.path.realpath(os.path.expandvars('$CMSSW_RELEASE_BASE/external/$SCRAM_ARCH/lib/libcudart.so'))
394  if os.path.isfile(libcudart):
395  cudart_basename = os.path.basename(libcudart)
396  cudart_version = '.'.join(cudart_basename.split('.')[2:4])
397  gpugroup.add_argument('--cuda-runtime',
398  help='Specify major and minor version of the CUDA runtime used to build the application.',
399  dest='CUDARuntime',
400  default=cudart_version)
401 
402  gpugroup.add_argument('--force-gpu-name',
403  help='Request a specific GPU model, e.g. "Tesla T4" or "NVIDIA GeForce RTX 2080". The default behaviour is to accept any supported GPU.',
404  dest='GPUName',
405  default='')
406 
407  gpugroup.add_argument('--force-cuda-driver-version',
408  help='Request a specific CUDA driver version, e.g. 470.57.02. The default behaviour is to accept any supported CUDA driver version.',
409  dest='CUDADriverVersion',
410  default='')
411 
412  gpugroup.add_argument('--force-cuda-runtime-version',
413  help='Request a specific CUDA runtime version, e.g. 11.4. The default behaviour is to accept any supported CUDA runtime version.',
414  dest='CUDARuntimeVersion',
415  default='')
416 
417  opt = parser.parse_args()
418  if opt.command: opt.command = ' '.join(opt.command)
419  os.environ["CMSSW_DAS_QUERY_SITES"]=opt.dasSites
420  if opt.failed_from:
421  rerunthese=[]
422  with open(opt.failed_from,'r') as report:
423  for report_line in report:
424  if 'FAILED' in report_line:
425  to_run,_=report_line.split('_',1)
426  rerunthese.append(to_run)
427  if opt.testList:
428  opt.testList+=','.join(['']+rerunthese)
429  else:
430  opt.testList = ','.join(rerunthese)
431 
432  if opt.IBEos:
433  from subprocess import getstatusoutput as run_cmd
434 
435  ibeos_cache = os.path.join(os.getenv("LOCALRT"), "ibeos_cache.txt")
436  if not os.path.exists(ibeos_cache):
437  err, out = run_cmd("curl -L -s -o %s https://raw.githubusercontent.com/cms-sw/cms-sw.github.io/master/das_queries/ibeos.txt" % ibeos_cache)
438  if err:
439  run_cmd("rm -f %s" % ibeos_cache)
440  print("Error: Unable to download ibeos cache information")
441  print(out)
442  sys.exit(err)
443 
444  for cmssw_env in [ "CMSSW_BASE", "CMSSW_RELEASE_BASE" ]:
445  cmssw_base = os.getenv(cmssw_env,None)
446  if not cmssw_base: continue
447  cmssw_base = os.path.join(cmssw_base,"src/Utilities/General/ibeos")
448  if os.path.exists(cmssw_base):
449  os.environ["PATH"]=cmssw_base+":"+os.getenv("PATH")
450  os.environ["CMS_PATH"]="/cvmfs/cms-ib.cern.ch"
451  os.environ["SITECONFIG_PATH"]="/cvmfs/cms-ib.cern.ch/SITECONF/local"
452  os.environ["CMSSW_USE_IBEOS"]="true"
453  print(">> WARNING: You are using SITECONF from /cvmfs/cms-ib.cern.ch")
454  break
455  if opt.restricted:
456  print('Deprecated, please use -l limited')
457  if opt.testList: opt.testList+=',limited'
458  else: opt.testList='limited'
459 
460  def stepOrIndex(s):
461  if s.isdigit():
462  return int(s)
463  else:
464  return s
465  if opt.apply:
466  opt.apply=map(stepOrIndex,opt.apply.split(','))
467  if opt.keep:
468  opt.keep=map(stepOrIndex,opt.keep.split(','))
469 
470  if opt.testList:
471  testList=[]
472  for entry in opt.testList.split(','):
473  if not entry: continue
474  mapped=False
475  for k in predefinedSet:
476  if k.lower().startswith(entry.lower()) or k.lower().endswith(entry.lower()):
477  testList.extend(predefinedSet[k])
478  mapped=True
479  break
480  if not mapped:
481  try:
482  testList.append(float(entry))
483  except:
484  print(entry,'is not a possible selected entry')
485 
486  opt.testList = list(set(testList))
487 
488  if opt.wmcontrol:
490  if opt.overWrite:
491  opt.overWrite=eval(opt.overWrite)
492  if opt.interactive:
493  import cmd
494  from colorama import Fore, Style
495  from os import isatty
496  import subprocess
497  import time
498 
499  class TheMatrix(cmd.Cmd):
500  intro = "Welcome to the Matrix (? for help)"
501  prompt = "matrix> "
502 
503  def __init__(self, opt):
504  cmd.Cmd.__init__(self)
505  self.opt_ = opt
506  self.matrices_ = {}
507  tmp = MatrixReader(self.opt_)
508  self.processes_ = dict()
509  for what in tmp.files:
510  what = what.replace('relval_','')
511  self.opt_.what = what
512  self.matrices_[what] = MatrixReader(self.opt_)
513  self.matrices_[what].prepare(self.opt_.useInput, self.opt_.refRel,
514  self.opt_.fromScratch)
515  os.system("clear")
516 
517  def do_clear(self, arg):
518  """Clear the screen, put prompt at the top"""
519  os.system("clear")
520 
521  def do_exit(self, arg):
522  print("Leaving the Matrix")
523  return True
524 
525  def default(self, inp):
526  if inp == 'x' or inp == 'q':
527  return self.do_exit(inp)
528  else:
529  is_pipe = not isatty(sys.stdin.fileno())
530  print(Fore.RED + "Error: " + Fore.RESET + "unrecognized command.")
531  # Quit only if given a piped command.
532  if is_pipe:
533  sys.exit(1)
534 
535  def help_predefined(self):
536  print("\n".join(["predefined [predef1 [...]]\n",
537  "Run w/o argument, it will print the list of known predefined workflows.",
538  "Run with space-separated predefined workflows, it will print the workflow-ids registered to them"]))
539 
540  def complete_predefined(self, text, line, start_idx, end_idx):
541  if text and len(text) > 0:
542  return [t for t in predefinedSet.keys() if t.startswith(text)]
543  else:
544  return predefinedSet.keys()
545 
546  def do_predefined(self, arg):
547  """Print the list of predefined workflows"""
548  print("List of predefined workflows")
549  if arg:
550  for w in arg.split():
551  if w in predefinedSet.keys():
552  print("Predefined Set: %s" % w)
553  print(predefinedSet[w])
554  else:
555  print("Unknown Set: %s" % w)
556  else:
557  print("[ " + Fore.RED + ", ".join([str(k) for k in predefinedSet.keys()]) + Fore.RESET + " ]")
558 
559  def help_showWorkflow(self):
560  print("\n".join(["showWorkflow [workflow1 [...]]\n",
561  "Run w/o arguments, it will print the list of registered macro-workflows.",
562  "Run with space-separated workflows, it will print the full list of workflow-ids registered to them"]))
563 
564  def complete_showWorkflow(self, text, line, start_idx, end_idx):
565  if text and len(text) > 0:
566  return [t for t in self.matrices_.keys() if t.startswith(text)]
567  else:
568  return self.matrices_.keys()
569 
570  def do_showWorkflow(self, arg):
571  if arg == '':
572  print("Available workflows:")
573  for k in self.matrices_.keys():
574  print(Fore.RED + Style.BRIGHT + k)
575  print(Style.RESET_ALL)
576  else:
577  selected = arg.split()
578  for k in selected:
579  if k not in self.matrices_.keys():
580  print("Unknown workflow %s: skipping" % k)
581  else:
582  for wfl in self.matrices_[k].workFlows:
583  print("%s %s" % (Fore.BLUE + str(wfl.numId) + Fore.RESET,
584  Fore.GREEN + wfl.nameId + Fore.RESET))
585  print("%s contains %d workflows" % (Fore.RED + k + Fore.RESET, len(self.matrices_[k].workFlows)))
586 
587  def do_runWorkflow(self, arg):
588  # Split the input arguments into a list
589  args = arg.split()
590  if len(args) < 2:
591  print(Fore.RED + Style.BRIGHT + "Wrong number of parameters passed")
592  print(Style.RESET_ALL)
593  return
594  workflow_class = args[0]
595  workflow_id = args[1]
596  passed_down_args = list()
597  if len(args) > 2:
598  passed_down_args = args[2:]
599  print(Fore.YELLOW + Style.BRIGHT + "Running with the following options:\n")
600  print(Fore.GREEN + Style.BRIGHT + "Workflow class: {}".format(workflow_class))
601  print(Fore.GREEN + Style.BRIGHT + "Workflow ID: {}".format(workflow_id))
602  print(Fore.GREEN + Style.BRIGHT + "Additional runTheMatrix options: {}".format(passed_down_args))
603  print(Style.RESET_ALL)
604  if workflow_class not in self.matrices_.keys():
605  print(Fore.RED + Style.BRIGHT + "Unknown workflow selected: {}".format(workflow_class))
606  print("Available workflows:")
607  for k in self.matrices_.keys():
608  print(Fore.RED + Style.BRIGHT + k)
609  print(Style.RESET_ALL)
610  return
611  wflnums = [x.numId for x in self.matrices_[workflow_class].workFlows]
612  if float(workflow_id) not in wflnums:
613  print(Fore.RED + Style.BRIGHT + "Unknown workflow {}".format(workflow_id))
614  print(Fore.GREEN + Style.BRIGHT)
615  print(wflnums)
616  print(Style.RESET_ALL)
617  return
618  if workflow_id in self.processes_.keys():
619  # Check if the process is still active
620  if self.processes_[workflow_id][0].poll() is None:
621  print(Fore.RED + Style.BRIGHT + "Workflow {} already running!".format(workflow_id))
622  print(Style.RESET_ALL)
623  return
624  # If it was there but it's gone, proceeed and update the value for the same key
625  # run a job, redirecting standard output and error to files
626  lognames = ['stdout', 'stderr']
627  logfiles = tuple('%s_%s_%s.log' % (workflow_class, workflow_id, name) for name in lognames)
628  stdout = open(logfiles[0], 'w')
629  stderr = open(logfiles[1], 'w')
630  command = ('runTheMatrix.py', '-w', workflow_class, '-l', workflow_id)
631  if len(passed_down_args) > 0:
632  command += tuple(passed_down_args)
633  print(command)
634  p = subprocess.Popen(command,
635  stdout = stdout,
636  stderr = stderr)
637  self.processes_[workflow_id] = (p, time.time())
638 
639 
640  def complete_runWorkflow(self, text, line, start_idx, end_idx):
641  if text and len(text) > 0:
642  return [t for t in self.matrices_.keys() if t.startswith(text)]
643  else:
644  return self.matrices_.keys()
645 
646  def help_runWorkflow(self):
647  print("\n".join(["runWorkflow workflow_class workflow_id\n",
648  "This command will launch a new and independent process that invokes",
649  "the command:\n",
650  "runTheMatrix.py -w workflow_class -l workflow_id [runTheMatrix.py options]",
651  "\nYou can specify just one workflow_class and workflow_id per invocation.",
652  "The job will continue even after quitting the interactive session.",
653  "stdout and stderr of the new process will be automatically",
654  "redirected to 2 logfiles whose names contain the workflow_class",
655  "and workflow_id. Mutiple command can be issued one after the other.",
656  "The working directory of the new process will be the directory",
657  "from which the interactive session has started.",
658  "Autocompletion is available for workflow_class, but",
659  "not for workflow_id. Supplying a wrong workflow_class or",
660  "a non-existing workflow_id for a valid workflow_class",
661  "will trigger an error and no process will be invoked.",
662  "The interactive shell will keep track of all active processes",
663  "and will prevent the accidental resubmission of an already",
664  "active jobs."]))
665 
666  def do_jobs(self, args):
667  print(Fore.GREEN + Style.BRIGHT + "List of jobs:")
668  for w in self.processes_.keys():
669  if self.processes_[w][0].poll() is None:
670  print(Fore.YELLOW + Style.BRIGHT + "Active job: {} since {:.2f} seconds.".format(w, time.time() - self.processes_[w][1]))
671  else:
672  print(Fore.RED + Style.BRIGHT + "Done job: {}".format(w))
673  print(Style.RESET_ALL)
674 
675  def help_jobs(self):
676  print("\n".join(["Print a full list of active and done jobs submitted",
677  "in the ongoing interactive session"]))
678 
680  print("\n".join(["searchInWorkflow wfl_name search_regexp\n",
681  "This command will search for a match within all workflows registered to wfl_name.",
682  "The search is done on both the workflow name and the names of steps registered to it."]))
683 
684  def complete_searchInWorkflow(self, text, line, start_idx, end_idx):
685  if text and len(text) > 0:
686  return [t for t in self.matrices_.keys() if t.startswith(text)]
687  else:
688  return self.matrices_.keys()
689 
690  def do_searchInWorkflow(self, arg):
691  args = arg.split()
692  if len(args) < 2:
693  print("searchInWorkflow name regexp")
694  return
695  if args[0] not in self.matrices_.keys():
696  print("Unknown workflow")
697  return
698  import re
699  pattern = None
700  try:
701  pattern = re.compile(args[1])
702  except:
703  print("Failed to compile regexp %s" % args[1])
704  return
705  counter = 0
706  for wfl in self.matrices_[args[0]].workFlows:
707  if re.match(pattern, wfl.nameId):
708  print("%s %s" % (Fore.BLUE + str(wfl.numId) + Fore.RESET,
709  Fore.GREEN + wfl.nameId + Fore.RESET))
710  counter +=1
711  print("Found %s compatible workflows inside %s" % (Fore.RED + str(counter) + Fore.RESET,
712  Fore.YELLOW + str(args[0])) + Fore.RESET)
713 
714  def help_search(self):
715  print("\n".join(["search search_regexp\n",
716  "This command will search for a match within all workflows registered.",
717  "The search is done on both the workflow name and the names of steps registered to it."]))
718 
719  def do_search(self, arg):
720  args = arg.split()
721  if len(args) < 1:
722  print("search regexp")
723  return
724  for wfl in self.matrices_.keys():
725  self.do_searchInWorkflow(' '.join([wfl, args[0]]))
726 
728  print("\n".join(["dumpWorkflowId [wfl-id1 [...]]\n",
729  "Dumps the details (cmsDriver commands for all steps) of the space-separated workflow-ids in input."]))
730 
731  def do_dumpWorkflowId(self, arg):
732  wflids = arg.split()
733  if len(wflids) == 0:
734  print("dumpWorkflowId [wfl-id1 [...]]")
735  return
736 
737  fmt = "[%s]: %s\n"
738  maxLen = 100
739  for wflid in wflids:
740  dump = True
741  for key, mrd in self.matrices_.items():
742  for wfl in mrd.workFlows:
743  if wfl.numId == float(wflid):
744  if dump:
745  dump = False
746  print(Fore.GREEN + str(wfl.numId) + Fore.RESET + " " + Fore.YELLOW + wfl.nameId + Fore.RESET)
747  for i,s in enumerate(wfl.cmds):
748  print(fmt % (Fore.RED + str(i+1) + Fore.RESET,
749  (str(s)+' ')))
750  print("\nWorkflow found in %s." % key)
751  else:
752  print("Workflow also found in %s." % key)
753 
754  do_EOF = do_exit
755 
756  TheMatrix(opt).cmdloop()
757  sys.exit(0)
758 
759  if opt.raw and opt.show:
760  ret = showRaw(opt)
761  else:
762  ret = runSelected(opt)
763 
764 
765  sys.exit(ret)
def performInjectionOptionTest(opt)
def runSelected(opt)
Definition: runTheMatrix.py:20
def do_predefined(self, arg)
def do_showWorkflow(self, arg)
def complete_showWorkflow(self, text, line, start_idx, end_idx)
def do_search(self, arg)
def showRaw(opt)
Definition: runTheMatrix.py:11
def do_clear(self, arg)
def help_dumpWorkflowId(self)
def complete_predefined(self, text, line, start_idx, end_idx)
def help_searchInWorkflow(self)
def do_dumpWorkflowId(self, arg)
void print(TMatrixD &m, const char *label=nullptr, bool mathematicaFormat=false)
Definition: Utilities.cc:47
def __init__(self, opt)
static std::string join(char **cmd)
Definition: RemoteFile.cc:19
def do_exit(self, arg)
def default(self, inp)
def complete_searchInWorkflow(self, text, line, start_idx, end_idx)
def stepOrIndex(s)
def complete_runWorkflow(self, text, line, start_idx, end_idx)
def do_runWorkflow(self, arg)
#define str(s)
def do_jobs(self, args)
def do_searchInWorkflow(self, arg)