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