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